-
Notifications
You must be signed in to change notification settings - Fork 9
歌词源及解析器脚本
ESLyric edited this page Sep 7, 2024
·
15 revisions
ESLyric 使用了QuickJS引擎的移植版本 提供自定义外部歌词源等功能,引擎中std及os模块未导出。
现提供的脚本可至仓库scripts查看。
歌词源脚本位置:fb2k配置目录\eslyric-data\scripts\searcher
interface IESLyricSearchServiceConfig
{
properties:
[r,w] string name; // 歌词源名称
[r,w] string author; // 歌词源作者
[r,w] string version; // 歌词源版本
}
interface IESLyricTrackMetadb
{
properties:
[r] string title; // 音轨标题,若启用了搜索预处理,则该字段为预处理后的关键词,否则与rawTitle相同
[r] string artist; // 音轨艺术家,若启用了搜索预处理,则该字段为预处理后的关键词,否则与rawArtist相同
[r] string album; // 音轨专辑,若启用了搜索预处理,则该字段为预处理后的关键词,否则与rawAlbum相同
[r] string rawTitle; // 未经过预处理的音轨标题
[r] string rawArtist; // 未经过预处理的音轨艺术家
[r] string rawAlbum; // 未经过预处理的音轨专辑
[r] string rawPath; // 完整路径,如file://c:\path\to\track.mp3
[r] string path; // 显示路径,如c:\path\to\track.mp3
[r] int subSong; // 子音轨索引
[r] double duration; // 音轨长度
};
interface IESLyricMetaInfo
{
properties:
[r,w] string title; // 歌词所属标题,必填字段
[r,w] string artist; // 歌词所属艺术家,推荐填写,显示结果更准确
[r,w] string album; // 歌词所属专辑,在搜索界面显示
[r,w] string lyricText; // 歌词文本, 与lyricData字段二者必填一项
[r,w] ArrayBuffer lyricData; // 歌词数据, 如为其他需要外部解析的歌词写入到该字段,与lyricText字段二者必填一项
[r,w] string source; // 歌词来源,可选,未填写时自动填充对应歌词源名
[r,w] string fileType; // 歌词文件类型,默认为lrc,为其他格式时需填写且需存在对应格式的解析器才能正常显示
[r,w] string location; // 歌词位置,可选
[r,w] bool isLocal; // 是否为本地歌词, 可选,默认为false
[r,w] int confidence; // 歌词匹配度, 可选,未填写时使用内部判断值
};
interface IESLyricMetaInfoManager
{
Methods:
IESLyricMetaInfo createLyric(); // 创建一个新的歌词描述信息(多个外部歌词可共用同个描述信息接口进行设置)
void addLyric(IESLyricMetaInfo newLyric); // 添加歌词至ESLyric
bool checkAbort(); // 用户是否取消搜索,是则返回true,否则返回false
string getSvcData(string key); // 获取歌词源相关配置
void setSvcData(string key); // 设置歌词源相关配置,key在同一歌词源内唯一即可
}
interface IHttpResponse
{
properties:
[r] int statusCode; // http状态值
[r] string statusMessage; // 状态信息
[r] object headers; // 响应头对象, 如 var encoding = headers['content-encoding'];
}
// 全局函数
// 发起http请求
// 参数options为以下两类值:
// 1. 字符串URL 如 request("https://www.example.com", ...);
// 2. 请求的配置对象,该对象支持四个字段,如reqeust({url: "https://www.example.com", method: "get", body: "post data", { Referer: "www.example.com" }}, ...);
// object HttpRequestSettings
//{
// string url; // 请求的url
// string method; // 请求的方式, "get"或"post"
// string body; // post data
// object headers; // 请求头部
// bool raw; // 返回原始数据, body为js array类型
//}
// 参数callback为请求结束后的回调 void callback(int err, IHttpResponse rsp, string body)
void request(object options, func callback);
// 获取歌词源信息时调用
export function getConfig(IESLyricSearchServiceConfig cfg)
{
}
// 获取歌词时调用
export function getLyrics(IESLyricTrackMetadb meta, IESLyricMetaInfoManager man)
{
}
上述两个回调函数每个歌词源都必须提供。
ESLyric中使用minixml解析xml文件,也提供了相关脚本接口。
// 全局对象mxml
interface IMiniXml
{
constants:
MXML_DESCEND;
MXML_NO_DESCEND;
MXML_DESCEND_FIRST;
MXML_IGNORE;
MXML_ELEMENT;
MXML_INTEGER;
MXML_OPAQUE;
MXML_REAL;
MXML_TEXT;
MXML_CUSTOM;
// callback types, loadString中使用
MXML_NO_CALLBACK;
MXML_TEXT_CALLBACK;
MXML_INTEGER_CALLBACK;
MXML_OPAQUE_CALLBACK;
MXML_REAL_CALLBACK;
MXML_IGNORE_CALLBACK;
Methods:
IMiniXmlNode loadString(string xmlText, int callbackType = MXML_NO_CALLBACK);// 加载xml文本
}
interface IMiniXmlNode
{
Methods:
// https://www.msweet.org/mxml/mxml.html#mxmlFindElement
IMiniXmlNode findElement(string element, string attr, string val, int decend);
// https://www.msweet.org/mxml/mxml.html#mxmlFindPath
IMiniXmlNode findPath(string path);
// https://www.msweet.org/mxml/mxml.html#mxmlElementGetAttr
string getAttr(string attrName);
// https://www.msweet.org/mxml/mxml.html#mxmlElementGetAttrCount
int getAttrCount();
// https://www.msweet.org/mxml/mxml.html#mxmlElementGetAttrByIndex
object getAttrByIndex(int idx)
// https://www.msweet.org/mxml/mxml.html#mxmlGetElement
string getElement();
// https://www.msweet.org/mxml/mxml.html#mxmlGetCDATA
string getCDATA();
// https://www.msweet.org/mxml/mxml.html#mxmlGetFirstChild
IMiniXmlNode getFirstChild();
// https://www.msweet.org/mxml/mxml.html#mxmlGetLastChild
IMiniXmlNode getLastChild();
// https://www.msweet.org/mxml/mxml.html#mxmlGetPrevSibling
IMiniXmlNode getPrevSibling();
// https://www.msweet.org/mxml/mxml.html#mxmlGetNextSibling
IMiniXmlNode getNextSibling();
// https://www.msweet.org/mxml/mxml.html#mxmlGetParent
IMiniXmlNode getParent();
// https://www.msweet.org/mxml/mxml.html#mxmlGetInteger
int getInteger();
// https://www.msweet.org/mxml/mxml.html#mxmlGetReal
double getReal();
// https://www.msweet.org/mxml/mxml.html#mxmlGetText
string getText();
// https://www.msweet.org/mxml/mxml.html#mxmlGetOpaque
string getOpaque();
// https://www.msweet.org/mxml/mxml.html#mxmlGetType
int getType();
}
zlib模块依赖foobar2000安装目录下的zlib1.dll文件。
// 全局对象zlib
interface IZlib
{
Methods:
arraybuffer compress(arraybuffer ab);
arraybuffer uncompress(arraybuffer ab);
}
// 全局对象console
interface IConsole
{
Methods:
void log(string msg); // 输出日志至foobar2000控制台,如console.log("hello!");
}
interface IFbProfiler
{
Methods:
void reset();
string queryString();
double time();
}
// 全局对象utils
interface IFbUtils
{
Methods:
IFbProfiler createProfiler(); // 创建一个profiler,如var profiler = utils.createProfiler();
}
// 全局函数
// 载入外部库,路径是相对于lib路径的相对路径,如evalLib("querystring/querystring.min.js");载入scripts\lib\querystring目录下的querystring.min.js库
void evalLib(string libRelativeLibPath);
// base64解码
string atob(string b64text)
// base64编码
string btoa(string text);
// 将arraybuffer中数据直接转换为string
string arrayBufferToString(arraybuffer ab);
// 将string转换为arraybuffer(utf8)
arraybuffer stringToArrayBuffer(string s);
示例歌词源脚本:
export function getConfig(cfg)
{
cfg.name = "My custom source";
cfg.version = "0.1";
cfg.author = "My name";
cfg.useRawMeta = false;
}
export function getLyrics(meta, man)
{
let lyricMeta = man.createLyric();
// 从网络获取歌词
request("https://example.com/", (err, res, body) => {
if (!err && res.statusCode == 200) {
lyricMeta.title = "title";
lyricMeta.artist = "artist";
lyricMeta.album = "album"; // 可选
lyricMeta.lyricText = body; // 设置歌词文本
man.addLyric(lyricMeta); // 添加至ESLyric
}
});
}
解析器脚本位置:eslyric安装文件目录\scripts\parser
实现解析器可以使ESLyric支持更多格式的歌词。解析器需要将其他格式歌词转换为ESLyric可识别的歌词。
当前ESLyric支持的歌词格式:
- 标准LRC
[00:00.00]line 1
[00:01.00]line 2
- 多标签增强LRC (见wiki
Enhanced format
部分说明)
[mm:ss.xx] <mm:ss.xx> line 1 word 1 <mm:ss.xx> line 1 word 2 <mm:ss.xx> ... line 1 last word <mm:ss.xx>
[mm:ss.xx] <mm:ss.xx> line 2 word 1 <mm:ss.xx> line 2 word 2 <mm:ss.xx> ... line 2 last word <mm:ss.xx>
因此解析器需要将其他格式的格式通过脚本转换为上述任一种形式。
解析器配置描述:
interface IParserConfig
{
properties:
string name; // 解析器名称
string author; // 解析器脚本作者
string version; // 解析器版本
string fileType; // 文件后缀,如"srt"
bool parsePlainText; // 是否纯文本,影响parseLyric回调中传入的歌词数据,默认为true
}
解析器解析上下文描述:
interface IParserContext
{
Properties:
[r,w] string lyricText; // 当IParserConfig中设置parsePlainText为true时有效,同时作为解析后的结果返回字段
[r] arraybuffer lyricData; // 当IParserConfig中设置parsePlainText为false时有效
[r] double duration; // 音轨长度(参考值)
}
解析器导出回调接口:
// 获取歌词源信息时调用
export function getConfig(IParserConfig cfg)
{
}
// 获取歌词时调用
export function parseLyric(IParserContext context)
{
}
export function getConfig(IParserConfig cfg)
{
cfg.name = "my custom parser";
cfg.fileType = "srt";
}
export function parseLyric(IParserContext context)
{
// 转换为ESLyric支持的标准或增强型lrc
context.lyricText = myCustomConv(context.lyricText);
// or context.lyricText = myCustomConv(context.lyricData);
}