diff --git a/public/scripts/extensions/assets/index.js b/public/scripts/extensions/assets/index.js new file mode 100644 index 000000000..cfc921cc7 --- /dev/null +++ b/public/scripts/extensions/assets/index.js @@ -0,0 +1,260 @@ +/* +TODO: + - Check failed install file (0kb size ?) +*/ +//const DEBUG_TONY_SAMA_FORK_MODE = false + +import { saveSettingsDebounced } from "../../../script.js"; +import { getContext, getApiUrl, extension_settings, doExtrasFetch, ModuleWorkerWrapper, modules } from "../../extensions.js"; +export { MODULE_NAME }; + +const MODULE_NAME = 'Assets'; +const DEBUG_PREFIX = " "; +const UPDATE_INTERVAL = 1000; +let ASSETS_JSON_URL = "https://raw.githubusercontent.com/SillyTavern/SillyTavern-Content/main/index.json" + +// DBG +//if (DEBUG_TONY_SAMA_FORK_MODE) +// ASSETS_JSON_URL = "https://raw.githubusercontent.com/Tony-sama/SillyTavern-Content/main/index.json" + +let assetDictFormat = { + "audio":{ + "ambient": [], + "bgm":[], + }}; + +let availableAssets = JSON.parse(JSON.stringify(assetDictFormat)); +let currentAssets = JSON.parse(JSON.stringify(assetDictFormat)); + +//#############################// +// Extension UI and Settings // +//#############################// + +const defaultSettings = { +} + +function loadSettings() { + updateCurrentAssets().then(function(){ + fetch(ASSETS_JSON_URL) + .then(response => response.json()) + .then(json => { + console.debug(DEBUG_PREFIX,"Received assets dictionary", json); + + for(const i of json){ + console.log(DEBUG_PREFIX,i) + if (i["type"] == "ambient"){ + availableAssets["audio"]["ambient"].push(i); + } + if (i["type"] == "bgm"){ + availableAssets["audio"]["bgm"].push(i); + } + } + + console.debug(DEBUG_PREFIX,"Updated available assets to",availableAssets); + + // Audio + + // Ambient + for(const i in availableAssets["audio"]["ambient"]) { + const assetId = availableAssets["audio"]["ambient"][i]["id"] + let assetUrl = availableAssets["audio"]["ambient"][i]["url"] + const elemId = `assets_install_ambient_${i}`; + let element = $('', { type: 'checkbox', id: elemId}) + + //if (DEBUG_TONY_SAMA_FORK_MODE) + // assetUrl = assetUrl.replace("https://github.com/SillyTavern/","https://github.com/Tony-sama/"); // DBG + + console.debug(DEBUG_PREFIX,"Checking asset",assetId, assetUrl); + + if (isAmbientInstalled(assetId)) { + console.debug(DEBUG_PREFIX,"installed, checked") + element.prop("disabled",true); + element.prop("checked",true); + } + else { + console.debug(DEBUG_PREFIX,"not installed, unchecked") + element.prop("checked",false); + element.on("click", function(){ + installAmbient(assetUrl,assetId); + element.prop("disabled",true); + element.off("click"); + }) + } + + console.debug(DEBUG_PREFIX,"Created element for BGM",assetId) + + $(``) + .append(element) + .append(`

${assetId}

`) + .appendTo("#assets_audio_ambient_div"); + + } + + // BGM + for(const i in availableAssets["audio"]["bgm"]) { + const assetId = availableAssets["audio"]["bgm"][i]["id"] + let assetUrl = availableAssets["audio"]["bgm"][i]["url"] + const elemId = `assets_install_bgm_${i}`; + let element = $('', { type: 'checkbox', id: elemId}) + + //if (DEBUG_TONY_SAMA_FORK_MODE) + // assetUrl = assetUrl.replace("https://github.com/SillyTavern/","https://github.com/Tony-sama/"); // DBG + + console.debug(DEBUG_PREFIX,"Checking asset",assetId, assetUrl); + + if (isBgmInstalled(assetId)) { + console.debug(DEBUG_PREFIX,"installed, checked") + element.prop("disabled",true); + element.prop("checked",true); + } + else { + console.debug(DEBUG_PREFIX,"not installed, unchecked") + element.prop("checked",false); + element.on("click", function(){ + installBgm(assetUrl,assetId); + element.prop("disabled",true); + element.off("click"); + }) + } + + console.debug(DEBUG_PREFIX,"Created element for BGM",assetId) + + $(``) + .append(element) + .append(`

${assetId}

`) + .appendTo("#assets_audio_bgm_div"); + + } + }); + }); +} + +$(document).ready(function () { + function addExtensionControls() { + const settingsHtml = ` +
+
+
+ Assets +
+
+
+
+

Audio

+

Ambient

+
+
+

BGM

