Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

folio-importer

概要

import フォルダに置かれたコンテンツを検出し、comic book reader の folio が扱う CBZ 形式に変換して library フォルダへ格納する Go 製 CLI ツール。


環境変数

変数名 デフォルト値 説明
FOLIO_IMPORT_DIR ./import 入力フォルダ
FOLIO_LIBRARY_DIR ./library 出力フォルダ(CBZ の保存先)
FOLIO_TMP_DIR ./tmp 処理済み元データの退避先

起動時に librarytmp が存在しない場合は自動作成する。import が存在しない場合は致命的エラーで終了する。


対象アイテムの検出

import フォルダの 直下 だけをスキャンする(再帰スキャンは行わない)。

検出対象 条件
アーカイブ 拡張子が .zip または .cbz(大文字小文字不問)
フォルダ 直下に子フォルダを持たないディレクトリ
スキップ 上記以外のファイル、または子フォルダを含むディレクトリ(ログに [skip] を出力)

検出したアイテムはすべて goroutine で並列処理 される。


アーカイブ処理(zip / cbz)

判定フロー

アーカイブを開く
  └─ repack を試みる
       ├─ 実際に変換が発生した  →  新 CBZ を library に書き出し、元ファイルを tmp へ移動
       └─ 変換なし             →  fast-move(元ファイルを library へ直接移動)

fast-move(変換不要パス)

変換処理(フラット化・画像リサイズ・画像圧縮)が 1 件も発生しなかった 場合に適用される。

処理:

  1. 元ファイルを library移動os.Rename、クロスデバイスの場合は copy + remove)
  2. 拡張子を .cbz にリネーム(.zip の場合)
  3. tmp への移動は行わない

repack(変換あり)

フラット化またはいずれかの画像変換が実際に発生した場合に適用される。

処理:

  1. アーカイブ内の全エントリをフラット化してメモリ上に展開
  2. 画像エントリは 画像処理 を適用
  3. 新しい CBZ を library に書き出す
  4. 元の zip/cbz を tmp に移動する

フラット化ルール

アーカイブ内の階層構造を撤廃し、全ファイルをルートに配置する。ファイル名の衝突を避けるため、パス区切り /-- に置換してファイル名のプレフィックスとする。

元のパス フラット後のファイル名
image.jpg image.jpg
chapter1/image.jpg chapter1--image.jpg
chapter1/sub/image.jpg chapter1--sub--image.jpg

ディレクトリエントリ(中身のないフォルダ)は出力 CBZ に含めない。


フォルダ処理

対象フォルダの条件

import 直下のフォルダのうち、直下に子フォルダを含まないもののみを処理対象とする。子フォルダが 1 つでも存在する場合はエラーログを出力してスキップする。

import/
  book1/          ← OK(直下はファイルのみ)
    page001.jpg
    page002.jpg
    readme.txt
  book2/          ← NG(子フォルダを含む)→ [skip]
    chapter1/
      page001.jpg

処理フロー

  1. フォルダ直下の全ファイルを収集する(再帰スキャンなし)
  2. 画像ファイルは 画像処理 を適用
  3. 画像以外のファイルはそのまま CBZ に梱包する
  4. フォルダ名 + .cbzlibrary に書き出す
  5. 元のフォルダを tmp に移動する(os.Rename

出力例

import/mybook/
  page001.jpg
  page002.jpg
  readme.txt

→ library/mybook.cbz(内部構造)
  page001.jpg   ← 必要に応じてリサイズ・圧縮済み
  page002.jpg
  readme.txt    ← そのまま梱包

画像処理

image.go に実装。zip・フォルダの両処理から呼び出される再利用可能なモジュール。

対応フォーマット

JPEG(.jpg, .jpeg)および PNG(.png)。それ以外のファイルは処理せずそのまま CBZ に格納する。

処理の判定

画像 1 枚ごとに以下を確認し、いずれも不要なら 元のバイト列をそのまま使用する(再エンコードなし)。

条件 閾値
リサイズ要否 横幅 > 1920 px
圧縮要否 ファイルサイズ ≥ 300 KB

リサイズ

  • 横幅を 1920 px に縮小し、アスペクト比を保って高さを算出(整数除算)
  • アルゴリズム:バイリニア補間(標準ライブラリのみ使用、外部依存なし)

圧縮:JPEG

  • 圧縮不要(300 KB 未満)かつリサイズ後:quality 90 で再エンコード
  • 圧縮必要(300 KB 以上):quality 1〜95 の範囲で バイナリサーチ を行い、出力が 200 KB 以下になる最高品質を選択する
  • quality 1 でも 200 KB を超える場合:quality 1 の結果をそのまま使用する

圧縮:PNG

  1. png.BestCompression で再エンコード
  2. 結果が 300 KB 未満 → そのまま使用
  3. 結果が 300 KB 以上 → JPEG に変換してファイル名の拡張子も .jpg に変更し、JPEG の圧縮ロジックを適用する

エラーハンドリング

画像デコードや再エンコードに失敗した場合、WARNログを出力し 元のバイト列をそのまま CBZ に格納する(処理は中断しない)。


library への保存と名前衝突回避

CBZ の保存先パスを決定する際、すでに同名ファイルが存在する場合はタイムスタンプをサフィックスに付けて上書きを回避する。

通常:  library/mybook.cbz
衝突:  library/mybook-20260411-153000.cbz

タイムスタンプのフォーマット:YYYYMMDD-HHMMSS

並列処理中の衝突チェックはミューテックスで保護されており、異なる goroutine が同時に同名ファイルを作成することはない。


tmp への退避

ケース tmp に移動されるもの
アーカイブ(変換あり) 元の zip/cbz ファイル
アーカイブ(変換なし・fast-move) 移動なし(library に直接移動済み)
フォルダ 元のフォルダごと

移動は os.Rename で行う。クロスデバイスの場合は copy + remove にフォールバックする。


ログ出力

タイミング フォーマット
処理開始 [N/M] Processing: <name> [2/4] Processing: mybook
圧縮発生時 compressed <name>: X KB -> Y KB compressed p001.jpg: 4398 KB -> 188 KB
処理完了 [N/M] Done (P%): <name> [2/4] Done (50%): mybook
エラー [N/M] ERROR <name>: <detail> [3/4] ERROR bad.zip: open zip: ...
画像処理失敗 WARN: image processing failed for <name>: <detail>
スキップ [skip] <name> [skip] readme.txt
最終結果 Finished. N succeeded, M failed (total T).

パーセント表示は完了数 / 全アイテム数で算出する。並列実行のため表示順序は不定。


ファイル構成

main.go   — 起動・スキャン・アーカイブ処理・フォルダ処理・ファイル操作
image.go  — 画像処理(processImage, encodeJPEG, encodePNG, resizeBilinear)

image.go は将来の PDF 対応など他の入力ソースからも利用できるよう、zip・フォルダ処理への依存を持たない独立した実装になっている。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages