LoginSignup
3
1

More than 1 year has passed since last update.

漫画BANK について

Last updated at Posted at 2021-11-11

過去5ヶ月間、ひたすらひとつの違法マンガサイトを見ていた。

ずっと見ていたのは公開されたマンガコンテンツではなく、サイト運営者が作ってるデータをひたすら見ていたので、11 月の 4 日、15 時くらいにサイトをたたんだのを確認した。1

Screenshot_20211104-164634.png

おそらくこの翻訳記事 2021年11月04日 14時00分

Manga Publisher Wants to Sue Huge Piracy Network, Needs Google's Help * TorrentFreak
https://torrentfreak.com/manga-publisher-wants-to-sue-huge-piracy-network-needs-googles-help-211101/

注) 'Shueisha’s application and proposed orders/subpoenas can be found here (1,2,3,4 pdf)' の書類が興味深い。

が公開されたことで、サイト運営者が違法性を自認して、サイト閉鎖を決定したのではないかと思われる。

追記 2021.12.月中頃、mangabank.org とはまた別のドメインで再開している。
画像ファイルのあるアドレスのドメインを whois したところ、cloudflare の管轄のホストではなさそうな感じ。
Screenshot_20211230-001601.jpg

最も新しい情報はこちら

過去に書いたこのような記事は、当時、宣伝につながらないように配慮して明記しなかったが、全て漫画 BANK についてのことだった。

6 月の時点では 5 万ページぼどだと思っていたが 10 月には 6 万ページ以上あることがわかった。

この 6 万ページというのはマンガコンテンツの漫画の総ページ数のことではなくて、URL のことで、そのひとつの URL に 30 点から 300 点ぐらいの画像ファイルの URL が埋め込まれている。
その画像一枚が、漫画のスキャン画像ファイルの一点に相当する。

Screenshot_photo-586353998.png

画像点数にすると、空想すると数えたことないおおきな数になるので、いずれいつか数えようと数えなかったが、その 6 万ページについては 著者 / 漫画のタイトル / 公開されていた URL / アップデート日時の情報 / 付与されていたタグ のデータのセットを記録した。

スキャン画像のファイルの漫画 BANK に読み込まれるようにページの中に URL が埋め込まれていて、観測した限りのその URL は、全てが cloudflare がホスティングしているドメインだった2ので、

2021年 7月の調べ

これが全てではないが、数千のアドレスから集計すると、こちらのドメインに収束した。

0  ssl.appx.buzz

1  ssl.asiax.cloud

2  ssl.stagingy.store

3  ssl.lsw.buzz

4  ssl.advx.cloud

5  ssl.appuru.store

6  ssl.lss.buzz

7  ssl.remon.store

8  ssl.lsq.buzz

9  ssl.lsb.buzz

10  ssl.appsx.cloud

11  ssl.lsh.buzz

12  ssl.raichi.store

13  ssl.lsr.buzz

14  ssl.akaax.com

15  ssl.axax.cloud

16  ssl.lsk.buzz

17  ssl.lsy.buzz

18  ssl.zqap.cloud

19  ssl.skyly.cloud

20  ssl.akax.cloud

21  ssl.zmqx.cloud

22  ssl.lssaq.cloud

23  ssl.lsm.buzz

24  ssl.nexc.store

参照: 🥝ページの中から lazy load の画像 URL を抽出する。

画像の著作権情報3と、公開されている cloudflare のドメインの画像ファイルアドレスのリストがあれば、すんなり停止できるのだろうなと4考えていたが、ずいぶんとほったらかしているな、あれ ? ゼンゼンナニモシナイノ ? と不思議に思えた。
たしか 2019 年5までサイトブロッキング6しかない!7 という主張さえあったのだが8、その前にどこまでどうしたのかは、主張からはさっぱりわからないので、「どこまでどうできるのか」がずっと気にかかっていた。

インターネット上の海賊版対策に関する検討会議 第9回会合 議事録を読んでいると とりまとまらない報告となった理由が熱くて面白かった。「両論併記をしない」という主張についての理由が議事録には残っている。

Rf.インターネット上の海賊版対策に関する検討会議 第9回会合 議事録


Mangabank “Suffers DDoS Attack” & Disappears Following Legal Action
November 9, 2021 by Andy Maxwell

注) 'A declaration filed with the court by Shueisha ( pdf ) contains a copy of Cloudflare's response to the DMCA subpoena filed earlier this year.' のところが興味深い。

漫画 BANK のアップロードして公開されていたタイトル名には命名規則があり、文字列抽出して、タイトルから検索して、間違った書籍情報をひっぱってくるものを選んでよくみると、簡単な間違いをしているものがあった。そして、これは間違いようなさそうなので、なにかもとで間違っていて、改正すると整合がとれないのではないかと思われた。
なにと比べるのか。
つまり、コピーしてきて、世の中では、そのタイトル名が通用していて、それは、オリジナルのタイトルからすると間違っているが、ファイル名としては正しいというような場合が考えられる。

つまり、コピーなのだと思う。自らスキャンして、自らファイル名をつけて、アップロードしてるわけではないという場合、そうなるかなと思う。
そう考えると、そのファイル名で、普通に検索すると、同じ間違ったタイトル名がひっかかるので、そいうことなのだ。

だとするならば、なんらかの理由で漫画をスキャンしてアップロードする人間がいて、それを告知する、そしてそのデータを加工するなどする人間がいるというエコサイクルのなかで、ネット上のアップロードファイルから回収されたものを展示しているということになるので、そのセレクトセンスによって傾向がみられるということである。
かなり古い漫画も選ばれていて、そのタイトルを知っているということは特徴的でもある。

とはいえ、興味は運営者が誰なのか...というところには全く無く、データがどうなってんのかな? どういう風に作ってるのかな? 全部のデータはいくつあるのか知るにはどういうアプローチでやるのかなというところに重点があり、ではどこから来たデータで、どういうモチベーションで出てきたファイルなんだろうかということに疑問をもちはじめた。

なんらかのモチベーションで日本の漫画をスキャニングし、ネットワークにアップロードする行為から始まり、ローカライズ(翻訳)し、漫画の言語を替えて、きれいにタイピングして公開する一連のことを、スキャンレーションと呼んでいるらしい。


scanlation

スキャンレーション( scanlation )で検索すると、その言葉の定義から、ガイドラインやチュートリアル、または役割名称や、その広報的なサイトの情報がたくさんある。

今は活動していないスキャンレーションのグループをターミナルの文字で眺めて数えるプログラム。23 時間経つと消える。

今は活動していないスキャンレーションのグループ名と、そのプロファイルのページのデータベース (sqlite file)。

https://www.mediafire.com/file/qlse91vdwyletgx/scanlation-g.db/file
IMG_20211113_140504_811.jpg

過去に翻訳されたタイトルの和名とそれ以外の対照を作りたい場合は有効かもしれないし、そうでもないかもしれない。

著作権がらみで問題のあるもののダウンロード情報や、データ自体は含まないと宣言されているデータベースとしてのサイトから全てのスキャンレーショングループのプロファイルページの所在を抽出してから、各プロファイルページにアップデートしてアーカイブされている仕事済みの漫画の英語タイトルを抽出すれば、プロファイルされたスキャンレーションングループについては、全ての翻訳漫画タイトルを知れるということになる。
方向グラフとしては 入り口、 グループのプロファイルページの所在、 プロファイルページ内にある翻訳したシリーズ名、日時 という順にたどると効率が良さそう。

1: タイトルを考えるのが面倒な scanlation groups counter プログラム Python link