+
+
+
+
+
+
+ `; + $('#extensions_settings').append(settingsHtml); + } + + addExtensionControls(); // No init dependencies + loadSettings(); // Depends on Extension Controls + + + //const wrapper = new ModuleWorkerWrapper(moduleWorker); + //setInterval(wrapper.update.bind(wrapper), UPDATE_INTERVAL); + //moduleWorker(); +}) + +function isAmbientInstalled(filename) { + for(const i of currentAssets["audio"]["ambient"]){ + console.debug(DEBUG_PREFIX,i,filename) + if(i.includes(filename)) + return true; + } + + return false; +} + +function isBgmInstalled(filename) { + for(const i of currentAssets["audio"]["bgm"]){ + console.debug(DEBUG_PREFIX,i,filename) + if(i.includes(filename)) + return true; + } + + return false; +} + +async function installAmbient(url, filename) { + console.debug(DEBUG_PREFIX,"Downloading ",url); + const save_path = "public/assets/audio/ambient/"+filename; + try { + const result = await fetch(`/asset_download?url=${url}&save_path=${save_path}`); + let musics = result.ok ? (await result.json()) : []; + return musics; + } + catch (err) { + console.log(err); + return []; + } +} + +async function installBgm(url, filename) { + console.debug(DEBUG_PREFIX,"Downloading ",url); + const save_path = "public/assets/audio/bgm/"+filename; + try { + const result = await fetch(`/asset_download?url=${url}&save_path=${save_path}`); + let musics = result.ok ? (await result.json()) : []; + return musics; + } + catch (err) { + console.log(err); + return []; + } +} + +//#############################// +// API Calls // +//#############################// + +async function updateCurrentAssets() { + console.debug(DEBUG_PREFIX,"Checking installed assets...") + let assetList + // Check Ambient list + assetList = await getAmbientList(); + currentAssets["audio"]["ambient"] = assetList; + + // Check BGM list + assetList = await getBgmList(); + currentAssets["audio"]["bgm"] = assetList; + + console.debug(DEBUG_PREFIX,"Current assets found:",currentAssets) +} + +async function getAmbientList() { + try { + const result = await fetch(`/get_default_ambient_list`); + let musics = result.ok ? (await result.json()) : []; + return musics; + } + catch (err) { + console.log(err); + return []; + } +} + +async function getBgmList() { + try { + const result = await fetch(`/get_default_bgm_list`); + let musics = result.ok ? (await result.json()) : []; + return musics; + } + catch (err) { + console.log(err); + return []; + } +} + + +//#############################// +// Module Worker // +//#############################// diff --git a/public/scripts/extensions/assets/manifest.json b/public/scripts/extensions/assets/manifest.json new file mode 100644 index 000000000..39ba8af1d --- /dev/null +++ b/public/scripts/extensions/assets/manifest.json @@ -0,0 +1,11 @@ +{ + "display_name": "Assets", + "loading_order": 15, + "requires": [], + "optional": [], + "js": "index.js", + "css": "style.css", + "author": "Keij#6799", + "version": "0.1.0", + "homePage": "https://github.com/SillyTavern/SillyTavern" +} diff --git a/public/scripts/extensions/assets/style.css b/public/scripts/extensions/assets/style.css new file mode 100644 index 000000000..3a9512da8 --- /dev/null +++ b/public/scripts/extensions/assets/style.css @@ -0,0 +1,4 @@ +.assets-list-div i { + display: flex; + flex-direction: row; +} diff --git a/server.js b/server.js index c66f109fb..1e60c73e4 100644 --- a/server.js +++ b/server.js @@ -4947,7 +4947,7 @@ app.get('/get_default_bgm_list', jsonParser, function (request, response) { const musicsPath = directories.assets_bgm; let files = []; let files_paths = []; - console.info("Checking audio file into",musicsPath); + //console.info("Checking audio file into",musicsPath); try { if (fs.existsSync(musicsPath) && fs.statSync(musicsPath).isDirectory()) { @@ -4980,7 +4980,7 @@ app.get('/get_default_ambient_list', jsonParser, function (request, response) { const musicsPath = directories.assets_ambient; let files = []; let files_paths = []; - console.info("Checking audio file into",musicsPath); + //console.info("Checking audio file into",musicsPath); try { if (fs.existsSync(musicsPath) && fs.statSync(musicsPath).isDirectory()) { @@ -5038,4 +5038,45 @@ app.get('/get_character_bgm_list', jsonParser, function (request, response) { finally { return response.send(musics); } +}); + +/** + * HTTP POST handler function to retrieve a character background music list. + * + * @param {Object} request - HTTP Request object, expects a folder path in the query. + * @param {Object} response - HTTP Response object will contain the path to save file. + * + * @returns {void} + */ +app.get('/asset_download', jsonParser, function (request, response) { + const fs = require('fs'); + const { Readable } = require('stream'); + const { finished } = require('stream/promises'); + const path = require("path"); + const url = request.query.url; + const file_path = request.query.save_path; + + console.debug("Request received to download", url,"to",file_path); + + + const downloadFile = (async (url, file_path) => { + const res = await fetch(url); + const destination = path.resolve(file_path); + const fileStream = fs.createWriteStream(destination, { flags: 'wx' }); + await finished(Readable.fromWeb(res.body).pipe(fileStream)); + console.debug("Download finished, file saved to",file_path); + }); + + downloadFile(url, file_path) +/* + https.get(url, function(response) { + const fileStream = fs.createWriteStream(file_path); + response.pipe(fileStream); + + // after download completed close filestream + fileStream.on("finish", () => { + fileStream .close(); + console.log("Download Completed"); + }); + });*/ }); \ No newline at end of file