Skip to content

Instantly share code, notes, and snippets.

@sinsinpub
Last active March 4, 2022 14:43
Show Gist options
  • Save sinsinpub/ed0643b62ef386037de532de4ecd98d3 to your computer and use it in GitHub Desktop.
Save sinsinpub/ed0643b62ef386037de532de4ecd98d3 to your computer and use it in GitHub Desktop.
From KanColle wikiwiki, extract and print Kanmusu quotes JSON at console for KC3Kai.
// ==UserScript==
// @name KanColle wikiwiki subtitles crawler
// @author sin_sin
// @namespace https://gist.github.com/sinsinpub
// @version 0.7
// @description Extract and print Kanmusu quotes JSON at devtools console for KC3Kai.
// @copyright 2017-2021, sin_sin
// @match https://wikiwiki.jp/kancolle/
// @include https://wikiwiki.jp/kancolle/*
// @icon https://cdn.wikiwiki.jp/to/w/common/user-favicon.ico
// @grant unsafeWindow
// @grant GM_setClipboard
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
const $ = unsafeWindow.$ || document.querySelector.bind(document);
const removeFootnote = function(txt) {
return (txt || "").replace(/\*[0-9]{1,2}\b/g, "").trim();
};
const removeSpoilerTag = function(txt) {
return (txt || "").replace(/^silver$/, "").replace("&color(foreground[,background]){text};", "");
};
const getTextByTitle = function(table, title, row = 1, etype = "td,th", returnElm = false) {
const td = $(etype, table).filter(
(i, el) => (
title.startsWith("*") ?
$(el).text().includes(title.substr(1)) :
title.startsWith("=") ?
$(el).text() === title.substr(1) :
$(el).text().startsWith(title)
)
);
if(td.length > 0) {
if(returnElm) {
return td.length === 1 ? td : td.first();
}
if(row > 1) {
let tr = td.first().parent();
for(let i = 1; i < row; i++) tr = tr.next();
return removeFootnote(tr.children().first().text());
} else if(!row) {
return removeFootnote(td.text());
} else {
return removeFootnote(td.first().next().text());
}
}
return "";
};
const parseOldFormatTable = function(subObj) {
const quotesTd = getTextByTitle($("body"), "セリフ", 1, "th", true);
if(quotesTd.length > 0) {
const quotesTable = quotesTd.parent().parent().parent();
subObj.ID.Intro = getTextByTitle(quotesTable, "*ログイン");
subObj.ID["Poke(1)"] = getTextByTitle(quotesTable, "*詳細閲覧", 1);
subObj.ID["Poke(2)"] = getTextByTitle(quotesTable, "*詳細閲覧", 2);
subObj.ID["Poke(3)"] = getTextByTitle(quotesTable, "*クリック時");
if(!subObj.ID["Poke(3)"]) {
subObj.ID["Poke(3)"] = getTextByTitle(quotesTable, "*詳細閲覧", 3);
if(subObj.ID["Poke(3)"].endsWith("クリック時")) subObj.ID["Poke(3)"] = "";
}
subObj.ID.Construction = getTextByTitle(quotesTable, "建造完了");
subObj.ID.Return = getTextByTitle(quotesTable, "帰投");
subObj.ID.Ranking = getTextByTitle(quotesTable, "戦績表示");
subObj.ID["Equip(1)"] = getTextByTitle(quotesTable, "改装", 1);
subObj.ID["Equip(2)"] = getTextByTitle(quotesTable, "改装", 2);
subObj.ID["Equip(3)"] = getTextByTitle(quotesTable, "改装", 3);
if(subObj.ID["Equip(3)"].endsWith("アイテム発見)")) {
subObj.ID["Equip(3)"] = getTextByTitle(quotesTable, "*アイテム発見");
}
subObj.ID.Supply = getTextByTitle(quotesTable, "補給");
subObj.ID["Docking(1)"] = getTextByTitle(quotesTable, "*小破以下");
subObj.ID["Docking(2)"] = getTextByTitle(quotesTable, "*中破以上");
subObj.ID.Join = getTextByTitle(quotesTable, "編成");
subObj.ID.Sortie = getTextByTitle(quotesTable, "出撃", 1);
if(subObj.ID.Sortie === subObj.ID.Join) {
subObj.ID.Sortie = getTextByTitle(quotesTable, "出撃", 2);
}
subObj.ID.Battle = getTextByTitle(quotesTable, "開戦");
subObj.ID.Attack = getTextByTitle(quotesTable, "攻撃", 1);
if(subObj.ID.Attack === subObj.ID.Battle) {
subObj.ID.Attack = getTextByTitle(quotesTable, "攻撃", 2);
}
subObj.ID["Yasen(1)"] = getTextByTitle(quotesTable, "夜戦開始");
subObj.ID["Yasen(2)"] = getTextByTitle(quotesTable, "*夜戦攻撃");
subObj.ID["Damaged(1)"] = getTextByTitle(quotesTable, "小破", 1);
subObj.ID["Damaged(2)"] = getTextByTitle(quotesTable, "小破", 2);
if(subObj.ID["Damaged(2)"].endsWith("旗艦大破")) {
subObj.ID["Damaged(2)"] = getTextByTitle(quotesTable, "*旗艦大破");
//subObj.ID["Damaged(1)"] = getTextByTitle(quotesTable, "小破", 1);
}
subObj.ID["Damaged(3)"] = getTextByTitle(quotesTable, "中破");
subObj.ID.Sunk = removeSpoilerTag(getTextByTitle(quotesTable, "轟沈"));
subObj.ID.MVP = getTextByTitle(quotesTable, "勝利MVP");
subObj.ID.Wedding = removeSpoilerTag(getTextByTitle(quotesTable, "ケッコンカッコカリ"));
subObj.ID.Married = removeSpoilerTag(getTextByTitle(quotesTable, "ケッコン後母港"));
subObj.ID.Idle = getTextByTitle(quotesTable, "放置時");
const libDesc = getTextByTitle($("body"), "図鑑説明", 1, "th", true);
if(libDesc) subObj.ID.Library = removeFootnote(libDesc.parent().next().children().first().text());
const timeAlert0400 = getTextByTitle(quotesTable, "時報", 5);
if(timeAlert0400) {
for(let i = 0; i < 24; i++) {
subObj.ID["H" + (i < 10 ? "0" : "") + i + "00"] = getTextByTitle(quotesTable, "時報", i + 1);
}
}
return true;
}
return false
};
// new quotes table formation, all remodels are merged into one table. TODO list all lines for every remodels
// https://wikiwiki.jp/kancolle/%E8%AD%B0%E8%AB%96%E6%8E%B2%E7%A4%BA%E6%9D%BF/%E8%89%A6%E5%A8%98%E3%83%9C%E3%82%A4%E3%82%B9%E4%B8%80%E8%A6%A7%E8%A1%A8%E3%81%AE%E5%88%A5%E8%A1%A8%E5%8C%96
const parseNewFormatTable = function(subObj) {
const newTableHead = getTextByTitle($("body"), "定型ボイス一覧", 1, "h3", true);
if(newTableHead.length > 0) {
const quotesTable = newTableHead.parent();
subObj.ID.Intro = getTextByTitle(quotesTable, "入手/");
subObj.ID["Poke(1)"] = getTextByTitle(quotesTable, "詳細");
subObj.ID["Poke(2)"] = getTextByTitle(quotesTable, "母港2");
subObj.ID["Poke(3)"] = getTextByTitle(quotesTable, "母港3");
subObj.ID.Construction = getTextByTitle(quotesTable, "建造完了");
subObj.ID.Return = getTextByTitle(quotesTable, "帰投");
subObj.ID.Ranking = getTextByTitle(quotesTable, "戦績表示");
subObj.ID["Equip(1)"] = getTextByTitle(quotesTable, "改修/");
subObj.ID["Equip(2)"] = getTextByTitle(quotesTable, "装備2");
subObj.ID["Equip(3)"] = getTextByTitle(quotesTable, "*/発見");
subObj.ID.Supply = getTextByTitle(quotesTable, "補給");
subObj.ID["Docking(1)"] = getTextByTitle(quotesTable, "*(小破以下)");
subObj.ID["Docking(2)"] = getTextByTitle(quotesTable, "*(中破以上)");
subObj.ID.Join = getTextByTitle(quotesTable, "=編成");
subObj.ID.Sortie = getTextByTitle(quotesTable, "=出撃", 1);
subObj.ID.Battle = getTextByTitle(quotesTable, "昼戦開始");
subObj.ID.Attack = getTextByTitle(quotesTable, "昼戦攻撃");
subObj.ID["Yasen(1)"] = getTextByTitle(quotesTable, "夜戦開始");
subObj.ID["Yasen(2)"] = getTextByTitle(quotesTable, "夜戦攻撃");
subObj.ID["Damaged(1)"] = getTextByTitle(quotesTable, "小破", 1);
subObj.ID["Damaged(2)"] = getTextByTitle(quotesTable, "小破", 2);
subObj.ID["Damaged(3)"] = getTextByTitle(quotesTable, "中破/");
subObj.ID.Sunk = removeSpoilerTag(getTextByTitle(quotesTable, "轟沈"));
subObj.ID.MVP = getTextByTitle(quotesTable, "勝利MVP");
subObj.ID.Wedding = removeSpoilerTag(getTextByTitle(quotesTable, "ケッコンカッコカリ"));
subObj.ID.Married = removeSpoilerTag(getTextByTitle(quotesTable, "ケッコン後母港"));
subObj.ID.Idle = getTextByTitle(quotesTable, "放置時");
const libDesc = getTextByTitle($("body"), "図鑑説明", 1, "th", true);
if(libDesc) subObj.ID.Library = removeFootnote(libDesc.parent().next().children().first().text());
const timeAlert0400 = getTextByTitle(quotesTable, "時報ボイス一覧", 1, "h3", true);
if(timeAlert0400) {
const hourlinesTable = timeAlert0400.next();
for(let i = 0; i < 24; i++) {
const timeName = (i < 10 ? "0" : "") + i;
subObj.ID["H" + timeName + "00"] = getTextByTitle(hourlinesTable, timeName);
}
}
return true;
}
return false
};
const subObj = {"ID":{}};
let quotesFound = parseNewFormatTable(subObj);
if(!quotesFound) quotesFound = parseOldFormatTable(subObj);
// only run at shipgirl page
if(!quotesFound) {
unsafeWindow.console.debug("Quotes table not found");
} else {
const subJson = JSON.stringify(subObj, null, '\t');
unsafeWindow.console.info(subJson);
unsafeWindow.subtitles = subObj;
if(subObj.ID.Intro) {
GM_setClipboard(subJson);
unsafeWindow.console.debug("Quotes JSON copied to clipboard");
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment