Audio extension, handle custome background. Factorised bgm/ambient file listing into one assets listing function on server.js.
This commit is contained in:
parent
b8c051694c
commit
8e38229ed4
|
@ -1,16 +1,8 @@
|
||||||
/*
|
/*
|
||||||
TODO:
|
Ideas:
|
||||||
- Emotion-based BGM
|
- cross fading between bgm / start a different time
|
||||||
- per character bgms OK
|
|
||||||
- simple fade out/in when switching OK
|
|
||||||
- cross fading ?
|
|
||||||
- BGM switch cooldown
|
|
||||||
- group chat
|
|
||||||
- Background based ambient sounds
|
- Background based ambient sounds
|
||||||
- global sounds OK
|
|
||||||
- global overides ?
|
|
||||||
- import option on background UI ?
|
- import option on background UI ?
|
||||||
- One UI with different mixing options OK
|
|
||||||
- Allow background music edition using background menu
|
- Allow background music edition using background menu
|
||||||
- https://fontawesome.com/icons/music?f=classic&s=solid
|
- https://fontawesome.com/icons/music?f=classic&s=solid
|
||||||
- https://codepen.io/noirsociety/pen/rNQxQwm
|
- https://codepen.io/noirsociety/pen/rNQxQwm
|
||||||
|
@ -18,13 +10,17 @@ TODO:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { saveSettingsDebounced } from "../../../script.js";
|
import { saveSettingsDebounced } from "../../../script.js";
|
||||||
import { getContext, getApiUrl, extension_settings, doExtrasFetch, ModuleWorkerWrapper, modules } from "../../extensions.js";
|
import { getContext, extension_settings, ModuleWorkerWrapper } from "../../extensions.js";
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
const MODULE_NAME = 'Audio';
|
const MODULE_NAME = 'Audio';
|
||||||
const DEBUG_PREFIX = "<Audio module> ";
|
const DEBUG_PREFIX = "<Audio module> ";
|
||||||
const UPDATE_INTERVAL = 1000;
|
const UPDATE_INTERVAL = 1000;
|
||||||
|
|
||||||
|
const ASSETS_BGM_FOLDER = "audio/bgm";
|
||||||
|
const ASSETS_AMBIENT_FOLDER = "audio/ambient";
|
||||||
|
const CHARACTER_BGM_FOLDER = "bgm"
|
||||||
|
|
||||||
const FALLBACK_EXPRESSION = "neutral";
|
const FALLBACK_EXPRESSION = "neutral";
|
||||||
const DEFAULT_EXPRESSIONS = [
|
const DEFAULT_EXPRESSIONS = [
|
||||||
//"talkinghead",
|
//"talkinghead",
|
||||||
|
@ -147,7 +143,7 @@ async function onBGMVolumeChange() {
|
||||||
$("#audio_character_bgm").prop("volume",extension_settings.audio.bgm_volume * 0.01);
|
$("#audio_character_bgm").prop("volume",extension_settings.audio.bgm_volume * 0.01);
|
||||||
$("#audio_character_bgm_volume").text(extension_settings.audio.bgm_volume);
|
$("#audio_character_bgm_volume").text(extension_settings.audio.bgm_volume);
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
console.debug(DEBUG_PREFIX,"UPDATED BGM MAX TO",extension_settings.audio.bgm_volume);
|
//console.debug(DEBUG_PREFIX,"UPDATED BGM MAX TO",extension_settings.audio.bgm_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onAmbientVolumeChange() {
|
async function onAmbientVolumeChange() {
|
||||||
|
@ -155,14 +151,14 @@ async function onAmbientVolumeChange() {
|
||||||
$("#audio_ambient").prop("volume",extension_settings.audio.ambient_volume * 0.01);
|
$("#audio_ambient").prop("volume",extension_settings.audio.ambient_volume * 0.01);
|
||||||
$("#audio_ambient_volume").text(extension_settings.audio.ambient_volume);
|
$("#audio_ambient_volume").text(extension_settings.audio.ambient_volume);
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
console.debug(DEBUG_PREFIX,"UPDATED Ambient MAX TO",extension_settings.audio.ambient_volume);
|
//console.debug(DEBUG_PREFIX,"UPDATED Ambient MAX TO",extension_settings.audio.ambient_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onBGMCooldownInput() {
|
async function onBGMCooldownInput() {
|
||||||
extension_settings.audio.bgm_cooldown = ~~($("#audio_bgm_cooldown").val());
|
extension_settings.audio.bgm_cooldown = ~~($("#audio_bgm_cooldown").val());
|
||||||
cooldownBGM = extension_settings.audio.bgm_cooldown * 1000;
|
cooldownBGM = extension_settings.audio.bgm_cooldown * 1000;
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
console.debug(DEBUG_PREFIX,"UPDATED BGM cooldown to",extension_settings.audio.bgm_cooldown);
|
//console.debug(DEBUG_PREFIX,"UPDATED BGM cooldown to",extension_settings.audio.bgm_cooldown);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
@ -257,27 +253,13 @@ $(document).ready(function () {
|
||||||
// API Calls //
|
// API Calls //
|
||||||
//#############################//
|
//#############################//
|
||||||
|
|
||||||
async function getAmbientList() {
|
async function getAssetsList(folderPath) {
|
||||||
console.debug(DEBUG_PREFIX, "getting ambient audio files");
|
console.debug(DEBUG_PREFIX, "getting files from",folderPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await fetch(`/get_default_ambient_list`);
|
const result = await fetch(`/get_assets_list?folderPath=${folderPath}`);
|
||||||
let musics = result.ok ? (await result.json()) : [];
|
let file_paths = result.ok ? (await result.json()) : [];
|
||||||
return musics;
|
return file_paths;
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getDefaultBgmList() {
|
|
||||||
console.debug(DEBUG_PREFIX, "getting default bgm files");
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await fetch(`/get_default_bgm_list`);
|
|
||||||
let musics = result.ok ? (await result.json()) : [];
|
|
||||||
return musics;
|
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -289,7 +271,7 @@ async function getCharacterBgmList(name) {
|
||||||
console.debug(DEBUG_PREFIX, "getting bgm list for", name);
|
console.debug(DEBUG_PREFIX, "getting bgm list for", name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await fetch(`/get_character_bgm_list?name=${encodeURIComponent(name)}`);
|
const result = await fetch(`/get_character_assets_list?name=${encodeURIComponent(name)}&assetsFolder=${CHARACTER_BGM_FOLDER}`);
|
||||||
let musics = result.ok ? (await result.json()) : [];
|
let musics = result.ok ? (await result.json()) : [];
|
||||||
return musics;
|
return musics;
|
||||||
}
|
}
|
||||||
|
@ -313,24 +295,32 @@ async function getCharacterBgmList(name) {
|
||||||
async function moduleWorker() {
|
async function moduleWorker() {
|
||||||
const moduleEnabled = extension_settings.audio.enabled;
|
const moduleEnabled = extension_settings.audio.enabled;
|
||||||
|
|
||||||
//console.debug(DEBUG_PREFIX, getContext());
|
|
||||||
|
|
||||||
if (moduleEnabled) {
|
if (moduleEnabled) {
|
||||||
cooldownBGM -= UPDATE_INTERVAL;
|
cooldownBGM -= UPDATE_INTERVAL;
|
||||||
//console.debug(DEBUG_PREFIX,currentCharacterBGM,currentExpressionBGM);
|
|
||||||
|
|
||||||
if (fallback_BGMS == null){
|
if (fallback_BGMS == null){
|
||||||
fallback_BGMS = await getDefaultBgmList();
|
console.debug(DEBUG_PREFIX,"Updating audio bgm assets...");
|
||||||
|
fallback_BGMS = await getAssetsList(ASSETS_BGM_FOLDER);
|
||||||
|
fallback_BGMS = fallback_BGMS.filter((filename) => filename != ".placeholder")
|
||||||
|
console.debug(DEBUG_PREFIX,"Detected assets:",fallback_BGMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ambients == null){
|
if (ambients == null){
|
||||||
ambients = await getAmbientList();
|
console.debug(DEBUG_PREFIX,"Updating audio ambient assets...");
|
||||||
|
ambients = await getAssetsList(ASSETS_AMBIENT_FOLDER);
|
||||||
|
ambients = ambients.filter((filename) => filename != ".placeholder")
|
||||||
|
console.debug(DEBUG_PREFIX,"Detected assets:",ambients);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1) Update ambient audio
|
// 1) Update ambient audio
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
let newBackground = $("#bg1").css("background-image");
|
let newBackground = $("#bg1").css("background-image");
|
||||||
newBackground = newBackground.substring(newBackground.lastIndexOf("/")+1).replace(/\.[^/.]+$/, "").replaceAll("%20","-"); // remove path and spaces
|
const custom_background = getContext()["chatMetadata"]["custom_background"];
|
||||||
|
|
||||||
|
if(custom_background !== undefined)
|
||||||
|
newBackground = custom_background
|
||||||
|
|
||||||
|
newBackground = newBackground.substring(newBackground.lastIndexOf("/")+1).replace(/\.[^/.]+$/, "").replaceAll("%20","-").replaceAll(" ","-"); // remove path and spaces
|
||||||
|
|
||||||
//console.debug(DEBUG_PREFIX,"Current backgroung:",newBackground);
|
//console.debug(DEBUG_PREFIX,"Current backgroung:",newBackground);
|
||||||
|
|
||||||
|
@ -359,8 +349,8 @@ async function moduleWorker() {
|
||||||
|
|
||||||
// 1.1) First time loading chat
|
// 1.1) First time loading chat
|
||||||
if (characterMusics[newCharacter] === undefined) {
|
if (characterMusics[newCharacter] === undefined) {
|
||||||
await loadCharacterBGM(newCharacter)
|
await loadCharacterBGM(newCharacter);
|
||||||
//currentExpressionBGM = FALLBACK_EXPRESSION;
|
currentExpressionBGM = FALLBACK_EXPRESSION;
|
||||||
//currentCharacterBGM = newCharacter;
|
//currentCharacterBGM = newCharacter;
|
||||||
|
|
||||||
//updateBGM();
|
//updateBGM();
|
||||||
|
@ -460,7 +450,7 @@ async function loadCharacterBGM(newCharacter) {
|
||||||
|
|
||||||
// 1.1) First time character appear, load its music folder
|
// 1.1) First time character appear, load its music folder
|
||||||
const audio_file_paths = await getCharacterBgmList(newCharacter);
|
const audio_file_paths = await getCharacterBgmList(newCharacter);
|
||||||
console.debug(DEBUG_PREFIX, "Recieved", audio_file_paths);
|
//console.debug(DEBUG_PREFIX, "Recieved", audio_file_paths);
|
||||||
|
|
||||||
// Initialise expression/files mapping
|
// Initialise expression/files mapping
|
||||||
characterMusics[newCharacter] = {};
|
characterMusics[newCharacter] = {};
|
||||||
|
@ -470,8 +460,8 @@ async function loadCharacterBGM(newCharacter) {
|
||||||
for(const i of audio_file_paths) {
|
for(const i of audio_file_paths) {
|
||||||
//console.debug(DEBUG_PREFIX,"File found:",i);
|
//console.debug(DEBUG_PREFIX,"File found:",i);
|
||||||
for(const e of DEFAULT_EXPRESSIONS)
|
for(const e of DEFAULT_EXPRESSIONS)
|
||||||
if (i["label"].includes(e))
|
if (i.includes(e))
|
||||||
characterMusics[newCharacter][e].push(i["path"]);
|
characterMusics[newCharacter][e].push(i);
|
||||||
}
|
}
|
||||||
console.debug(DEBUG_PREFIX,"Updated BGM map of",newCharacter,"to",characterMusics[newCharacter]);
|
console.debug(DEBUG_PREFIX,"Updated BGM map of",newCharacter,"to",characterMusics[newCharacter]);
|
||||||
}
|
}
|
||||||
|
|
154
server.js
154
server.js
|
@ -318,8 +318,7 @@ const directories = {
|
||||||
context: 'public/context',
|
context: 'public/context',
|
||||||
backups: 'backups/',
|
backups: 'backups/',
|
||||||
quickreplies: 'public/QuickReplies',
|
quickreplies: 'public/QuickReplies',
|
||||||
assets_bgm: 'public/assets/audio/bgm',
|
assets: 'public/assets',
|
||||||
assets_ambient: 'public/assets/audio/ambient'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// CSRF Protection //
|
// CSRF Protection //
|
||||||
|
@ -4935,108 +4934,36 @@ app.post('/delete_extension', jsonParser, async (request, response) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP POST handler function to retrieve local ST default BGM files.
|
* HTTP POST handler function to retrieve name of all files of a given folder path.
|
||||||
*
|
*
|
||||||
* @param {Object} request - HTTP Request object.
|
* @param {Object} request - HTTP Request object. Require folder path in query
|
||||||
* @param {Object} response - HTTP Response object will contain a list of audio file path.
|
* @param {Object} response - HTTP Response object will contain a list of file path.
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
app.get('/get_default_bgm_list', jsonParser, function (request, response) {
|
app.get('/get_assets_list', jsonParser, function (request, response) {
|
||||||
const musicsPath = directories.assets_bgm;
|
const folderPath = path.join(directories.assets,request.query.folderPath);
|
||||||
let files = [];
|
let output = []
|
||||||
let files_paths = [];
|
//console.info("Checking files into",folderPath);
|
||||||
//console.info("Checking audio file into",musicsPath);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(musicsPath) && fs.statSync(musicsPath).isDirectory()) {
|
if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
|
||||||
files = fs.readdirSync(musicsPath)
|
const files = fs.readdirSync(folderPath)
|
||||||
.filter(file => {
|
.filter(filename => {
|
||||||
const mimeType = mime.lookup(file);
|
return filename != ".placeholder";
|
||||||
return mimeType && mimeType.startsWith('audio/');
|
});
|
||||||
});
|
|
||||||
for(const i of files)
|
for (i of files)
|
||||||
files_paths.push(`/assets/audio/bgm/${i}`);
|
output.push(`/assets/${request.query.folderPath}/${i}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
return response.send(files_paths);
|
return response.send(output);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP POST handler function to retrieve a ST background ambient sounds files.
|
|
||||||
*
|
|
||||||
* @param {Object} request - HTTP Request object.
|
|
||||||
* @param {Object} response - HTTP Response object will contain a list of audio file path.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(musicsPath) && fs.statSync(musicsPath).isDirectory()) {
|
|
||||||
files = fs.readdirSync(musicsPath)
|
|
||||||
.filter(file => {
|
|
||||||
const mimeType = mime.lookup(file);
|
|
||||||
return mimeType && mimeType.startsWith('audio/');
|
|
||||||
});
|
|
||||||
for(const i of files)
|
|
||||||
files_paths.push(path.join(`/assets/audio/ambient/${i}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
return response.send(files_paths);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP POST handler function to retrieve a character background music list.
|
|
||||||
*
|
|
||||||
* @param {Object} request - HTTP Request object, expects a character name in the query.
|
|
||||||
* @param {Object} response - HTTP Response object will contain a list of audio file path.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
app.get('/get_character_bgm_list', jsonParser, function (request, response) {
|
|
||||||
const AUDIO_FOLDER = "audio"
|
|
||||||
const BGM_FOLDER = "bgm"
|
|
||||||
const name = request.query.name;
|
|
||||||
const musicsPath = path.join(directories.characters, name, AUDIO_FOLDER,BGM_FOLDER);
|
|
||||||
let musics = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(musicsPath) && fs.statSync(musicsPath).isDirectory()) {
|
|
||||||
musics = fs.readdirSync(musicsPath)
|
|
||||||
.filter(file => {
|
|
||||||
const mimeType = mime.lookup(file);
|
|
||||||
return mimeType && mimeType.startsWith('audio/');
|
|
||||||
})
|
|
||||||
.map((file) => {
|
|
||||||
const pathToMusic = path.join(musicsPath, file);
|
|
||||||
return {
|
|
||||||
label: path.parse(pathToMusic).name.toLowerCase(),
|
|
||||||
path: `/characters/${name}/${AUDIO_FOLDER}/${BGM_FOLDER}/${file}`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
return response.send(musics);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5068,15 +4995,40 @@ app.get('/asset_download', jsonParser, function (request, response) {
|
||||||
});
|
});
|
||||||
|
|
||||||
downloadFile(url, 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");
|
/**
|
||||||
});
|
* HTTP POST handler function to retrieve a character background music list.
|
||||||
});*/
|
*
|
||||||
|
* @param {Object} request - HTTP Request object, expects a character name in the query.
|
||||||
|
* @param {Object} response - HTTP Response object will contain a list of audio file path.
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
app.get('/get_character_assets_list', jsonParser, function (request, response) {
|
||||||
|
const name = request.query.name;
|
||||||
|
const assetsFolder = request.query.assetsFolder
|
||||||
|
const folderPath = path.join(directories.characters, name, assetsFolder);
|
||||||
|
let output = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
|
||||||
|
const files = fs.readdirSync(folderPath)
|
||||||
|
.filter(filename => {
|
||||||
|
return filename != ".placeholder";
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i of files)
|
||||||
|
output.push(`/characters/${name}/${assetsFolder}/${i}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
return response.send(output);
|
||||||
|
}
|
||||||
});
|
});
|
Loading…
Reference in New Issue