2: a , b
2つのデータベースをマージする Lua プログラムサンプル link
:[ 依存関係 lsqlite3 https://github.com/LuaDist/lsqlite3/blob/master/examples/smart.lua]

「1。1。1。1。」
https://en.m.wikipedia.org/wiki/1.1.1.1

スキャンレーションもエコシステムの一環で、フェーズとしてはオンラインでの海賊配信の水際に位置していると考えられる。
2次創作漫画画像を作るために、漫画をスキャナーでスキャンする必要があるわけだが、漫画を入手してスキャンし、アップロード ① してダウンロードアドレスを告知する ② ということをしているというところが、ボトムで、スキャンレーションの作業のエントリーポイントにもこの行程が不可欠。
スキャンしてアップロード ① する人は必ずしもスキャンレーションチームにしかいないわけではないが、アップロードされたスキャン済み画像をダウングレード ③ して海賊配信 ④ していたり、スキャン画像をクリーンアップして翻訳、タイプセットして、翻訳版の海賊配信サイトにアップロード ⑤ していたりと、それぞれに直接関係があったり無かったりするのだろうけども、スキャンレーションという枠では、ひとまとまとまり情報として関係性が見える。例えば、このグループがここ ④ へアップロード ⑤ した等。

④ のサイト群については、正当な方法(カドカワ的に「インターネット上の海賊版対策に関する検討会議 第9回会合 平成30年10月15日 議事録5」)similarweb910 11で横並びに見えるもののことを主に指すようだが、ボトムアップから見るとすると、行為とモチベーション度に着目する12とスキャンレーションのサイドからたどると動線も把握できる。スキャンレーションのさらに二次コピーなどが ④ に回収されて公開されている場合もあるだろう。トラフィックの大きさは、配信自体の技術に左右されるので、着目される経済的損失について語られるのはトラフィックの大きな上流の方のことだと思われる。漫画 BANK は ④ に含まれる(すでにアップロードされて海賊配信されているサイトからの画像流用)。

これは想像なのでイマジネーションは図にした方がいい。

oie_1I69MA5YrCfZ.png

image%3A8342.jpg

参考: https://kknews.cc/comic/moz43xz.html

3: link

1:link / 2:link / 3:link とプログラムにせっせと、動いてもらって 3 をポチッとしてから翌日起きて、途中で止まってると思ってたら、朝になっても昼前まで止まらない量のデータをせっせと書き込んでいた。
カウンターは 106000 を越えていて、なんか無理しているなぁと思いつつ、そのわきで次のプログラムを書きはじめて、

oie_png (1).png

4:link を書いた。

たぶんこれも明日もお昼までうごいているんではないか。

漠然とした中での目的としては、翻訳された(おそらく勝手に)漫画のタイトルからオリジナルのタイトルを知りたいのと、その他の言葉でのタイトルを眺めたいので、そうするとどうやって組み上げたらいいのかなということをやってみたい。

ということで、まずスキャンレーショングループが過去から現在まで翻訳したシリーズになった(単行本とかのことだと思われる)ものをカウントアップするために、まずグループのリストを作る。これが 1:link のコード。
1:link でできたリストのなかには、グループについてのプロファイリングされた個別のページのアドレスがあり、このプロファイリングされたページ上にグループの翻訳したシリーズがリストアップされている。
1:link で作れるデータベースを複数足し合わせるのが 2:link のコード。なぜ、Lua なのか、コンパクトで速いから。同じように他の言語で書いて同じような速度かもしれないが、コードを見れば、見える通りのことなのでシンプル。遅くはない。

hy (clojure lisp 風 Python) 言語に合わせて 2:link と同じものを Lua の Lisp 風言語 fennel に直してみると

2:link fennel

merge-sqlite.fnl
(local sqlite3 (require :lsqlite3)) ;;-- dependency https://github.com/LuaDist/lsqlite3

(local db1 (sqlite3.open :scanlation-g-inactive.db)) ;;-- inactive
(local db2 (sqlite3.open :scanlation-g-active.db)) ;;-- active

(local newdb (sqlite3.open :scanlation-g-work.db)) ;;-- for working space / additive

(local newdb1 (sqlite3.open :scanlation-g-new1.db)) ;;-- additive & order by url


(newdb:exec "CREATE TABLE tbl_scanlation (id INTEGER PRIMARY KEY, url text,name text,active int);")
(newdb1:exec "CREATE TABLE tbl_scanlation (id INTEGER PRIMARY KEY, url text,name text,active int);")

(local smt1 "SELECT id FROM tbl_scanlation ORDER BY id DESC LIMIT 1 ;")

(var last1 0)
(var last2 0)

(each [id (db1:urows smt1)]
  (set last1 id))

(each [id (db2:urows smt1)]
  (set last2 id))

(print (.. "db1 has " last1 " URLs"))
(print (.. "db2 has " last2 " URLs"))

(var newcount 0)

(each [last-id (newdb:urows smt1)]
  (set newcount last-id))

(var i 0)

(each [url-data (db2:urows "SELECT url FROM tbl_scanlation ;")]
  (set i (+ i 1))
  (print "copy from db2 ")
  (print i)
  (print (.. "total " last2))
  (var existflag 0)
  (each [exist (newdb:urows (.. "SELECT id FROM tbl_scanlation WHERE url=\""
                                url-data "\" ;"))]
    (set existflag exist)
    (print (.. url-data " is aleady exist in DB / skip")))

  (when (= existflag 0) ;;-- record
    (var tempname "")
    (var tempactive "")
    (each [name (db2:urows (.. "SELECT name FROM tbl_scanlation WHERE url=\""
                               url-data "\";"))]
      (set tempname name))
    (each [active (db2:urows (.. "SELECT active FROM tbl_scanlation WHERE url=\""
                                 url-data "\";"))]
      (set tempactive active))
    (print tempname)
    (set newcount (+ newcount 1))
    (print)
    (print (.. "newdb : " newcount " " url-data " " tempname))
    (local stmt2
           (newdb:prepare " INSERT INTO tbl_scanlation VALUES (:id, :url, :name, :active) "))
    (stmt2:bind_names {:id newcount
                       :url url-data
                       :name tempname
                       :active tempactive})
    (stmt2:step)
    (stmt2:reset)
    (stmt2:finalize)))

(db2:close)

(set i 0) ;;-- reset

(each [url-data (db1:urows "SELECT url FROM tbl_scanlation ;")]
  (set i (+ i 1))
  (print "copy from db1 ")
  (print i)
  (print (.. "total " last1))
  (var existflag 0)
  (each [exist (newdb:urows (.. "SELECT id FROM tbl_scanlation WHERE url=\""
                                url-data "\" ;"))]
    (set existflag exist)
    (print (.. url-data " is aleady exist in DB / skip")))

  (when (= existflag 0);;-- record
    (var tempname "")
    (var tempactive "")
    (each [name (db1:urows (.. "SELECT name FROM tbl_scanlation WHERE url=\""
                               url-data "\";"))]
      (set tempname name))
    (each [active (db1:urows (.. "SELECT active FROM tbl_scanlation WHERE url=\""
                                 url-data "\";"))]
      (set tempactive active))
    (set newcount (+ newcount 1))
    (print)
    (print (.. "newdb : " newcount " " url-data))
    (local stmt2
           (newdb:prepare " INSERT INTO tbl_scanlation VALUES (:id, :url, :name, :active) "))
    (stmt2:bind_names {:id newcount
                       :url url-data
                       :name tempname
                       :active tempactive})
    (stmt2:step)
    (stmt2:reset)
    (stmt2:finalize)))

(db1:close)

(print (.. "new DB last id : " newcount))

(var newdb1-last 0)

(each [last-id (newdb1:urows smt1)]
  (set newdb1-last last-id))

(var counter newdb1-last) ;;-- first time ==> 0

(set i 0);;-- reset

(each [url-data (newdb:urows "SELECT url FROM tbl_scanlation ORDER BY name ;")]
  (set i (+ i 1))
  (print "copy from newdb ")
  (print i)
  (print (.. "total " newcount))
  (var existflag 0)
  (each [exist (newdb1:urows (.. "SELECT id FROM tbl_scanlation WHERE url=\""
                                 url-data "\" ;"))]
    (set existflag exist)
    (print (.. url-data " is aleady exist in DB / skip")))

  (when (= existflag 0);; -- record
    (var tempname "")
    (var tempactive "")
    (each [name (newdb:urows (.. "SELECT name FROM tbl_scanlation WHERE url=\""
                                 url-data "\";"))]
      (set tempname name))
    (each [active (newdb:urows (.. "SELECT active FROM tbl_scanlation WHERE url=\""
                                   url-data "\";"))]
      (set tempactive active))
    (set counter (+ counter 1))
    (print)
    (print (.. "newdb1 : " counter " " url-data))
    (local stmt2
           (newdb1:prepare " INSERT INTO tbl_scanlation VALUES (:id, :url, :name, :active) "))
    (stmt2:bind_names {:id counter
                       :url url-data
                       :name tempname
                       :active tempactive})
    (stmt2:step)
    (stmt2:reset)
    (stmt2:finalize)))

Vim だとプラグインを設定しないとちょっと難しい感じだけど、kakoune だとデフォルトで色分けはしてくれる。どうなってるんでしょう。vis editor も。

プロファイルされたページのシリーズタイトルを足し合わせて記録していくのが 3:link のコード。Python だが hy 言語。今のところ hy で書くメリットは分かりやすさ。
SQLite のバインドも Python 独自のものなので、select して execute されて戻ってくるデータが空のときどうやって空のデータを比較できるのかというところが言語とバインドによって違うので、そこは注意しなくてはいけない。Lua の場合は、空の場合は素通りで、値を判定する式自体を無視するよう、そのことを分かっていたらシンプル。

例えば、

local smt1 = "SELECT id FROM tbl_scanlation ORDER BY id DESC LIMIT 1 ;" 

local last1 = 0

for id in db1:urows(smt1) do
    last1 = id
end

これは Lua バインドで sqlite3 データベースの tbl_scanlation というテーブルのデータの中の primary キー連番 id 番号の最後の int 値を取り出す式を実行して last1 に代入したい箇所だが、テーブルの中にデータが入ってなければ local last1 = 0 で初期化している値が入る。 nil とか -1 とかにはならない。python や Ruby 、 go や nim など、またそれぞれ違うので、いろんな別の言語にて書き換える場合は、無い場合どういう値が入るのかよく調べなければいけない。SQLite3 自体では返ってくる値は決められているが、その値に対する値は、バインドによって書き換えられて処理されているようなので。

3:link で出来上がるデータベースの件数は三万件くらいだろうかと思っていたが、10 万件以上だった。SQLite の場合は扱える数はそれ以下のはずだが、無理でもできるとこまででいいのでがんばってもらう。

4:link の様子。お昼になっても終わっていない。
Screenshot_20211120-113635.png

一週間くらい経ってる気がするが、VALID データが 96,426 。つまり、中国、韓国、日本の漫画がスキャンレーショングループによって、それだけの数は翻訳されている。
sqlite3 database file
https://we.tl/t-xUEh2MPRcF

Screenshot_20211211-143003_kindlephoto-66542057.png

ちなみに漫画BANK は 65000 以上 url があったので、それだけ分の漫画が掲載されていたことになるだろう。60300 前後までは、タイトルの記録がある。

つづき

  1. 2021/11/17 はこんな状況 https://pastebin.com/fTcHK0ti

  2. 違法と思われるマンガ Thank(仮称)の HTML の構造をよく確認する

  3. 本の ISBN 情報なしに、本の題名から書籍データを抽出したいということ。

  4. 権利侵害記事、保存も違法 東京地裁が米社に仮処分 2018年10月10日

  5. インターネット上の海賊版対策に関する検討会議 2

  6. 海賊版サイトをブロッキングするための5つの手法 Internet Society 日本支部 2018年6月22日

  7. カドカワ川上量生社長が語る、サイトブロッキングの必要性 浅川 直輝 日経xTECH/日経コンピュータ

  8. 海賊版「ブロッキング」法制化断念 政府、広告抑制など総合対策で対応 2019/1/14

  9. 資料7 https://www.kantei.go.jp/jp/singi/titeki2/tyousakai/kensho_hyoka_kikaku/2018/kaizoku/dai9/gijisidai.html

  10. https://en.globes.co.il/en/article-similarwebs-controversial-route-to-wall-street-1001376912

  11. These Chrome extensions spy on 8 million users 31 Mar 2016 https://mweissbacher.com/2016/03/31/these-chrome-extensions-spy-on-8-million-users/

  12. https://www.reddit.com/r/scanlation/about/

3
1
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
1