Last active
November 17, 2016 01:18
-
-
Save knoajp/8e0f82e21731b8ed38d408e2cb50e97c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name ShogiDB2 DownloadLinkCreator | |
// @description 将棋DB2の検索結果一覧ページに棋譜ダウンロードボタンを追加します。 | |
// @include https://shogidb2.com/latest* | |
// @include https://shogidb2.com/floodgate* | |
// @include https://shogidb2.com/tournament/* | |
// @include https://shogidb2.com/player/* | |
// @include https://shogidb2.com/strategy/* | |
// @require https://cdn.rawgit.com/polygonplanet/encoding.js/master/encoding.min.js | |
// @namespace knoa.jp | |
// @version 1.1 | |
// ==/UserScript== | |
(function () { | |
console.log('ShogiDB2 DownloadLinkCreator'); | |
var KEYWORDS = ['竜王戦','名人戦','順位戦','王位戦','王座戦','棋王戦','王将戦','棋聖戦','十段戦','九段戦'];/*対局情報に含まれていればハイライト*/ | |
var TITLES = ['竜王','名人','王位','王座','棋王','王将','棋聖','叡王','朝日杯','銀河','NHK杯','JT杯'];/*対局者名から取り除く称号*/ | |
var FILETYPE = 'KIF';/*棋譜ファイルの形式(CSA,KIF,KI2)*/ | |
var ENCODING = 'SJIS';/*棋譜ファイルの文字コード変換(SJIS,UTF8,...)※ブックマークレット実行時は無効*/ | |
var INTERVAL = 1000;/*短時間連続読み込みの抑制*/ | |
var LIMIT = 9999;/*取得数制限(デバッグ用)*/ | |
var AUTO = false;/*自動ダウンロード(キーワードが含まれる棋譜のみ)*/ | |
var games = document.getElementsByClassName('list-group-item');/*検索結果一覧*/ | |
var start = document.createElement('a');/*起動ボタン*/ | |
var core = { | |
/*初期化*/ | |
'initialize': function(){ | |
console.log('initialize...'); | |
var year, script; | |
core.attatchStyle(); | |
start.className = 'make-downloads btn btn-primary'; | |
start.textContent = AUTO ? '自動ダウンロード開始' : 'ダウンロードボタン生成'; | |
start.addEventListener('click', function(e){ | |
this.classList.add('disabled'); | |
for(var i=0; games[i]; i++){ | |
core.markKeywords(games[i]); | |
} | |
/*自動ダウンロード時は先に取得予定リストを揃えておく*/ | |
if(AUTO){ | |
year = prompt('何年度までさかのぼりますか?', (new Date()).getFullYear()); | |
core.paginate(document.querySelector('a[aria-label="Next"]').href, year); | |
} | |
/*棋譜データ処理スクリプトを取得してからボタン生成を始める*/ | |
script = document.createElement('script'); | |
script.src = '/js/shogiboard.min.js'; | |
script.addEventListener('load', function(e){ | |
core.createLink(0); | |
}); | |
document.getElementsByTagName('head')[0].appendChild(script); | |
}); | |
document.querySelector('h2').appendChild(start); | |
}, | |
/*スタイル付与*/ | |
'attatchStyle': function(){ | |
console.log('attatchStyle...'); | |
var style, css = ''; | |
css += 'a.keywords{background:#ccddee!important;}'; | |
css += 'a.make-downloads{position:absolute;right:15px;}'; | |
css += 'a.download{position:absolute;right:30px;margin-top:-45px;}'; | |
style = document.createElement('style'); | |
style.textContent = css; | |
document.getElementsByTagName('head')[0].appendChild(style); | |
}, | |
/*キーワードを含む棋譜を特定*/ | |
'markKeywords': function (game) { | |
if(game.textContent.match(new RegExp(KEYWORDS.join('|'))) != null){ | |
game.classList.add('keywords'); | |
} | |
}, | |
/*自動ページネーション*/ | |
'paginate': function (url, year) { | |
console.log('paginate...', url); | |
var xhr, d, gs; | |
setTimeout(function () { | |
xhr = new XMLHttpRequest(); | |
xhr.open('GET', url); | |
xhr.responseType = 'document'; | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState == 4 && xhr.status == 200) { | |
d = xhr.responseXML; | |
gs = d.querySelectorAll('a.list-group-item'); | |
for(var i=0; gs[i]; i++){ | |
if(year+'年04月' <= gs[i].querySelector('p:nth-child(2)').textContent.replace(/\b([1-9])(月)/g, '0$1$2')){ | |
core.markKeywords(gs[i]); | |
games[0].parentNode.insertBefore(gs[i], null); | |
}else{ | |
core.markKeywords(); | |
return; | |
} | |
if(!gs[i+1] && d.querySelector('a[aria-label="Next"]')){ | |
core.paginate(d.querySelector('a[aria-label="Next"]').href, year); | |
} | |
} | |
} | |
}; | |
xhr.send(); | |
}, INTERVAL); | |
}, | |
/*棋譜ダウンロードボタン生成*/ | |
'createLink': function (i) { | |
console.log('createLink...', i); | |
var a, xhr, d, table, date, title, sente, gote, kifu; | |
/*自動モードのときはキーワードを含まない棋譜は無視する*/ | |
if(AUTO && !games[i].classList.contains('keywords')){ | |
if (!games[i+1] || LIMIT <= i+1){ | |
start.textContent = '完了'; | |
console.log('done.'); | |
return; | |
} | |
core.createLink(i+1); | |
return; | |
} | |
/*無効状態のボタンを作っておく*/ | |
a = document.createElement('a'); | |
a.className = 'download btn btn-primary disabled'; | |
a.textContent = FILETYPE + '形式'; | |
games[i].parentNode.insertBefore(a, games[i].nextSibling); | |
setTimeout(function () { | |
xhr = new XMLHttpRequest(); | |
xhr.open('GET', games[i].href); | |
xhr.responseType = 'document'; | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState == 4 && xhr.status == 200) { | |
d = xhr.responseXML; | |
/*ここからファイル名構築*/ | |
table = d.querySelector('table'); | |
date = table.querySelector('tr:nth-child(1) td').textContent.replace(/\b([1-9])(月|日)/g, '0$1$2'); | |
title = table.querySelector('tr:nth-child(2) td').textContent; | |
sente = core.normalizeName(table.querySelector('tr:nth-child(4) td').textContent); | |
gote = core.normalizeName(table.querySelector('tr:nth-child(5) td').textContent); | |
a.download = [date, title, sente, gote].join('-') + '.' + FILETYPE.toLowerCase(); | |
/*ここから棋譜取得*/ | |
eval(d.querySelector('body>script[type]').textContent);/*"var data = {(json)}"であることを信頼*/ | |
kifu = core.exportKifu(data); | |
/*ここからボタン有効化*/ | |
a.href = core.kifuToObjectURL(kifu); | |
if(AUTO && games[i].classList.contains('keywords')){ | |
a.click(); | |
a.textContent = "済"; | |
}else{ | |
a.classList.remove('disabled'); | |
} | |
} | |
}; | |
xhr.send(); | |
if (!games[i+1] || LIMIT <= i+1){ | |
start.textContent = '完了'; | |
console.log('done.'); | |
return; | |
} | |
core.createLink(i+1); | |
}, INTERVAL); | |
}, | |
/*段位タイトルを削除*/ | |
'normalizeName': function(name){ | |
var dan = new RegExp('((女流|奨励会)?[初一二三四五六七八九・](級|段|冠)|' + TITLES.join('|') + ')$', 'g'); | |
name = name.replace(dan, ''); | |
name = name.replace(/ | /g, ''); | |
return name; | |
}, | |
/*指定形式で棋譜ファイル生成*/ | |
'exportKifu': function(data){ | |
switch(FILETYPE){ | |
case 'CSA': | |
return new CSAExporter(data).export(); | |
case 'KIF': | |
return new KifExporter(data).export(); | |
case 'KI2': | |
return new KI2Exporter(data).export(); | |
} | |
}, | |
/*棋譜ファイルからobjectURL生成*/ | |
'kifuToObjectURL': function(kifu){ | |
var kifuArray; | |
if(typeof Encoding === 'undefined' || ENCODING == 'UTF8'){ | |
kifuArray = [new Uint8Array([0xEF, 0xBB, 0xBF])/*BOM追加*/, kifu]; | |
}else{ | |
kifuArray = [new Uint8Array(Encoding.convert(kifu, {to:ENCODING, from:'AUTO', type:'array'}))]; | |
} | |
return window.URL.createObjectURL(new Blob(kifuArray)); | |
} | |
}; | |
core.initialize(); | |
}) (); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment