mattintosh note

どこかのエンジニアモドキの備忘録

macOSでpixivFANBOXに大きなファイルをアップする方法を考えてみる

先日、pixivFANBOX にファイルをアップロードしようとしたら 1 ファイル 300 MB までの制限に引っかかってしまいました。

fanbox.pixiv.help

というわけでファイルを分割してアップロードしたり、ユーザさんに手元で結合してから解凍してもらったりしなければなりません。しかし、macOS に付属のアーカイブユーティリティは分割された ZIP ファイルの解凍に対応していません。サードパーティ製のアーカイバにはその機能が付いていたりすることもありますが、出来ればそういう余計なものをインストールせずに使ってもらいたいのでファイルサイズの大きなファイルを分割して pixivFANBOX や BOOTH にアップロードする方法を考えてみました。

pixivFANBOX のアップローダについて

「300 MB」ってどういうサイズなのか

試してみたところ 314,572,800(2^20*3)バイトではなく 300,000,000(10^6*300)バイトでした。1 バイトでも超えるとアップロードする前にブラウザに拒否されます。

2019年2月時点でアップロード方法の拡充を検討していたようですが現時点では変化は無い気がします。ストレージや帯域の確保なども大変でしょうからなかなか難しいのではないかと思います。

BOOTH では 1 GB まで対応しているようです。比較的大きなサイズではありますがゲームや映像作品だと超えてしまうことがありそうな気がします。

booth.pixiv.help

pixivFANBOX のアップローダは拡張子偽装不可

何らかの方法でファイルを分割したとしてそれがアップロード可能な形式ではない場合、例えば拡張子を .zip.txt に変えてしまえばとりあえず pixivFANBOX 側に送ることは出来ますがファイルタイプをチェックしているようなのでエラーになってしまうようです。

話が長くなってしまうので先にまとめを書く

pixivFANBOX にアップロード可能な形式で汎用性が高い形式は「ZIP」だと思います。ZIP には分割する機能があるのでこれを用いるのが簡単なのですが、分割された ZIP ファイルは最初のファイル以外はヘッダの違いからか pixiv 側で ZIP ファイルだと認められないことがあります(分割方法によります)。

従って、pixivFANBOX に分割したファイルをアップロードする場合は下記のような工程になると思われます。

  1. フォルダを1つの ZIP ファイルにする(ファイルの場合は不要)
  2. 1 ファイル 300 MB 以内で分割する
  3. 各ファイルを ZIP ファイルにする

Windows はユーティリティが豊富なので BOOTH の回答にある通り 7-Zip 等で対応出来ると思います(7-Zip で分割 ZIP 作っても2つ目以降はエラーになる気がしますが)。

後述しますが LinuxmacOS でもコマンドを扱えれば別途アプリケーションを用意せずとも分割や結合を行うことは可能です。しかし、特に macOS をお使いの方はコマンドに馴染みが無いと思いますので毎回コマンドを叩くのは大変だと思います。macOS には Automator というアプリケーションがあるので分割・結合用の自作アプリケーションかサービスを作るのが良いと思います。例えば下記の構成で 1 ファイル 300 MB 以内のファイルを生成するアプリケーションを作ることが出来ます。

「よくわからない!」と言う方は「分割ちゃん.app」と「結合ちゃん.app」を作って pixivFANBOX で頒布してますのでそちらをご自由にお使いください。

www.pixiv.net

分割アプリケーションサンプル

f:id:mattintosh4:20191124034139p:plain
Automator
(画像内のスクリプトは将来変更される可能性があります)

シェルは「/bin/bash」または「/bin/ksh」、入力の引き渡し方法は「引数として」に設定します。limit 変数の値を増やしてもらえば BOOTH 用にも使えるかもしれません(BOOTH にアップする 1 GB を超えるファイルが無いので未検証)。

set -e
set -u
PATH=/usr/bin:/bin

limit=$((10**6*300-1024))

