MTG Arenaのデッキをブログに貼り付けようとすると、プレイ中は絵で判別するし会話は日本語名でするので英語名だけ出されても自分でも読めない。
そこでアリーナからエクスポートしたテキストを貼り付ければ日本語のカード名に変換する処理を
MTG Developers
を使い作ろうと思いましたが、カードを一回で特定できないため断念中。
APIはOR検索ができるので、当初はカード名を全て取り出して渡せば一回の通信で済むと考えていました。
しかし、カード名での検索では、再録がそれぞれ1件となりページサイズを圧迫します。
基本土地だけで100件中のほとんどを使ってしまうのでよろしくない。
セット名まで指定した検索条件のグループ化までできればよかったのですが、そこまではできなさそう。
一応、APIにはカードごとに一意に割り当てられるハッシュがあるのですが、
id
A unique id for this card. It is made up by doing an SHA1 hash of setCode + cardName + cardImageName
cardImageNameが何を指すのか不明で使えず。そもそもエクスポート内に情報なし。
よって、カード一枚につき名前とセット名で一回一回通信する方法にしようとしましたが、
時折CORS要求に失敗したり、並列のためか数回実行するとCloudflareに弾かれたりと微妙。
そもそも待ち時間が気持ちよくない範囲になったので、素直に諦めてデッキビルダーを使ったほうがいいかなあという具合になりました。
処理時間が許容できてもエラーやセット名の違い等が今後も出そうで継続性がなさそうでした。
カード資産が集まれば4積みが増えてリクエスト数が減るのですが、初期無課金のレアをちょっとずつ積む構成やハイランダー、バベルなどに対して安定して処理を成功させることを考えると満足いく出来は難しいのかなと考えています。
コード
エラーがでなければちゃんと動く作りにはなっているので、遅くても良い場合はもうちょっと頑張ってGithub Pagesにでも投げるかもしれません。
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<textarea id="input" rows="20">
4 Novice Knight (M19) 30
24 Plains (RIX) 192
4 Righteous Blow (GRN) 23
4 Take Heart (GRN) 28
4 Leonin Vanguard (M19) 22
4 Daybreak Chaplain (M19) 10
4 Knight's Pledge (M19) 19
4 Oreskos Swiftclaw (M19) 31
4 Sunhome Stalwart (GRN) 26
4 Blade Instructor (GRN) 1
</textarea>
<select id="lang">
<option value="Japanese">日本語</option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
</select>
<input id="leave" type="checkbox">
<button id="exe">変換</button>
<textarea id="out" rows='20'></textarea>
</body>
<script type="text/javascript">
/*
1 History of Benalia (DAR) 21
2 Squire's Devotion (RIX) 25
1 Legion's Landing (XLN) 22
4 Ajani's Pridemate (M19) 5
3 Ajani's Welcome (M19) 6
2 Cleansing Nova (M19) 9
4 Leonin Vanguard (M19) 22
3 Leonin Warleader (M19) 23
2 Resplendent Angel (M19) 34
4 Revitalize (M19) 35
4 Fountain of Renewal (M19) 235
1 Transmogrifying Wand (M19) 247
23 Plains (M19) 263
4 Dawn of Hope (GRN) 8
2 Divine Visitation (GRN) 10
*/
const input = document.getElementById('input')
const out = document.getElementById('out')
const exe = document.getElementById('exe')
const API_URL = 'https://api.magicthegathering.io/v1/cards'
let text
const makeQuery = (string) => {
const reg = new RegExp('^(\\d+ )' + '(.*)' + ' \\((\\w+)\\) \\d+$', 'gm')
const names = string.replace(reg, '$2').split('\n')
// アリーナでのドミナリアのセット名がAPIと異なるので変換
const sets = string.replace(reg, '$3').replace(/DAR/g, 'DOM').split('\n')
const querys = []
for (var i = names.length - 1; i >= 0; i--) {
querys.push({
'name' : names[i],
'set' : sets[i],
})
}
return querys
//console.log(names,names.replace(/$\n/mg, '|'))
//return names.replace(/$\n/mg, '|')
}
const fetchInfo = (query) => {
const params = new URLSearchParams();
params.set('name', query.name);
params.set('set', query.set);
params.set('pageSize', 1);
// 原因不明で特定カードでのみ出そうなエラーがある。
// クロスオリジン要求をブロックしました: 同一生成元ポリシーにより、https://api.magicthegathering.io/v1/cards?name=Legion%27s+Landing&set=XLN&pageSize=1 にあるリモートリソースの読み込みは拒否されます (理由: CORS 要求が成功しなかった)。[詳細]
// TypeError: NetworkError when attempting to fetch resource.
return fetch(API_URL + '?' + params.toString(), {
mode: 'cors'
})
.then(response => {
return response.json();
})
.then(json => {
console.log(json);
const lang = document.getElementById('lang').value
const isLeaveOriginal = document.getElementById('leave').checked
let replaceName
for (const card of json.cards) {
for (const foreignName of card.foreignNames) {
if (foreignName.language == lang) {
let replace
if (isLeaveOriginal) {
replace = '$1'+ foreignName.name + ' / ' + card.name +' $2'
} else {
replace = '$1'+ foreignName.name +'$2'
}
console.log(text, replace)
text = text.replace(new RegExp('^(\\d+ )' + card.name + '( \\(\\w+\\) \\d+)$', 'm'), replace)
break
}
}
}
})
}
exe.addEventListener('click', async () => {
text = input.value.trim()
console.log(makeQuery(text))
const querys = makeQuery(text)
let requests = []
for (const query of querys) {
requests.push(fetchInfo(query))
}
await Promise.all(requests)
out.textContent = text
console.log(text, out)
})
</script>
</html>