3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アニメ名探偵コナンの放送話情報を得るために誤りと表記ゆれの海なYTVのjsonと格闘する

Last updated at Posted at 2021-06-05

注意

微粒子レベルですが名探偵コナンとまじっく快斗のネタバレを含んでいます。苦手な方は注意して読み進めてください。

はじめに

皆さん、アニメ名探偵コナンはご存知でしょうか?「真実はいつも一つ!」とかのたまってる見た目は子ども、頭脳は(自称)大人なバーローが主人公のあのアニメです。

さて、アニメ名探偵コナンはytv(日本テレビ系列)が制作しているので、そこに公式Webページがあります。
そしてこれまでの放送話(事件ファイル)を公開しています。
https://www.ytv.co.jp/conan/archive/index.html

公式の事件ファイルのページはどのように作られているか

最近仕様変更が入ったのですがそれに基づいて話をしていきます。

通信をブラウザで調査すると主に2つのjsonファイルが登場します。

これをもとに自作のツールを作ろうとしていたので具体的に公式でこのjsonをどうパースしてDOMを組み立ててるかは意図的に見ないことにしました。著作権侵害とか言われても困りますしね。

これらのjsonには以下の4つに分類される情報が時系列に混ぜられて格納されています。

  • 通常の放送
  • 再放送(デジタルリマスター版)
  • まじっく快斗の放送(名探偵コナンと同じ原作者青山 剛昌先生の作品、怪盗)
  • なぜか放送話の連番から外れた「謹賀新年 毛利小五郎」(2015年1月3日放送)
  • 劇場版のTV放送情報(むかしのほうだけ)

(おい、5つあるぞ)

今回は劇場版のTV放送情報は無視することにしました。

story.jsonの誤りと表記ゆれの数々

YTVが提供しているこのstory.jsonには誤りと表記ゆれが多数存在しています。見ていきましょう。

「名探偵コナンスペシャル 『風林火山 迷宮の鎧武者』」

当該部分のjsonは次のとおりです。

			{
				"oaDateId"	: "20081103",
				"title"			: "名探偵コナンスペシャル 『風林火山 迷宮の鎧武者』",
				"story_num"	: "",
				"url"				:	"k116921.html"
			},

story_numが抜けています。516が正しい値です。

「怪盗キッドの瞬間移動魔術」

当該部分のjsonは次のとおりです。

			{
				"oaDateId"	: "20081020",
				"title"			: "怪盗キッドの瞬間移動魔術",
				"story_num"	: "",
				"url"				:	"k116923.html"
			},

story_numが抜けています。515が正しい値です。

()()の不統一

jsonを示すのはやめますが統一されていません。どっちかにしてくれ・・・。

story_numRから始まるけどオリジナルの放送時とタイトルが一致しない例

title内のデジタルリマスターの表現が自由すぎる