split_and_zip(){
    split -b ${limit} -a 1 "${1}" "${1}".
    for p in "${1}".?
    do
        zip -q -0 -m -T "${p}".zip "${p}"
    done
}

for f
do
    basename=$(basename "${f}")
    dirname=$(dirname "${f}")
    type=$(stat -f %T "${f}")

    cd "${dirname}"

    case ${type} in
    /)
        zip -q -r -y "${basename}".zip "${basename}"
        split_and_zip "${basename}".zip
    ;;
    '')
        split_and_zip "${basename}"
    ;;
    esac
done

結合アプリケーションサンプル

f:id:mattintosh4:20191124034202p:plain
Automator
(画像内のスクリプトは変更されていることがあります)

シェルは「/bin/bash」または「/bin/ksh」、入力の引き渡し方法は「引数として」に設定します。

set -e
set -u
PATH=/usr/bin:/bin

cd "$(dirname "${1}")"
for f
do
    unzip -q "${f}"
done
cat "${@%.*}" >"${1%.?.*}"

分割ちゃん.appと結合ちゃん.app

分割ちゃん.app

サイズの大きなファイルを 300 MB 毎の ZIP ファイルに分割するアプリケーションです。26 分割まで対応しているので約 7.8 GB までのファイルであれば pixivFANBOX にアップロード可能な形式で 300 MB 毎に分割された ZIP ファイルを作成することが出来ます。

実行するとファイル選択ダイアログが開くので分割したいファイルやフォルダを選択します。暫くすると選択したファイルと同じフォルダに分割された ZIP ファイルが作成されます。

f:id:mattintosh4:20191124002019p:plain
分割ちゃん.app

分割が終わると通知で教えてくれます。

f:id:mattintosh4:20191124003157p:plain
分割ちゃん

pixivFANBOX や BOOTH には .a.zip.b.zip という名前のファイルをアップロードします。

f:id:mattintosh4:20191124003237p:plain
分割ちゃん

www.pixiv.net

結合ちゃん.app

分割ちゃん.app で分割された ZIP ファイルを結合して 1 つの ZIP ファイルにするアプリケーションです。

実行するとファイル選択ダイアログが開くので結合したいファイルを選択します。暫くすると選択したファイルと同じフォルダに結合された ZIP ファイルが作成されます。アプリケーション内でファイルの並び替えを行うので選択する順番は自由で構いません。

f:id:mattintosh4:20191124004823p:plain
結合ちゃん

結合が終わると通知で教えてくれます。

f:id:mattintosh4:20191124004839p:plain
結合ちゃん

結合されたファイルは Finder やアーカイブユーティリティから解凍することが出来ます。

f:id:mattintosh4:20191124004918p:plain
結合ちゃん

www.pixiv.net

コマンドでなんとかする

zip コマンドによる分割を試す

zip コマンドでは -s サイズ オプションで分割 ZIP を作成することが出来ます。

300 MB 毎に分割された ZIP を作成する例

分割サイズの指定には byte 指定出来ないので k を使って 300000000 / 1024 の結果(292968k)をオプションに渡します。

Terminal

zip -r -y -s $((300*10**6/1024))k EasyWine.app.zip EasyWine.app

Shell-Session

$ ls
total 639664
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  299999232 11 24 03:55 EasyWine64.app.z01
-rw-r--r--  1 501  0   24163798 11 24 03:55 EasyWine64.app.zip
$ file EasyWine64.app.z*
EasyWine64.app.z01: Zip multi-volume archive data, at least PKZIP v2.50 to extract
EasyWine64.app.zip: Zip archive data

しかし、pixivFANBOX ではアップロード可能なファイルの拡張子に制限があるため .z01 のようなファイルは選択することが出来ません。

f:id:mattintosh4:20191124040624p:plain

.z01 のファイルに .zip を追加して .z01.zip のようにリネームすればアップロードすることは可能でしたが、.z01.z01.zip にリネームしてしまっているので解凍の際にファイルを見失ってしまいます。そのため、ユーザには .z01.zip のようなファイルだけ .z01 にリネームしてもらい、ターミナルで解凍してもらう…という流れになります。

アーカイブユーティリティは分割された ZIP を解凍出来ないようです。

f:id:mattintosh4:20191124041348p:plain

解凍は「分割されたファイルを分割サイズ 0(ゼロ)にする」という感じのちょっとわかりにくいコマンドになります。.z01 などのファイルを指定する必要はありません。--out ファイル名 のファイル名は任意です。

Terminal

zip -s 0 EasyWine64.app.zip --out unsplit.zip

Shell-Session

$ ls
total 1288016
-rw-r--r--  1 501  0  299999232 11 24 03:55 EasyWine64.app.z01
-rw-r--r--  1 501  0   24163798 11 24 03:55 EasyWine64.app.zip
-rw-r--r--  1 501  0  324163026 11 24 04:10 unsplit.zip

結合されたファイルを解凍します。

Terminal

unzip unsplit.zip

アーカイブユーティリティが .z01 などのファイルを見つけてくれるならいいんですがそれも無理なので微妙ですね。

zipsplit コマンドによる分割を試す

zipsplit コマンドに ZIP ファイルを渡すことで分割された ZIP ファイルを作成することもできます。このコマンドでは ZIP ファイルの中身を上手くやりくりして最大サイズに収まるように分けて個別の ZIP ファイルとして生成してくれるようです。この仕組の都合上、圧縮ファイル内に最大サイズを超えるファイルが存在する場合は ZIP を分割することは出来ません。また、2 GB を超えるファイルをサポートしていません。

分割元の ZIP ファイルを作成しておきます。

$ ls
total 657024
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  324163026 11 24 04:24 EasyWine64.app.zip

最大サイズを 300 MB に設定して ZIP ファイルを分割します。

Terminal

zipsplit -n $((300*10**6)) EasyWine64.app.zip

分割された ZIP ファイルは名前が変わってしまうようです。

Shell-Session

$ ls
total 1307296
-rw-r--r--  1 501  0  296834141 11 24 04:25 EasyWin1.zip
-rw-r--r--  1 501  0   27328907 11 24 04:25 EasyWin2.zip
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  324163026 11 24 04:24 EasyWine64.app.zip

zipsplit コマンドを使った場合の特徴としてそれぞれの ZIP ファイルが ZIP ファイルとして独立している点です。「複数のフォルダに分けて圧縮したので解凍するときにひとつに集約すれば元通りになる」という感じ。「結合」と言うよりは「統合」かもしれません。

Terminal

unzip EasyWin1.zip
unzip EasyWin2.zip

split コマンドによる分割を試す

テキストファイルを指定行数で分割したりするのに使う split コマンドにはバイトサイズに対応した分割モードがあるのでこちらを使います。

ひとまず圧縮済みの ZIP ファイルを最大サイズ 300 MB で分割してみます。

Terminal

split -b $((300*10**6)) -a 1 EasyWine64.app.zip EasyWine64.app.zip.

300 MB ピッタリで分割することが出来ました。

Shell-Session

$ ls
total 1312480
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  324163026 11 24 04:24 EasyWine64.app.zip
-rw-r--r--  1 501  0  300000000 11 24 04:36 EasyWine64.app.zip.a
-rw-r--r--  1 501  0   24163026 11 24 04:36 EasyWine64.app.zip.b

しかしこれだと ZIP のヘッダが入ると 300 MB をわずかに超えてしまうので 1 KB くらい減らして作り直します。

Shell-Session

$ split -b $((300*10**6-1024)) -a 1 EasyWine64.app.zip EasyWine64.app.zip.
$ ls
total 1297848
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  324163026 11 24 04:24 EasyWine64.app.zip
-rw-r--r--  1 501  0  299998976 11 24 04:41 EasyWine64.app.zip.a
-rw-r--r--  1 501  0   24164050 11 24 04:41 EasyWine64.app.zip.b

このファイルに .zip という拡張子を追加すればアップロード可能ファイルとして選択することは可能ですが、ZIP ファイルを単純に分割しただけなので最初のファイル以外はエラーが発生してしまいます。この状態になるとこの投稿は公開することが出来なくなり、最初からやり直しになってしまいます。

f:id:mattintosh4:20191123215427p:plain
pixivFANBOX

面倒ですがそれぞれを再度 ZIP にします。既に圧縮をしているためここでは -0 を指定して無圧縮 ZIP にすることで圧縮・解凍にかかるコストを減らします。

Terminal

zip -0 EasyWine64.app.zip.a.zip EasyWine64.app.zip.a
zip -0 EasyWine64.app.zip.b.zip EasyWine64.app.zip.b

Shell-Session

total 1940376
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  324163026 11 24 04:24 EasyWine64.app.zip
-rw-r--r--  1 501  0  299998976 11 24 04:54 EasyWine64.app.zip.a
-rw-r--r--  1 501  0  299999166 11 24 04:55 EasyWine64.app.zip.a.zip
-rw-r--r--  1 501  0   24164050 11 24 04:54 EasyWine64.app.zip.b
-rw-r--r--  1 501  0   24164240 11 24 04:55 EasyWine64.app.zip.b.zip

出来上がった ZIP ファイルは正常に pixivFANBOX にアップロード出来ます。

f:id:mattintosh4:20191123220821p:plain
pixivFANBOX

解凍はそれぞれの ZIP ファイルを1段階解凍した後に結合して出来上がったファイルを再度解凍します。

最初に分割されたファイルを解凍します。この操作は Finder でも行うことが出来ます。

unzip EasyWine64.app.zip.a.zip
unzip EasyWine64.app.zip.b.zip

次に、cat コマンドでファイルを結合します。ファイルが複数ある場合は *? などのワイルドカードを使用した方が楽です。また、結合の順番を間違えることもありません。

cat EasyWine64.app.zip.? >EasyWine64.app.zip

最後に出来上がった ZIP ファイルを解凍します。この操作は Finder で行うことが出来ます。

unzip EasyWine64.app.zip

7z コマンドによる分割を試す

7z コマンドは Homebrew や MacPortsp7zip をインストールすることで使えるようになります。

分割サイズを 300 MB からちょっと削った値にして分割圧縮します。こちらも拡張子制限によりアップロードは出来ませんし、.zip を追加してもエラーになります。

Shell-Session

$ 7z a -v$((300*10**6-1024)) EasyWine.app.zip EasyWine.app
$ ls
total 626704
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  299998976 11 24 05:08 EasyWine64.app.zip.001
-rw-r--r--  1 501  0   14705401 11 24 05:08 EasyWine64.app.zip.002

圧縮レベル 0 で圧縮します。

Terminal

7z a -mx=0 EasyWine64.app.zip.001.zip EasyWine64.app.zip.001
7z a -mx=0 EasyWine64.app.zip.002.zip EasyWine64.app.zip.002

Shell-Session

$ ls
total 1271880
drwxr-xr-x  3 501  0         96 11 22 20:21 EasyWine64.app
-rw-r--r--  1 501  0  299998976 11 24 05:08 EasyWine64.app.zip.001
-rw-r--r--  1 501  0  299999154 11 24 05:11 EasyWine64.app.zip.001.zip
-rw-r--r--  1 501  0   14705401 11 24 05:08 EasyWine64.app.zip.002
-rw-r--r--  1 501  0   14705579 11 24 05:11 EasyWine64.app.zip.002.zip

これで pixivFANBOX や BOOTH にアップロード出来るようになりました。

解凍は無圧縮 ZIP 分を解凍したら 001 のファイルをそのまま渡せば 7z コマンドがよしなにやってくれます。

Terminal

7z x EasyWine64.app.zip.001.zip
7z x EasyWine64.app.zip.002.zip
7z x EasyWine64.app.zip.001

dd コマンドによる分割を試す

bscountskip の組み合わせで…(めんどくさい)