注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
?_=1来访问最新页面。https://mobile.moegirl.org.cn/User:%E6%9D%B1%E6%9D%B1%E5%90%9B/js/ruby.js?_=1/*
该插件是一个歌词注音插件,使用了雅虎日本的文本解析API:ルビ振り。
载入该插件后,在编辑页面右上角的搜索栏左边“更多”中,将添加一个“注音工具”按钮,点击即可呼出该插件的操作界面。
说明一下主要使用方式以及4个功能按钮:
基本用法:左边为一个编辑框,你可以将要注音的歌词粘贴到这个编辑框,点击“添加注音”按钮。待处理完成后,编辑框的将变成ruby注音后的歌词,并在右侧显示预览。
按钮介绍:
获取歌词:将从源代码中第一个指定格式[1] 的LyricsKai模板或其衍生模板的original参数中获取歌词到编辑框中,若源代码中不存在则提示。
添加注音:对编辑框中的文字执行注音,并在完成后显示预览。
需要注意要注音的内容中不能包含日语当用汉字中不存在的汉字(如日语中不使用的中文简体字等),或一些特殊字符(如心形等),
如果包含将导致注音失败,并提示。
提交歌词:将编辑框中的文字提交至页面中第一个指定格式[1] 的LyricsKai模板或其衍生模板的original参数中,这将覆盖original参数中原本的内容,若源代码中不存在则提示。
复制歌词:将编辑框中的文字复制至剪切板。
打开转换列表页面:详见此页面:https://zh.moegirl.org.cn/User:東東君/js/ruby.js/转换列表
开关介绍:
书面语注音:对一些单词进行书面语的注音,如:「明日」(あした => あす),多用于一些比较文艺的歌。
转换规则位于转换列表页面。
[1]:模板传入了original和translated参数,并且original在前,translated在后,这也是目前使用LyricsKai模板的最普遍形式。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@ 特别感谢User:Nzh21 提供的服务器资源 @@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
*/
if (/((?!\.css|模块|module).+)action=(edit|submit)/.test(location.href)) {
let common = []
let kakikotoba = []
$.get("https://zh.moegirl.org.cn/User:東東君/js/ruby.js/转换列表?action=render")
.done(resultUrl => {
const doc = $(resultUrl)
const findRubyTransferGroupByName = name => Array.from(doc.find(`#rubyTransferGroup-${name} > li`)).map(item => item.textContent.split('、'))
common = findRubyTransferGroupByName('common')
kakikotoba = findRubyTransferGroupByName('kakikotoba')
})
var escapes = /[àâäèéêëîïôœùûüÿçÀÂÄÈÉÊËÎÏÔŒÙÛÜŸÇ?!·♡⸱]/g
$(function () {
var rubyHtml = [
' <div id="widget-ruby" style="display:none;">',
' <div id="widget-ruby-hide">×</div>',
' <div class="ruby-left">',
' <div class="ruby-editor">',
' <textarea id="ruby-editor-body" lang="ja"></textarea>',
' <div class="ruby-btn-group">',
' <button id="ruby-getText" title="从模板中获取歌词">获取歌词</button>',
' <button id="ruby-execute" title="对内容添加注音">添加注音</button>',
' <button id="ruby-update" title="将歌词提交至模板">提交歌词</button>',
' <button id="ruby-copy" title="复制歌词至剪切板">复制歌词</button>',
' <label for="ruby-kakikotoba" title="是否应用书面语注音规则,如:「明日」(あした => あす),多用于一些比较文艺的歌" style="display:inline-table; margin-left:10px; background:#eee; padding:3px; border-radius:3px;">',
' <input type="checkbox" id="ruby-kakikotoba" style="vertical-align:-2px;" />',
' <span style="font-size:14px;">书面语注音</span>',
' </label>',
' <button id="ruby-gotoTransferList" title="由于注音API返回一些读音在歌词中并不常用,需要将其替换为常用读音,你可以在转换列表中添加新的转换规则">打开转换列表页面</button>',
' </div>',
' </div>',
' </div>',
' <div class="ruby-right">',
' <div class="ruby-view" lang="ja"></div>',
' </div>',
' </div>',
' <style>',
' #widget-ruby{',
' position: fixed;',
' top: 0;',
' left: 0;',
' bottom: 0;',
' right: 0;',
' z-index: 100;',
' background-color: rgba(0, 0, 0, 0.3);',
' }',
' #widget-ruby-hide{',
' font-size: 30px;',
' font-weight: bold;',
' color: white;',
' font-family: SimSun;',
' position: fixed;',
' top: 10px;',
' right: 20px;',
' transition: transform 0.3s;',
' z-index: 10001;',
' cursor: pointer',
' }',
' #widget-ruby-hide:hover{',
' transform: rotate(90deg);',
' }',
' .ruby-left, .ruby-right{',
' width: 50%;',
' height: 100%;',
' float: left;',
' position: relative;',
' }',
' .ruby-editor-body, .ruby-btn-group{',
' margin: 10px;',
' }',
' .ruby-editor, .ruby-view{',
' width: 450px;',
' height: 80%;',
' min-height: 300px;',
' position: absolute;',
' top: 0; left: 0; bottom: 0; right: 0;',
' margin: auto;',
' background-color: white;',
' border: 3px #ccc solid;',
' }',
' #ruby-editor-body{',
' width: 100%;',
' height: 100%;',
' box-sizing: border-box;',
' resize: none;',
' padding: 5px;',
' outline: none;',
' }',
' .ruby-btn-group{',
' height: 20%;',
' min-height: 70px;',
' }',
' .ruby-view{',
' overflow: auto;',
' padding: 5px;',
' }',
' </style>'].join('')
$('body').append(rubyHtml)
$('#p-cactions ul').append('<li id="btn-ruby"><a title="为日语歌词进行注音">注音工具</a></li>')
$('#btn-ruby').click(function () {
$('#widget-ruby').fadeIn(200)
})
const intervalKey = setInterval(() => {
if ($('#mw-notification-area').length !== 0) {
document.body.appendChild($('#mw-notification-area').get(0)) // 防止提示框被遮挡
clearInterval(intervalKey)
}
}, 300)
var editor = $('#ruby-editor-body'),
view = $('.ruby-view').eq(0),
wikiEditor = $('#wpTextbox1'),
hideBtn = $('#widget-ruby-hide'),
getTextBtn = $('#ruby-getText'),
executeBtn = $('#ruby-execute'),
updateBtn = $('#ruby-update'),
copyBtn = $('#ruby-copy'),
gotoTransferListBtn = $('#ruby-gotoTransferList')
var messages = {
notFound: '代码中并未找到歌词模板(LyricsKai及其衍生模板)!',
badFormat: '歌词模板的格式不正确或不受支持,请手动复制粘贴!',
emptyText: '要注音的内容不能为空!',
badText: '无法注音,请检查内容中是否包含特殊字符或非日语当用汉字、除拉丁字母以外的文字',
timeout: '请求超时!'
}
gotoTransferListBtn.click(() => window.open('https://zh.moegirl.org.cn/User:東東君/js/ruby.js/转换列表', '_blank'))
hideBtn.click(function () {
$('#widget-ruby').fadeOut(200)
})
var regex = /(\{\{[Ll]yricsKai[\s\S]*?\|original=)([\s\S]*?)(\|translated)/
getTextBtn.click(function () {
var codeContent = wikiEditor.val()
if (!/\{\{[Ll]yricsKai/.test(codeContent)) {
mw.notify(messages.notFound, { type: 'error' })
} else {
if (!codeContent.match(regex)) {
mw.notify(messages.badFormat, { type: 'error' })
} else {
var text = codeContent.match(regex)[2]
editor.val(text.trim())
}
}
})
executeBtn.click(function () {
var text = editor.val().trim()
if (text.length == 0) {
mw.notify(messages.emptyText, { type: 'error' })
} else {
function ruby(kanji, kana) {
return '{{photrans|' + kanji + '|' + kana + '}}'
}
text = text.replace(escapes, function (s) { return '!UNICODE(' + escape(s).replace('%', '#') + ')' })
editor.attr('disabled', 'disabled')
$.ajax({
type: 'post',
url: 'https://api.nzh21.site/yahooapis/FuriganaService/V2/furigana',
contentType: 'application/json',
headers: {
'x-ua': "Yahoo AppID: dj00aiZpPXE2azZNYXFyR29kSSZzPWNvbnN1bWVyc2VjcmV0Jng9ODY-"
},
data: JSON.stringify({
"id": "1234-1",
"jsonrpc": "2.0",
"method": "jlp.furiganaservice.furigana",
"params": {
"q": text,
"grade": 1,
"appid": "dj00aiZpPXE2azZNYXFyR29kSSZzPWNvbnN1bWVyc2VjcmV0Jng9ODY-"
}
}),
timeout: '15000',
}).always(function () {
editor.removeAttr('disabled')
}).done(function (data) {
if (data.Error) {
mw.notify(messages.badText, { type: 'error' })
} else {
var wordList = data.result.word
var result = wordList.reduce(function (result, item) {
return result + (() => {
if (item.furigana) {
if (item.subword) {
return item.subword
.map(item => item.furigana !== item.surface ? ruby(item.surface, item.furigana) : item.surface)
.join("")
}
return ruby(item.surface, item.furigana)
}
return item.surface
})()
}, "")
function rubyReplace(patterns) {
for (var i = 0, len = patterns.length; i < len; i++) {
var regex = new RegExp('(\\{\\{photrans\\|' + patterns[i][0] + '\\|)' + patterns[i][1] + '\\}\\}', 'g')
result = result.replace(regex, '$1' + patterns[i][2] + '}}')
}
}
rubyReplace(common)
$('#ruby-kakikotoba').prop('checked') && rubyReplace(kakikotoba)
result = result.replace(/!UNICODE\((.+?)\)/g, function (s, s1) { return unescape(s1.replace('#', '%')) })
editor.val(result)
var viewHtml = result.replace(/\n/g, '<br>').replace(/\{\{photrans\|(.+?)\|(.+?)\}\}/g, '<ruby>$1<rt>$2</rt></ruby>')
view.html(viewHtml)
}
}).fail(function (e) {
mw.notify(messages.timeout, { type: 'error' })
})
}
})
updateBtn.click(function () {
var codeContent = wikiEditor.val()
var ruby = '\n' + editor.val() + '\n\n'
if (!regex.test(codeContent)) {
mw.notify(messages.badFormat, { type: 'error' })
} else {
if (editor.attr('disabled') == 'disabled') {
mw.notify('请先等待注音执行完毕')
return
}
wikiEditor.val(codeContent.replace(regex, '{{photrans/button}}\n' + '$1' + ruby + '$3'))
mw.notify('提交成功!', { type: 'warn' })
hideBtn.click()
}
})
copyBtn.click(function () {
editor.focus()
document.execCommand('selectAll')
document.execCommand('copy')
mw.notify('已复制至剪切板', { type: 'warn' })
})
})
}