Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions plugins/winddrift.splayerlrc-classisland.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/**
* @name ClassIsland 联动
* @id winddrift.splayerlrc-classisland
* @version 1.0.3
* @author imsyy & WindDrift
* @homepage https://github.com/WindDrift/SPlayerLRC-In-ClassIsland
* @type control
* @grant network
* @apiLevel 2
* @description 把当前歌词推送到 ClassIsland 主界面
* @updateUrl https://raw.githubusercontent.com/WindDrift/SPlayerLRC-In-ClassIsland/main/SPlayerLRC-In-ClassIsland.js
*/
splayer.register({
events: ["trackChange", "lyricChange", "lineChange"],
settings: [
{
key: "port",
type: "number",
label: "端口",
description: "ClassIsland 歌词组件监听的本地端口",
default: 50063,
min: 1024,
max: 65535,
},
{
key: "showTranslation",
type: "switch",
label: "显示翻译",
description: "当歌词行包含翻译时,将翻译显示在副行",
default: true,
},
{
key: "showNextLine",
type: "switch",
label: "无翻译时显示下一行",
description: "当没有翻译可显示时,将下一行歌词显示在副行",
default: true,
},
{
key: "skipBackgroundLyrics",
type: "switch",
label: "跳过背景歌词",
description: "开启后,背景歌词不会显示在 ClassIsland 上,但其所属主歌词仍会正常显示",
default: false,
},
{
key: "overlapDuetAsExtra",
type: "switch",
label: "重叠对唱显示在副行",
description: "开启后,与主歌词时间重叠的对唱歌词会显示在副行,主歌词保持显示在主行",
default: true,
},
],
});

const post = (lyric, extra) => {
const port = splayer.getSetting("port") || 50063;
splayer
.request(`http://127.0.0.1:${port}/component/lyrics/lyrics/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ lyric, extra }),
})
.catch(() => {});
};

/** 一行歌词 → 纯文本 */
const lineText = (line) => (line && line.words ? line.words.map((w) => w.word).join("") : "");

/** 向前查找最近的主歌词行索引(用于背景歌词) */
const findPrevMainLineIndex = (lines, from) => {
for (let i = from; i >= 0; i--) {
if (!lines[i].isBG) return i;
}
return -1;
};

/** 查找与当前行时间重叠的最近主歌词行索引(用于对唱) */
const findOverlappingMainLineIndex = (lines, from) => {
const cur = lines[from];
for (let i = from - 1; i >= 0; i--) {
const line = lines[i];
if (line.isBG || line.isDuet) continue;
if (line.endTime > cur.startTime) return i;
}
return -1;
};

/** 向后查找下一行应显示的歌词行索引(开启跳过时将跳过背景歌词行) */
const findNextLineIndex = (lines, from, skipBG) => {
for (let i = from + 1; i < lines.length; i++) {
if (!skipBG || !lines[i].isBG) return i;
}
return -1;
};

let lines = [];

splayer.player.on("trackChange", ({ track }) => {
if (track) post(track.title, track.artists);
});

splayer.player.on("lyricChange", ({ lines: ls }) => {
lines = ls || [];
});

splayer.player.on("lineChange", ({ index }) => {
const skipBG = splayer.getSetting("skipBackgroundLyrics");
const overlapDuet = splayer.getSetting("overlapDuetAsExtra");
const cur = lines[index];

let lyric = "";
let extra = "";
let mainLine = cur;

if (cur && cur.isBG) {
// 当前是背景歌词行,向前找到所属主歌词行
const mainIdx = findPrevMainLineIndex(lines, index);
if (mainIdx < 0) {
// 找不到所属主行时,跳过背景歌词模式下不发送
if (skipBG) return;
lyric = lineText(cur);
} else if (skipBG) {
// 跳过背景歌词模式下,保持主行显示,但不在副行显示背景歌词
mainLine = lines[mainIdx];
lyric = lineText(mainLine);
} else {
mainLine = lines[mainIdx];
lyric = lineText(mainLine);
extra = lineText(cur);
}
} else if (overlapDuet && cur && cur.isDuet) {
// 当前是对唱行,若与某主行时间重叠,则主行保持主显示,对唱行显示在副行
const mainIdx = findOverlappingMainLineIndex(lines, index);
if (mainIdx >= 0) {
mainLine = lines[mainIdx];
lyric = lineText(mainLine);
extra = lineText(cur);
} else {
lyric = lineText(cur);
}
} else {
lyric = lineText(cur);
}

// 默认情况下,主歌词行的下一行若是背景歌词行,则把背景歌词显示在副行
if (!skipBG && cur && !cur.isBG && lines[index + 1] && lines[index + 1].isBG) {
extra = lineText(lines[index + 1]);
}

// 仍未确定副行时,按原有逻辑回退:翻译 > 下一行
if (!extra && mainLine) {
if (splayer.getSetting("showTranslation") && mainLine.translatedLyric) {
extra = mainLine.translatedLyric;
} else if (splayer.getSetting("showNextLine")) {
const nextIdx = findNextLineIndex(lines, index, skipBG);
if (nextIdx >= 0) extra = lineText(lines[nextIdx]);
}
}

post(lyric, extra);
});
Loading