为playAudio提供更强大的功能,并增加tryAudio来播放音频地址列表
This commit is contained in:
parent
46de6f4958
commit
0e0fefc811
|
@ -1356,61 +1356,148 @@ export class Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
* @overload
|
||||||
|
* @param { object } options
|
||||||
|
* @param { string } options.path
|
||||||
|
* //param { boolean } [options.broadcast = false]
|
||||||
|
* @param { boolean } [options.addVideo = true]
|
||||||
|
* @param { boolean } [options.video = false]
|
||||||
|
* @param { (evt: Event) => void } [options.onCanPlay = (evt => void 0)]
|
||||||
|
* @param { (evt: Event) => void } [options.onPlay = (evt => void 0)]
|
||||||
|
* @param { (evt: Event) => void } [options.onEnded = (evt => void 0)]
|
||||||
|
* @param { (evt: Event) => void } [options.onError = (evt => void 0)]
|
||||||
* @returns { HTMLAudioElement }
|
* @returns { HTMLAudioElement }
|
||||||
*/
|
*/
|
||||||
playAudio() {
|
/**
|
||||||
let path = "",
|
* @overload
|
||||||
emptyPath = true,
|
* @param { ...string | number | ((evt: Event) => void) } args
|
||||||
notCheckDBPath = true,
|
* @returns { HTMLAudioElement }
|
||||||
onError = null;
|
*/
|
||||||
if (_status.video) {
|
playAudio(...args) {
|
||||||
// 为了能更美观的写代码,默认返回audio而不额外加一个void类型
|
const options = (args.length === 1 && get.objtype(args[0]) === "object")
|
||||||
// @ts-ignore
|
? args[0]
|
||||||
if (arguments[1] != "video") return;
|
: {
|
||||||
path = arguments[0];
|
path: args.filter(arg => typeof arg === 'string' || typeof arg === 'number').join("/"),
|
||||||
} else {
|
onError: args.find(arg => typeof arg === "function"),
|
||||||
for (const argument of arguments) {
|
};
|
||||||
if (typeof argument === "string" || typeof argument == "number") {
|
|
||||||
if (emptyPath) emptyPath = false;
|
const {
|
||||||
else if (notCheckDBPath) {
|
path = "",
|
||||||
notCheckDBPath = false;
|
// broadcast = false,
|
||||||
if (/^db:extension-[^:]*$/.test(path)) path += ":";
|
addVideo = true,
|
||||||
else path += "/";
|
video = false,
|
||||||
} else path += "/";
|
onCanPlay = (evt => void 0),
|
||||||
path += argument;
|
onPlay = (evt => void 0),
|
||||||
} else if (typeof argument == "function") onError = argument;
|
onEnded = (evt => void 0),
|
||||||
if (_status.video) break;
|
onError = (evt => void 0),
|
||||||
}
|
} = options;
|
||||||
if (path.startsWith("ext:")) path = path.replace(/^ext:/, "extension/");
|
|
||||||
else if (!["db:", "blob:", "data:"].some(prefix => path.startsWith(prefix))) path = `audio/${path}`;
|
// 为了能更美观的写代码,默认返回audio而不额外加一个void类型
|
||||||
if (!lib.config.repeat_audio && _status.skillaudio.includes(path)) return;
|
// @ts-ignore
|
||||||
}
|
if (_status.video && !video) return;
|
||||||
const audio = document.createElement("audio");
|
|
||||||
audio.autoplay = true;
|
let parsedPath = "";
|
||||||
|
if (["blob:", "data:"].some(prefix => path.startsWith(prefix))) parsedPath = path;
|
||||||
|
else if (path.startsWith('ext:')) parsedPath = path.replace(/^ext:/, 'extension/');
|
||||||
|
else if (path.startsWith('db:')) parsedPath = path.replace(/^(db:[^:]*)\//, (_, p) => p + ":");
|
||||||
|
else parsedPath = `audio/${path}`;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if (!lib.config.repeat_audio && _status.skillaudio.includes(parsedPath)) return;
|
||||||
|
|
||||||
|
const audio = document.createElement('audio');
|
||||||
audio.volume = lib.config.volumn_audio / 8;
|
audio.volume = lib.config.volumn_audio / 8;
|
||||||
//Some browsers do not support "autoplay", so "oncanplay" listening has been added
|
audio.autoplay = true;
|
||||||
audio.oncanplay = () => Promise.resolve(audio.play()).catch(() => void 0);
|
|
||||||
audio.onplay = () => {
|
audio.oncanplay = ev => {
|
||||||
_status.skillaudio.add(path);
|
//Some browsers do not support "autoplay", so "oncanplay" listening has been added
|
||||||
setTimeout(() => _status.skillaudio.remove(path), 1000);
|
Promise.resolve(audio.play()).catch(e => console.error(e));
|
||||||
game.addVideo("playAudio", null, path);
|
onCanPlay(ev);
|
||||||
|
}
|
||||||
|
audio.onplay = ev => {
|
||||||
|
_status.skillaudio.add(parsedPath);
|
||||||
|
setTimeout(() => _status.skillaudio.remove(parsedPath), 1000);
|
||||||
|
// if (broadcast) game.broadcast(game.playAudio, options);
|
||||||
|
if (addVideo) game.addVideo("playAudio", null, path);
|
||||||
|
if (_status.video || game.online) return;
|
||||||
|
onPlay(ev);
|
||||||
};
|
};
|
||||||
audio.onended = event => audio.remove();
|
audio.onended = ev => {
|
||||||
audio.onerror = event => {
|
|
||||||
audio.remove();
|
audio.remove();
|
||||||
if (onError) onError(event);
|
if (_status.video || game.online) return;
|
||||||
|
onEnded(ev);
|
||||||
};
|
};
|
||||||
new Promise((resolve, reject) => {
|
audio.onerror = ev => {
|
||||||
if (path.startsWith("db:")) game.getDB("image", path.slice(3)).then(octetStream => resolve(get.objectURL(octetStream)), reject);
|
audio.remove();
|
||||||
else if (lib.path.extname(path)) resolve(`${lib.assetURL}${path}`);
|
if (_status.video || game.online) return;
|
||||||
else if (URL.canParse(path)) resolve(path);
|
onError(ev);
|
||||||
else resolve(`${lib.assetURL}${path}.mp3`);
|
};
|
||||||
}).then(resolvedPath => {
|
|
||||||
|
Promise.resolve().then(async () => {
|
||||||
|
let resolvedPath;
|
||||||
|
if (parsedPath.startsWith('db:')) resolvedPath = get.objectURL(await game.getDB('image', parsedPath.slice(3)));
|
||||||
|
else if (lib.path.extname(parsedPath)) resolvedPath = `${lib.assetURL}${parsedPath}`;
|
||||||
|
else if (URL.canParse(path)) resolvedPath = path;
|
||||||
|
else resolvedPath = `${lib.assetURL}${parsedPath}.mp3`;
|
||||||
|
|
||||||
audio.src = resolvedPath;
|
audio.src = resolvedPath;
|
||||||
ui.window.appendChild(audio);
|
ui.window.appendChild(audio);
|
||||||
});
|
});
|
||||||
|
|
||||||
return audio;
|
return audio;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @param { object } options
|
||||||
|
* @param { string[] } options.audioList
|
||||||
|
* @param { boolean } [options.autoplay = true]
|
||||||
|
* @param { boolean } [options.random = true]
|
||||||
|
* @param { boolean } [options.addVideo = true]
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
tryAudio({ audioList, autoplay = true, random = true, addVideo=true}) {
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
let audio,
|
||||||
|
list = get.Audio.copy(audioList),
|
||||||
|
refresh = false; // 当前audioList是否有可播放的音频
|
||||||
|
|
||||||
|
const check = () => {
|
||||||
|
if (list.length) return true;
|
||||||
|
if (refresh) {
|
||||||
|
list = get.Audio.copy(audioList);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//@ts-ignore
|
||||||
|
if (!list.alternate) return false;
|
||||||
|
//@ts-ignore
|
||||||
|
audioList = list.alternate;
|
||||||
|
list = get.Audio.copy(audioList);
|
||||||
|
return check();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLAudioElement}
|
||||||
|
*/
|
||||||
|
const play = () => {
|
||||||
|
//@ts-ignore
|
||||||
|
if (!check()) return;
|
||||||
|
//@ts-ignore
|
||||||
|
audio = random ? list.randomRemove() : list.shift();
|
||||||
|
return game.playAudio({
|
||||||
|
path: audio,
|
||||||
|
addVideo,
|
||||||
|
onCanPlay: () => refresh = true,
|
||||||
|
onError: play,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (autoplay) return play();
|
||||||
|
return () => {
|
||||||
|
if (random) list = get.Audio.copy(audioList);
|
||||||
|
return play();
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @deprecated 请使用get.Audio.skill + get.Audio.toFile
|
* @deprecated 请使用get.Audio.skill + get.Audio.toFile
|
||||||
*
|
*
|
||||||
|
@ -1465,7 +1552,7 @@ export class Game {
|
||||||
* @param { Player | string } player
|
* @param { Player | string } player
|
||||||
* @param { boolean } [directaudio]
|
* @param { boolean } [directaudio]
|
||||||
* @param { boolean } [nobroadcast]
|
* @param { boolean } [nobroadcast]
|
||||||
* @param { ['lib']['skill'] } [skillInfo]
|
* @param { any } [skillInfo]
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
trySkillAudio(skill, player, directaudio, nobroadcast, skillInfo) {
|
trySkillAudio(skill, player, directaudio, nobroadcast, skillInfo) {
|
||||||
|
@ -1476,21 +1563,9 @@ export class Game {
|
||||||
if (!info) return;
|
if (!info) return;
|
||||||
if (info.direct && !directaudio) return;
|
if (info.direct && !directaudio) return;
|
||||||
if (lib.skill.global.includes(skill) && !info.forceaudio) return;
|
if (lib.skill.global.includes(skill) && !info.forceaudio) return;
|
||||||
|
|
||||||
let audio, list = get.Audio.skill({ skill, player, info: skillInfo }).randomSort();
|
const audioList = get.Audio.toFile(get.Audio.skill({ skill, player, info: skillInfo }));
|
||||||
const check = () => {
|
return game.tryAudio({ audioList });
|
||||||
if (list.length) return true;
|
|
||||||
//@ts-ignore
|
|
||||||
if (!list.alternate) return false;
|
|
||||||
//@ts-ignore
|
|
||||||
list = list.alternate;
|
|
||||||
return check();
|
|
||||||
};
|
|
||||||
return (function play() {
|
|
||||||
if (!check()) return;
|
|
||||||
audio = list.shift();
|
|
||||||
return game.playAudio(audio.file, play);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param { Player | string } player
|
* @param { Player | string } player
|
||||||
|
@ -1500,22 +1575,11 @@ export class Game {
|
||||||
game.broadcast(game.tryDieAudio, player);
|
game.broadcast(game.tryDieAudio, player);
|
||||||
if (!lib.config.background_speak) return;
|
if (!lib.config.background_speak) return;
|
||||||
|
|
||||||
let audio, list = get.Audio.die({player}).randomSort();
|
const audioList = get.Audio.toFile(get.Audio.die({ player }));
|
||||||
const check = () => {
|
return game.tryAudio({ audioList });
|
||||||
if (list.length) return true;
|
|
||||||
//@ts-ignore
|
|
||||||
if (!list.alternate) return false;
|
|
||||||
//@ts-ignore
|
|
||||||
list = list.alternate;
|
|
||||||
return check();
|
|
||||||
};
|
|
||||||
return (function play() {
|
|
||||||
if (!check()) return;
|
|
||||||
audio = list.shift();
|
|
||||||
return game.playAudio(audio.file, play);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* @param { string } name
|
* @param { string } name
|
||||||
* @param { number } [index]
|
* @param { number } [index]
|
||||||
* @returns
|
* @returns
|
||||||
|
@ -2576,7 +2640,7 @@ export class Game {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
playAudio: function (str) {
|
playAudio: function (str) {
|
||||||
game.playAudio(str, "video");
|
game.playAudio({ path: str, video: true });
|
||||||
},
|
},
|
||||||
playSkillAudio: function (name) {
|
playSkillAudio: function (name) {
|
||||||
game.playSkillAudio(name, "video");
|
game.playSkillAudio(name, "video");
|
||||||
|
|
|
@ -155,7 +155,7 @@ export class Audio {
|
||||||
const parseAudioWithCache = (name, audioInfo, data, isDefault = false) => {
|
const parseAudioWithCache = (name, audioInfo, data, isDefault = false) => {
|
||||||
const key = this.#getCacheKey(options, name, audioInfo, data);
|
const key = this.#getCacheKey(options, name, audioInfo, data);
|
||||||
const result = this.#Cache[key];
|
const result = this.#Cache[key];
|
||||||
if (result !== void 0) return this.#copy(result);
|
if (result !== void 0) return this.copy(result);
|
||||||
else {
|
else {
|
||||||
const result = parseAudio(name, audioInfo, data);
|
const result = parseAudio(name, audioInfo, data);
|
||||||
if (isDefault && name.includes("_")) {
|
if (isDefault && name.includes("_")) {
|
||||||
|
@ -163,7 +163,7 @@ export class Audio {
|
||||||
result.alternate = getInfoAudio(name, originData);
|
result.alternate = getInfoAudio(name, originData);
|
||||||
}
|
}
|
||||||
this.#Cache[key] = result;
|
this.#Cache[key] = result;
|
||||||
return this.#copy(result);
|
return this.copy(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,14 +258,15 @@ export class Audio {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {textMap[]} list
|
* @template {textMap | string} T
|
||||||
|
* @param {T[]} list
|
||||||
* @this {typeof get.Audio}
|
* @this {typeof get.Audio}
|
||||||
* @returns {textMap[]}
|
* @returns {T[]}
|
||||||
*/
|
*/
|
||||||
#copy = function (list) {
|
copy(list) {
|
||||||
const result = JSON.parse(JSON.stringify(list));
|
const result = JSON.parse(JSON.stringify(list));
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (list.alternate) result.alternate = this.#copy(list.alternate);
|
if (list.alternate) result.alternate = this.copy(list.alternate);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ export class status {
|
||||||
event = null;
|
event = null;
|
||||||
ai = {};
|
ai = {};
|
||||||
lastdragchange = [];
|
lastdragchange = [];
|
||||||
skillaudio = [];
|
/**
|
||||||
|
* @type { string[] }
|
||||||
|
*/
|
||||||
|
skillaudio = []
|
||||||
dieClose = [];
|
dieClose = [];
|
||||||
dragline = [];
|
dragline = [];
|
||||||
dying = [];
|
dying = [];
|
||||||
|
@ -56,6 +59,10 @@ export class status {
|
||||||
* @type { boolean | undefined }
|
* @type { boolean | undefined }
|
||||||
*/
|
*/
|
||||||
connectMode = undefined;
|
connectMode = undefined;
|
||||||
|
/**
|
||||||
|
* @type { boolean | undefined }
|
||||||
|
*/
|
||||||
|
video = undefined
|
||||||
/**
|
/**
|
||||||
* @type { boolean | undefined }
|
* @type { boolean | undefined }
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3555,23 +3555,17 @@ export class Click {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lib.config.background_speak && e !== "init") {
|
if (lib.config.background_speak && e !== 'init') {
|
||||||
let audio,
|
if (!this.playAudio) {
|
||||||
skillnode = this;
|
const audioList = get.Audio.toFile(get.Audio.skill({ skill: this.link, player: playername }));
|
||||||
const playedAudios = [];
|
this.playAudio = game.tryAudio({
|
||||||
(function play() {
|
audioList,
|
||||||
if (!skillnode.audioList || !skillnode.audioList.length) {
|
addVideo: false,
|
||||||
skillnode.audioList = game.parseSkillAudio(skillnode.link, playername);
|
random: false,
|
||||||
if (
|
autoplay: false
|
||||||
!skillnode.audioList.length ||
|
});
|
||||||
skillnode.audioList.length == playedAudios.length
|
}
|
||||||
)
|
this.playAudio();
|
||||||
return;
|
|
||||||
}
|
|
||||||
audio = skillnode.audioList.shift();
|
|
||||||
playedAudios.push(audio);
|
|
||||||
game.playAudio(audio, play);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -3914,23 +3908,17 @@ export class Click {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lib.config.background_speak && e !== "init") {
|
if (lib.config.background_speak && e !== 'init') {
|
||||||
let audio,
|
if (!this.playAudio) {
|
||||||
skillnode = this;
|
const audioList = get.Audio.toFile(get.Audio.skill({ skill: this.link, player: playername }));
|
||||||
const playedAudios = [];
|
this.playAudio = game.tryAudio({
|
||||||
(function play() {
|
audioList,
|
||||||
if (!skillnode.audioList || !skillnode.audioList.length) {
|
addVideo: false,
|
||||||
skillnode.audioList = game.parseSkillAudio(skillnode.link, playername);
|
random: false,
|
||||||
if (
|
autoplay: false
|
||||||
!skillnode.audioList.length ||
|
});
|
||||||
skillnode.audioList.length == playedAudios.length
|
}
|
||||||
)
|
this.playAudio();
|
||||||
return;
|
|
||||||
}
|
|
||||||
audio = skillnode.audioList.shift();
|
|
||||||
playedAudios.push(audio);
|
|
||||||
game.playAudio(audio, play);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue