注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
?_=1来访问最新页面。https://zh.moegirl.org.cn/User:Leranjun/js/UtatenSearch.js?_=1"use strict";
$(() => (async () => {
await mw.loader.using("ext.gadget.site-lib");
const searchTitle = wgULS("UtaTen搜索", "UtaTen搜尋");
if (mw.config.get("wgPageName") !== "Special:UtatenSearch") {
if (mw.config.get("wgNamespaceNumber") === 0 && !$(".photrans")[0]) {
mw.util.addPortletLink("p-tb", `/Special:UtatenSearch?song=${encodeURIComponent(mw.config.get("wgTitle"))}`, searchTitle, "ca-lr-utaten", wgULS("搜索UtaTen.com的歌词并转换为Photrans格式", "搜尋UtaTen.com的歌詞並轉換為Photrans格式"));
}
return;
}
$("#firstHeading").text(searchTitle);
$("#mw-content-text").html(`<p>${wgULS("正在加载", "正在載入")}……</p>`);
document.title = searchTitle + document.title.replace(/^.*?( - .*?)$/, "$1");
await mw.loader.using(["mediawiki.Uri", "oojs-ui"]);
const fetchHTML = async (url) => $($.parseHTML((await $.getJSON(`https://api.allorigins.win/get?url=${encodeURIComponent(url)}`)).contents));
class UtaTenWindow extends OO.ui.ProcessDialog {
static static = $.extend(Object.create(super.static), {
name: "lr-utaten",
title: searchTitle,
actions: [
{
action: "cancel",
label: "取消",
flags: ["safe", "close", "destructive"],
modes: "query",
},
{
action: "continue",
label: wgULS("继续", "繼續"),
flags: ["primary", "progressive"],
modes: "query",
},
{
action: "back",
label: "返回",
flags: ["safe", "back"],
modes: ["select", "result"],
},
{
action: "close",
label: wgULS("关闭", "關閉"),
flags: ["primary", "progressive"],
modes: "result",
},
],
});
constructor(config) {
// Parent constructor
super(config);
this.prepopContent = config.data.prepopContent;
}
initialize() {
// Parent method
super.initialize();
this.queryPanel = new OO.ui.PanelLayout({
scrollable: false,
expanded: false,
padded: true,
});
this.selectPanel = new OO.ui.PanelLayout({
scrollable: false,
expanded: false,
padded: true,
});
this.resultPanel = new OO.ui.PanelLayout({
scrollable: false,
expanded: false,
padded: true,
});
const labels = {
artist_name: "歌手",
song: `歌曲(${wgULS("请使用日文原标题", "請使用日文原標題")})`,
beginning: wgULS("歌词开头", "歌詞開頭"),
body: wgULS("歌词", "歌詞"),
lyricist: wgULS("作词", "作詞"),
composer: "作曲",
sub_title: wgULS("副标题", "副標題"),
tag: wgULS("标签", "標籤"),
};
this.fields = Object.entries(labels).reduce((acc, [key]) => {
acc[key] = new OO.ui.TextInputWidget({
value: this.prepopContent[key] || "",
});
return acc;
}, {});
this.queryPanel.$element.append(Object.entries(this.fields).map(([key, field], index) => {
const layout = new OO.ui.FieldLayout(field, {
label: labels[key],
align: "top",
});
layout.$element.css({
width: "50%",
display: "inline-block",
"box-sizing": "border-box",
});
if (!(index % 2)) {
layout.$element.css("padding-right", "1em");
}
if (index === 1) {
layout.$element.css("margin-top", 0);
}
return layout.$element;
}));
this.stackLayout = new OO.ui.StackLayout({
items: [this.queryPanel, this.selectPanel, this.resultPanel],
});
this.$body.append(this.stackLayout.$element);
}
getBodyHeight() {
return this.stackLayout.getCurrentItem().$element.outerHeight(true);
}
getSetupProcess(data) {
return super.getSetupProcess(data).next(() => {
this.actions.setMode("query");
this.stackLayout.setItem(this.queryPanel);
}, this);
}
getReadyProcess(data) {
return super.getReadyProcess(data)
.next(() => {
this.fields.artist_name.focus();
}, this);
}
getActionProcess(action) {
const dfd = $.Deferred();
if (action === "cancel") {
return new OO.ui.Process(() => {
this.close({ action: action });
}, this);
} else if (action === "continue") {
return new OO.ui.Process(() => {
this.selectPanel.$element.empty();
this.search().then(() => {
this.actions.setMode("select");
this.stackLayout.setItem(this.selectPanel);
this.updateSize();
dfd.resolve();
}).catch((e) => {
dfd.reject(new OO.ui.Error(e));
});
return dfd.promise();
}, this);
} else if (action === "back") {
const cur = this.stackLayout.getCurrentItem();
if (cur === this.selectPanel) {
this.actions.setMode("query");
this.stackLayout.setItem(this.queryPanel);
this.updateSize();
} else if (cur === this.resultPanel) {
this.actions.setMode("select");
this.stackLayout.setItem(this.selectPanel);
this.updateSize();
}
} else if (action === "close") {
return new OO.ui.Process(() => {
this.close({ action: action });
}, this);
}
// Fallback to parent handler
return super.getActionProcess(action);
}
async search() {
const $panel = this.selectPanel.$element;
const query = Object.entries(this.fields).map(([key, field]) => `${key === "song" ? "title" : key}=${field.getValue()}`).join("/");
const searchURL = `https://utaten.com/search/${query}/`;
const res = await fetchHTML(searchURL);
if (res.find(".noItem")[0]) {
$panel.html(`<div class="errorbox">${wgULS("无搜索结果", "無搜尋結果")}。</div>`);
return;
}
const table = res.find(".searchResult__title").closest("table");
const results = table.find("tr").map((_, ele) => {
const self = $(ele);
if (!self.find(".searchResult__title")[0]) {
return;
}
const title = self.find(".searchResult__title").text().trim();
const src = self.find(".searchResult__title a").attr("href");
const artist = self.find(".searchResult__name").text().trim();
const lyrics = self.find(".lyricList__beginning").text().trim();
return { title, src, artist, lyrics };
}).get();
const resTable = $(`<table class="wikitable" style="width:100%;"><tr><th>歌曲</th><th>${wgULS("歌词开头", "歌詞開頭")}</th></tr></table>`);
results.forEach((result) => {
$("<tr>").append(`<td>${result.title}<br />by ${result.artist}</td><td>${result.lyrics}</td>`).on("click", () => {
this.getLyrics(/lyric\/(.*?)\//.exec(result.src)[1]);
}).css("cursor", "pointer").on("mouseover", (e) => {
$(e.currentTarget).css("background-color", "#eaecf0");
}).on("mouseout", (e) => {
$(e.currentTarget).css("background-color", "");
}).appendTo(resTable);
});
const manualID = new OO.ui.TextInputWidget();
$panel.empty().append(`<p>${wgULS("请选择您所寻找的歌曲", "請選擇您所尋找的歌曲")}:</p>`, resTable, new OO.ui.FieldsetLayout({
items: [
new OO.ui.FieldLayout(manualID, {
label: wgULS("未找到结果?请手动输入歌词ID", "未找到結果?請手動輸入歌詞ID"),
align: "top",
}),
new OO.ui.FieldLayout(new OO.ui.ButtonWidget({
label: wgULS("搜索", "搜尋"),
icon: "search",
flags: ["progressive"],
}).on("click", () => {
const id = manualID.getValue();
if (!id) {
return;
}
this.getLyrics(id);
})),
],
}).$element);
}
async getLyrics(id) {
const $panel = this.resultPanel.$element;
$panel.html("<p>正在获取歌词……</p>");
this.actions.setMode("result");
this.stackLayout.setItem(this.resultPanel);
this.updateSize();
const res = await fetchHTML(`https://utaten.com/lyric/${id}/`);
const raw = res.find(".hiragana").first().html();
if (!raw) {
$panel.html(`<div class="errorbox">${wgULS("无法找到歌词,请检查", "無法找到歌詞,請檢查")}ID ${id} ${wgULS("是否正确", "是否正確")}。</div>`);
this.updateSize();
return;
}
const replaced = raw.replace(/\n|\r/g, "").replace(/<br>/g, "\n").replace(/<span class="ruby"><span class="rb">(.*?)<\/span><span class="rt">(.*?)<\/span><\/span>/g, (_, o, r) => o.trim() && r.trim() ? `{{Photrans|${o.trim()}|${r.trim()}}}` : o.trim()).trim();
const decoded = $("<textarea/>").html(replaced).text(); // Decode html entities
$panel.empty().append(`<p>${wgULS("转换成功!以下为Photrans歌词", "轉換成功!以下為Photrans歌詞")}:</p>`, new OO.ui.MultilineTextInputWidget({
value: decoded,
autosize: true,
maxRows: 30,
}).$element.css("max-width", "100%"));
this.updateSize();
}
}
const $body = $(document.body);
const windowManager = new OO.ui.WindowManager();
$body.append(windowManager.$element);
const utatenDialog = new UtaTenWindow({
size: "full",
data: {
prepopContent: new mw.Uri(location.href).query,
},
});
windowManager.addWindows([utatenDialog]);
windowManager.openWindow(utatenDialog);
$("#mw-content-text").empty().append(new OO.ui.ButtonWidget({
label: wgULS("打开搜索窗口", "開啟搜尋視窗"),
flags: ["primary", "progressive"],
}).on("click", () => {
windowManager.openWindow(utatenDialog);
}).$element);
})());