まあそもそもstory_numRから始まるとデジタルリマスター版であるということになっています。ところが、titleにデジタルリマスターであることを示す文言が入っていなかったり、入り方が多岐に渡ります。

  1. そもそもそんなものは含まれていない
    デジタルリマスター版放映が始まった初期に多いです。

  2. デジタルリマスターで終端する
    わかりやすくていいですね。最近のに多めな気がします。

  3. 正規表現でどうにか引っ掛けられるケース

    const degitalReMasterSearchRegex = /(.+)[[(([]デジタル *リマスター.*[))\]]$/;
    

    のような正規表現で引っかかります。括弧が同種類で対応しないことすらあります。あとデジタル リマスター/デジタルリマスターの2パターンあります。揺れ過ぎな?ちなみにこの正規表現は黒の組織との接触(デジタルリマスター特別編集版)みたいなやつにも対応しています。

    しかもここからさらに

    const pureTitle = executed[1].replace(/[ 〔(]+(.{1,2})[〕) ]*$/, '($1編)');
    ```
    
    のような置換が必要です。前後編以外にも`仏滅に出る悪霊解決編`みたいなパターンがあります。
    
  4. 正規表現で「」の中を抜き出すことでなんとかなるケース
    秋の本格的ミステリースペシャル 「呪いの仮面は冷たく笑う」(デジタルリマスター版)(2004/9/20)が実例ですね。

    const bracket = /「(.+)」/.exec(title);
    

    ただし秋のミステリースペシャル名探偵コナン「鳥取クモ屋敷の怪(デジタルリマスター)」(2007/10/29)のように抜いたあとにさらにデジタルリマスターのような何かを含んでいることもあるので

    const degitalReMasterSearchRegex = /(.+)[[(([]デジタル *リマスター.*[))\]]$/;
    //略
    const maybePureTitle = bracket[1];
    const executed = degitalReMasterSearchRegex.exec(maybePureTitle);
    

    のようにさらなる抽出が必要です。そして鳥取クモ屋敷の怪は初回は3話に分けて放送されていますからそれも想定して

    const matched = this.pure.filter(c => c.title.includes(pureTitle));
    

    のように全体検索で絞り込む必要が出てきます。

あらかじめstory.jsonを置換しておかないときついケース

こういう努力にも関わらずうまく行かないものがたくさんあるので予めstory.jsonを置換するプログラムを書くことにしました。

storyConverter.ts

  • 集められた名探偵~: 再放送は分割されたので集められた名探偵!工藤新一VS怪盗キッド
  • 容疑者毛利小五郎~: もとの話は`容疑者・毛利小五郎~
  • ブラックインパクト~: 再放送は分割されたので名探偵コナン放送10周年記念超拡大スペシャル「ブラックインパクト!組織の手が届く瞬間」
  • 闇の男爵殺人事件~: s/闇の男爵殺人事件・(.+)編\(デジタルリマスター\)/闇の男爵(ナイトバロン)殺人事件($1篇)/
  • 園子のアブナイ夏物語: s/園子のアブナイ夏物語((.+)編)\(デジタル・*リマスター\)/園子のアブない夏物語($1編)
const replaceList = [
  ['TVドラマロケ殺人事件(デジタルリマスター)', 'TVドラマロケ殺人事件'],
  ['標的(ターゲット)は毛利小五郎(デジタルリマスター)', '標的は毛利小五郎'],
  ['帝丹小7不思議事件(デジタルリマスター)', '帝丹小7不思議事件'],
  ['1年B組大作戦!(デジタルリマスター版)', '1年B組大作戦!'],
  ['黒の組織との再会', '黒の組織との再会(灰原編)'],
  ['名探偵コナンスペシャル「工藤新一NYの事件」', '工藤新一NYの事件(事件編)'],
  ['黒の組織との接触(デジタルリマスター特別編集版)', '黒の組織との接触(交渉編)'],
  ['そして人魚はいなくなった(デジタルリマスター特別編集版)', 'そして人魚はいなくなった(事件編)'],
  ['名探偵コナン10周年記念スペシャル 「コナンVS怪盗キッド」(デジタルリマスター版)', 'コナンVS怪盗キッド'],
  ['名探偵コナン1時間スペシャル「空飛ぶ密室 工藤新一最初の事件」', '空飛ぶ密室 工藤新一最初の事件'],
  [
    '名探偵コナン秋の本格ミステリー2時間スペシャル 揺れる警視庁1200万人の人質」(デジタルリマスター版) ',
    '揺れる警視庁 1200万人の人質',
  ],
  ['1時間スペシャル(デジタルリマスター版)「迷宮への入り口 巨大神像の怒り」', '迷宮への入口 巨大神像の怒り'],
  ['怪盗キッドの驚異空中歩行', '怪盗キッドの驚異空中歩行」1時間スペシャル】'],
];

加えてこれらの手動置換が必要です。

case.jsonに対する補正

フォーマットが変わったcase.json、比較的揺れが少ないので「title内のデジタルリマスターの表現が自由すぎる」の項目の対策だけである程度通るので助かるのですが、やっぱり補正がいらないわけではないようです。

大捜索 9つのドア

大捜索 9つのドアという放送話ですが、じつはデジタルリマスター版で、もとの放送話は大捜索九つのドアというタイトルです。

緋色の帰還

上記のような対策をしてもう完璧やろと安心しきっていました。しかし2021年4月、毎週回すようにしていたCIが落ちた知らせが入ります。何かと思ったら「緋色の帰還」系でやらかしてくれました。こいつもまたタイトルだけではデジタルリマスター版と見抜けないシリーズです。しかも元の放送話とタイトルの規則が違うので置換が必要です。

const replaceScarletCase = (title: string) => {
  if (!title.startsWith('緋色の帰還')) return undefined;
  const k = '(デジタルリマスター)';
  // 2021-04-10放送のタイトルは、緋色の帰還(真相)、なんと(デジタルリマスター)って書いてない!
  const t = title.endsWith(k) ? title.substring(0, title.length - k.length) : title;
  return t.replace(/緋色の帰還(([^]+))/, '緋色の$1');
};

名探偵コナン放送話検索ツールを作ったが、結局どういうフローでこれらの誤りに立ち向かっているのか

これが作ったものです。

typescriptで書いています。ビルドにはWebpackを使っていましたがesbuildに乗り換えました。テストコードの実行が律速するのでCIの実行時間的にはあまり意味はありません。

ビルドは2回行われます

  1. story.jsonの事前変換ツールのビルド
  2. story.jsonの事前変換: 実行時に持っていけない辛さを予めなんとかする
    1. 初回放送っぽいのを抜き出す
    2. 手動置換や正規表現を駆使して再放送と初回放送をさらに分離
    3. まじっく快斗/怪盗キッドを含むor聖夜(イブ)は恋するゲレンデではまじっく快斗に分離
    4. 残りは特別話として扱う
  3. 変換されたstory.jsonをbundleして実行時に動かすツールをビルド

実行時にはcase.jsonを取得して分類していきます。このときPureDatabase#find関数が上記のような変換をして揺れを吸収します。ただしcase.jsonに対する補正は分類の前に当てます。

教訓

世に送り出すデータがきちんと正規化されていないと、利用者はこういう膨大な苦労が必要になります。
YTVさんはべつにデータを提供しようとはさほど思っていないだろうと予想できますのでいいのですが、
データを提供しよう、という人は使う人がパースしやすい形式で正規化して提供するように心がけるといいと思います。

注意

npm packageにするとstory.jsonを梱包するような形になるので著作権に控えめに言って喧嘩を売ってしまうものと思います。ましてや再頒布とかするのはアウトです。やめましょう。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?