Claude Code で急に permission denied: claude-XXXX-cwd 的なエラーが出るようになった時の応急処置

Claude Code を使っていたら、急に毎回こんなエラーが出るようになった(2.1.1の時に気づいた)。

zsh:22: permission denied: /var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/claude-f341-cwd

コマンド自体は実行できるものの、毎回標準エラー出力が汚されて鬱陶しい。画面も赤くなるし、何より本当にエラーの場合に区別がつきにくい。 ので直したい。

推定される原因

Claude Code が /var/folders 配下へ一時ファイル claude-XXXX-cwd を作成しようとするが、何らかの理由(macOS アップデートや Claude Code のバージョンアップ)で書き込み権限が不足している。

GitHub Issue #8896 でも報告されてぽいけど、根本的な修正はまだリリースされていない雰囲気。

暫定対応

とりあえず一時ファイルが作れればいいはずなので、それ用の設定を追加する。

TMPDIR 環境変数を明示的に設定することで解決する。

bash# 一時ディレクトリを作成
mkdir -p ~/tmp
# シェル設定に追加(zsh の場合)
echo 'export TMPDIR="$HOME/tmp"' >> ~/.zshrc
source ~/.zshrc

これで Claude Code は /var/folders の代わりに ~/tmp を使うようになり、エラーが出なくなる。

細かい点として、~/tmp は自動クリーンアップされないので、たまに手動で掃除すると良い。

bash# 7日以上前のファイルを削除
find ~/tmp -type f -mtime +7 -delete

そのうち直るとは思うけど、特に致命的なもんだがあるわけではないのでTMPDIRは指定したままでも大丈夫。

⌘英かな Apple Silicon版 で macOS Tahoeに対応しました

tl;dr

  • ⌘英かな Apple Silicon版をv2.4.0にアップデートしました。macOS Tahoe (26) で動作するようになりました。
  • あと、Apple公証に対応したので、初回起動時に簡単なダイアログで開くことができるようになりました。

eikana.dominion525.com

背景

先日リリースしたv2.3.1ですが、macOS Tahoe (26) で動かないぽいことがわかりました(Tahoeは常用してないので、オリジナル版に対するポストを見た感じです)。

たまたまTahoe環境が準備できたので確認したら、確かに動かなかった。 正確にはアプリは起動し、キーリマップは機能するものの、メニューが反応しない、アプリが応答不能になるなどの問題が確認できました。


v2.4.0の変更点

  • macOS Tahoe (26) 対応
    • Input Monitoring権限のチェックと要求を追加
    • メインRunLoopの使用方法を修正
  • Apple公証(Notarization)対応
    • インストール時の「開発元を検証できません」警告が出なくなった
      • ダウンロード後、普通に「開く」をクリックするだけでOK
  • 初回起動時の権限設定
    • 入力監視 → アクセシビリティの順で許可が必要です

ダウンロード

github.com

感想

  • このためにApple Developer IDを登録した。課金分頑張ろう。
  • 全体的に雰囲気で修正した。
  • Claude code さんありがとう。

「⌘英かな」 の Apple Silicon 対応版をフォークして公開しました

tl;dr

https://eikana.dominion525.com/eikana.dominion525.com

背景

主にMacを使ってるんですが、USキーボードユーザです。

で、基本的には全然快適なんですが、日本語入力の切り替えだけがトグルになってて面倒なわけです。 JISキーボードの「英数」「かな」で切り替えられるのはすごく便利だと思っています。

で、それを解決してくれるのが「⌘英かな」です。

左Commandキー単押しで英数、右Commandキー単押しでかなに切り替えられるようになります。 近年は高機能キーリマッパーであるKarabiner-Elements が使われることも多いかと思うんですが、ちょっと高機能すぎるので、「⌘英かな」を愛用していました。

セットアップしたら真っ先に入れるくらいなんですが、オリジナル版は 2017年6月の2.2.3で更新が止まってしまっています。  で、Rosseta2経由で動作はするので今のところ実用はできるんですが、Apple Silicon(M1-M5) にはネイティブ対応していません(それでも特に支障なく動くのすごいなって思いますが)。

で、MITライセンスだったのでフォークしてApple Silicon版をビルドしました。

2021年にApple Silicon対応してくれた方がいたので、ほとんどそのまま動かせそうでした、ありがたい…。

調べてみるとJigの創業者の方っぽい。

mac、USキーボードでの入力を快適にする「英かな」を Swift 5 / Apple M1対応

変更点

オリジナル版からの主な変更点は以下の通りです:

  • 🔥 Apple Silicon (arm64) ネイティブビルド
    • ファイルサイズが半減して、Rosseta2が不要に。
  • 最小動作要件を macOS 12.0 (Monterey) 以降に変更
  • Bundle ID を変更(io.github.dominion525.cmd-eikana
  • 更新チェック機能を GitHub Releases API に対応

使い方

入力 出力
左Command(単押し) 英数
右Command(単押し) かな
Command + 他のキー 通常のショートカット

Command+C とか Command+V は普通に使えます。単押しのときだけ入力切り替えが発動する仕組みです。

インストール方法

GitHub Releases からZIPをダウンロードして展開するだけです。

ただし未署名アプリなので、初回起動時に macOS の Gatekeeper にブロックされます。詳しい手順は配布サイトにスクリーンショット付きで書いたので参照してください。

オリジナル版からの移行

オリジナル版を使っていた人は、Bundle ID が変わっているのでアクセシビリティの設定が競合することがあります。システム設定の「プライバシーとセキュリティ」→「アクセシビリティ」で古いエントリを削除してから、新しい方を許可する必要があります。

感想など

  • 作者のiMasanariさん、素晴らしいソフトウェアをありがとうございます。
  • 本変更の大部分はClaude Codeに頑張ってもらいました。ありがとうClaude Code。
    • CLIで進めてくれるのでXCodeをほぼ使わなくても済んでよかった。
    • 初めてMacのネイティブアプリビルドしたかもしれない。
  • キーボードユーティリティなのでキャプチャとが動画が実質出せない。ので文字ばっかになっちゃった。

https://eikana.dominion525.com/eikana.dominion525.com

ei-kana.appspot.com

github.com

karabiner-elements.pqrs.org

カバディ専用のタイマーアプリの不具合を修正しました

先日公開したカバティタイマーなのですが、今日練習試合で利用するとわりと不具合が判明したので諸々修正しました。 あとついでにいくつかの調整を行いました。ご迷惑おかけしました。

dominion525.hatenablog.jp

v0.1.1 アップデート内容

重要な不具合の修正

  • カウントダウンが適切に行われない問題

タイマーのカウントダウンが正確に動作しないケースがありました。 内部的にはサーバとの同期を諦め端末側での高精度な相対時間を用いるように変更し、おそらく問題がなくなったと思います。 (端末間の誤差が発生する可能性はあります)

  • QRコードが再表示されない問題

一度閉じたQRコードモーダルを再度開くと、QRコードが表示されない問題がありました。 開き直してもQRコードが正しく表示されるようになりました。

仕様の変更

スコアリセットボタンの削除とレイドカウントの表示

  • Do or Die の仕様変更

カバディのルール上、Do or Die状態以外がプレイヤーに認知されてはいけないそうなので、インジケータ表示を変更しました。 レイド回数は操作画面に表示されています。

  • スコアリセットボタンを削除

誤って押してしまいやすかったスコアリセットボタンをシンプルモードから削除しました。スコアをリセットしたい場合は、通常モードに切り替えてご利用ください。

その他の改善

  • ボタン配置の改善

モバイル端末の非シンプルモードで全体コントロールを画面最上部に移動しました。

リセットとコートチェンジを上部に

  • モバイル端末で初めて開いた時はシンプルモード

スマートフォンで初めてタイマーを開いた時、シンプルモードの画面が表示されるようになりました。

  • デスクトップ版のボタンサイズ調整

+1/-1などの操作ボタンをよりコンパクトなサイズに調整ました。

利用はこちらから

kabaddi.dominion525.com

リンク

github.com

kindle の蔵書一覧を取得するツール kindle-tilte-exporter を作りました(Mac専用)

tl;dr

  • Kindle for Macの蔵書情報をCSV/JSONでエクスポートするCLIツールを作りました
  • npmパッケージとして公開、MITライセンス
  • 下記でインストール不要で使えます。
npx kindle-title-exporter > books.csv 
  • メタデータのみ取得、コンテンツ本体には関与しません。
  • Mac専用です。

背景

Kindleで本を買い続けていると、シリーズ本の購入状況を把握するのが難しくなってきます。Kindleアプリで一覧は見られますが、スクロールして目視確認するしかありません。もちろん集計やソート、フィルタリングもできません。

Amazonの「コンテンツと端末の管理」ページにも一覧はありますが、ページネーションで少しずつしか見られず、エクスポート機能もありません。

で今、主に漫画なんですが、現在ざっくり3500冊、600シリーズくらいあるんですよ。なお、継続購入してるシリーズが100件くらい。結構つらい。

そういえば Kidle for Macを使っていればローカルに蔵書情報が保存されているので、それを読めばいいじゃない、と言うことで、CSV/JSON形式で出力するツールを作りました。

準備

Kindle

Kindle

  • AMZN Mobile LLC
  • ブック
  • 無料
apps.apple.com

Kindle for Mac をセットアップして、蔵書リストを同期しておいて下さい(普通に本が読めるようにするだけ)。

使い方

インストール不要で使えます:

  npx kindle-title-exporter > books.csv

CSV形式で標準出力に出力されるので、リダイレクトでファイルに保存します。

JSON形式での出力も可能です:

  npx kindle-title-exporter -f json > books.json

出力される項目は12個です:

フィールド名 説明
bookId 書籍ID(例: A:B009DEMC8W-0)
asin 純粋なASIN(例: B009DEMC8W)
title タイトル
author 著者名
seriesName シリーズ名
seriesNumber シリーズ番号
publisher 出版社名
publicationDate 出版日(ISO 8601形式)
purchaseDate 購入日時(ISO 8601形式)
contentTags コンテンツタグ(配列)
language 言語コード(例: ja, en)
sortTitle ソート用タイトル(カタカナ表記など)

例えば、Googleスプレッドシートにインポートすれば、フィルタリングやソートが自由にできます。 シリーズ名でフィルタリングすることで、購入していない巻も分かりやすくなります。 購入日でソートすると、購入頻度の傾向も見えたりしますね。

いろいろ二次利用が捗るかと思います。

出力例

"bookId","asin","title","author","seriesName","seriesNumber","publisher","publicationDate","purchaseDate","contentTags","language","sortTitle"
"A:B0FHGY4T96-0","B0FHGY4T96","フラジャイル(30) (アフタヌーンコミックス)","恵三朗,草水敏","フラジャイル 病理医岸京一郎の所見","30","講談社","2025-07-23T00:00:00.000Z","2025-08-07T06:23:51+0000","MANGA","Unknown","フラジャイル030 (アフタヌーンコミックス)"
"A:B00AQY85PM-0","B00AQY85PM","フランケン・ふらん 1 (チャンピオンREDコミックス)","木々津克久","フランケン・ふらん","1","秋田書店","2007-11-01T00:00:00.000Z","2016-10-12T19:02:15+0000","MANGA","Unknown","フランケンフラン001  フランケンフラン (チャンピオンレッドコミックス)"
"A:B00AQY85U2-0","B00AQY85U2","フランケン・ふらん 2 (チャンピオンREDコミックス)","木々津克久","フランケン・ふらん","2","秋田書店","2008-07-01T00:00:00.000Z","2016-10-12T19:02:14+0000","MANGA","Unknown","フランケンフラン002  フランケンフラン (チャンピオンレッドコミックス)"
"A:B00AQY85UW-0","B00AQY85UW","フランケン・ふらん 3 (チャンピオンREDコミックス)","木々津克久","フランケン・ふらん","3","秋田書店","2009-02-01T00:00:00.000Z","2016-10-12T19:02:19+0000","MANGA","Unknown","フランケンフラン003  フランケンフラン (チャンピオンレッドコミックス)"
[
  {
    "bookId": "A:B00J919VBU-0",
    "asin": "B00J919VBU",
    "title": "りんたとさじ",
    "author": "オガツカヅオ",
    "seriesName": null,
    "seriesNumber": null,
    "publisher": "朝日新聞出版",
    "publicationDate": "2014-03-31T00:00:00.000Z",
    "purchaseDate": "2016-11-21T11:03:53+0000",
    "contentTags": [
      "MANGA",
      "COMICS"
    ],
    "language": "Unknown",
    "sortTitle": "リンタトサジ"
  },
  {
    "bookId": "A:B09C1WWXQF-0",
    "asin": "B09C1WWXQF",
    "title": "るなしい(1) (小説現代コミックス)",
    "author": "意志強ナツ子",
    "seriesName": "るなしい",
    "seriesNumber": "1",
    "publisher": "講談社",
    "publicationDate": "2021-08-23T00:00:00.000Z",
    "purchaseDate": "2024-06-03T02:28:53+0000",
    "contentTags": "MANGA",
    "language": "Unknown",
    "sortTitle": "ルナシイ001 (ショウセツゲンダイコミックス)"
  }
]

あとはjqなりで適宜加工やフィルタリングしましょう。

技術的な実装

データソース

Kindle for Macはデータをローカルに保存していますので、これを読むだけです。

~/Library/Containers/com.amazon.Lassen/Data/Library/Protected/BookData.sqlite

SQLiteファイルなので直接読めます。読むだけなら多分壊れないと思います。Kindle for Mac と同時起動はしないほうがいいかもしれません。

公式のドキュメントはないため、テーブル構造やフィールドの意味は独自調査です。 データベース構造の詳細は別記事にまとめました。 記事は細かく分割されていますが、読むべき必要があるのは一部のみなので大丈夫でしょう。

dominion525.hatenablog.jp

実装方針

書籍のメタデータ(タイトル、著者、購入日など)のみを取得します。本文やコンテンツには触りません。DRM回避でもありません。単なる蔵書管理ツールです。

ふつうの技術をふつうに使うことを心がけたので、特別な工夫はしていません。だってSQLiteをダンプするだけなんだし。

小さめのモジュールに分割して、各機能を独立してテストしやすくしました:

src/
├── db/reader.ts          # SQLite読み込み
├── converters/plist.ts   # plistデコード
├── converters/mapper.ts  # フィールドマッピング
├── formatters/csv.ts     # CSV出力(RFC 4180準拠)
└── formatters/json.ts    # JSON出力

テストカバレッジは今のところ90%くらいです。

指標 カバレッジ
全体 89.51%
Statements 89.51%
Branches 89.02%
Functions 93.75%
Lines 89.51%

なお、ストリーム処理とかもしてなくて、単にSQLiteから全件取得してガッと出力するだけです。せいぜい数千-数万件程度のテキストデータなのでまあいいかと。3500件のCSV出力でも秒だったし。

実装支援

本ツールは大部分Claude Codeの支援によって作成されています。 2.0(sonet4.5)以降、あんまりトークン使わない印象があるので、20Xじゃなくでもいいかもって気持ちにはなってきた。

npmパッケージ

npmに公開しました。

https://www.npmjs.com/package/kindle-title-exporter

グローバルインストールも可能ですが、しなくていいと思います。

なお、Github レポジトリは下記です。

github.com

免責

本ツールは非公式であり、AmazonまたはKindleとは一切関係がなく、承認や推奨を受けたものではありません。

「Kindle」はAmazon.com, Inc.の登録商標です。本ソフトウェアは、機能説明のためにのみ(Kindle for Macのデータベースファイルを読み取る)「Kindle」という名称を使用しています(nominative fair use)。本ツールは、デジタル著作権管理(DRM)やコピープロテクション機構を改変、回避、妨害するものではありません。

リンク

Kindle の蔵書一覧を取得する(5) / シリーズ情報の取り扱い

ようやくほぼ最後です。 シリーズの取り扱いについてです。基本的には便利なんですが、けっこうシリーズが設定されていないシリーズものがありそこそこ困ります。AIとか使いながらヒューリスティックに対応しないといけない雰囲気があるのですが、まあ、それはそれで別のお話。ひとまず、標準で持っているシリーズのお話です。

とはいえ、普通にLEFT JOINしようなってだけです。

シリーズ情報の取得方法

書籍のシリーズ情報を取得する方法を説明します。シリーズ情報はZGROUPZGROUPITEMZBOOKの3つのテーブルを使用して管理されています。

関連テーブルの構造

ZGROUP(シリーズマスタ)

シリーズの基本情報を格納するマスタテーブルです。

フィールド 説明
Z_PK INTEGER プライマリキー 123
ZGROUPID VARCHAR グループID(文字列) "B01FU3MY2S"
ZDISPLAYNAME VARCHAR シリーズ名🔥 "ワンパンマン"
ZDISPLAYAUTHOR VARCHAR シリーズ著者 "ONE/村田雄介"
ZSERIESTYPE VARCHAR シリーズタイプ "series"
ZRAWPUBLICATIONDATE INTEGER 出版日 1234567890
ZLASTACCESSTIME INTEGER 最終アクセス時刻 1234567890
ZSERIESCOVERIMAGE INTEGER 表紙画像への外部キー 456

重要フィールド: - ZDISPLAYNAME: ユーザーに表示するシリーズ名

ZGROUPITEM(書籍-シリーズ中間テーブル)

書籍とシリーズを紐付ける中間テーブルです。

フィールド 説明
Z_PK INTEGER プライマリキー 789
ZBOOK INTEGER 書籍への外部キー🔥 2940
ZPARENTCONTAINER INTEGER シリーズへの外部キー 123
ZPOSITION INTEGER シリーズ内位置(0始まり)🔥 0, 14, 33
ZPOSITIONLABEL VARCHAR 位置ラベル🔥 "1", "15", "34"
ZITEMID VARCHAR アイテムID "B01FU3MY2S"
ZRAWITEMCOLLECTIONTYPE VARCHAR アイテムコレクションタイプ "series"

重要フィールド: - ZBOOK: ZBOOK.Z_PKへの外部キー - ZPARENTCONTAINER: ZGROUP.Z_PKへの外部キー - ZPOSITION: シリーズ内の順序(0始まり) - ZPOSITIONLABEL: ユーザーに表示する位置("1"始まり)

ZBOOK(書籍テーブル)

書籍情報を格納するメインテーブル。シリーズ関連では以下のフィールドを持ちます。

フィールド 説明
Z_PK INTEGER プライマリキー 2940
ZGROUPID VARCHAR グループID "B01FU3MY2S"
ZDISPLAYTITLE VARCHAR タイトル "ワンパンマン 1"

注意: ZGROUPIDフィールドはありますが、実際のシリーズ情報取得にはZGROUPITEMを経由する必要があります。

リレーション構造

テーブル間の関係

ZBOOK (Z_PK)
  ↓
  ← ZGROUPITEM.ZBOOK (外部キー)
  ↓
ZGROUPITEM (ZPOSITION, ZPOSITIONLABEL)
  ↓
ZGROUPITEM.ZPARENTCONTAINER → ZGROUP.Z_PK (外部キー)
  ↓
ZGROUP (ZDISPLAYNAME)

関係の特徴

  1. 1対多の関係:

    • 1つのシリーズ(ZGROUP)は複数の書籍(ZBOOK)を持つ
    • 1つの書籍は1つのシリーズにのみ属する(または属さない)
  2. 中間テーブルの役割:

    • ZGROUPITEMが書籍とシリーズを紐付け
    • シリーズ内の位置情報も保持
  3. NULL値の意味:

    • シリーズ情報が未設定の書籍は、LEFT JOINの結果としてNULLとなる
    • 注意: 実際にはシリーズ作品でもデータベースに登録されていない場合がある

シリーズ情報の取得SQL

基本クエリ

SELECT
  ZBOOK.Z_PK,
  ZBOOK.ZDISPLAYTITLE,
  ZGROUP.ZDISPLAYNAME as series_name,
  ZGROUPITEM.ZPOSITION as series_position,
  ZGROUPITEM.ZPOSITIONLABEL as series_position_label
FROM ZBOOK
LEFT JOIN ZGROUPITEM ON ZBOOK.Z_PK = ZGROUPITEM.ZBOOK
LEFT JOIN ZGROUP ON ZGROUPITEM.ZPARENTCONTAINER = ZGROUP.Z_PK
ORDER BY ZBOOK.ZSORTTITLE ASC;

クエリの説明

  1. LEFT JOINの理由:

    • シリーズに属さない書籍も取得するため
    • INNER JOINだとシリーズに属する書籍のみになる
  2. 結合条件:

    • ZBOOK.Z_PK = ZGROUPITEM.ZBOOK: 書籍と中間テーブルを紐付け
    • ZGROUPITEM.ZPARENTCONTAINER = ZGROUP.Z_PK: 中間テーブルとシリーズマスタを紐付け
  3. 取得フィールド:

    • series_name: シリーズ名(ZGROUP.ZDISPLAYNAME
    • series_position: シリーズ内位置(0始まり、ZGROUPITEM.ZPOSITION
    • series_position_label: 位置ラベル("1"始まり、ZGROUPITEM.ZPOSITIONLABEL

全フィールドを含むクエリ

SELECT
  ZBOOK.*,
  ZGROUP.ZDISPLAYNAME as series_name,
  ZGROUPITEM.ZPOSITION as series_position,
  ZGROUPITEM.ZPOSITIONLABEL as series_position_label
FROM ZBOOK
LEFT JOIN ZGROUPITEM ON ZBOOK.Z_PK = ZGROUPITEM.ZBOOK
LEFT JOIN ZGROUP ON ZGROUPITEM.ZPARENTCONTAINER = ZGROUP.Z_PK
ORDER BY ZBOOK.ZSORTTITLE ASC;

シリーズのみを取得するクエリ

SELECT
  ZBOOK.ZDISPLAYTITLE,
  ZGROUP.ZDISPLAYNAME as series_name,
  ZGROUPITEM.ZPOSITIONLABEL as series_position_label
FROM ZBOOK
INNER JOIN ZGROUPITEM ON ZBOOK.Z_PK = ZGROUPITEM.ZBOOK
INNER JOIN ZGROUP ON ZGROUPITEM.ZPARENTCONTAINER = ZGROUP.Z_PK
WHERE ZGROUP.ZDISPLAYNAME IS NOT NULL
ORDER BY ZGROUP.ZDISPLAYNAME, ZGROUPITEM.ZPOSITION;

フィールド詳細

series_name(ZGROUP.ZDISPLAYNAME)

  • : VARCHAR
  • 説明: シリーズの表示名
  • : "ワンパンマン", "LIAR GAME", "明日の敵と今日の握手を【電子単行本】"
  • NULL値: シリーズに属さない書籍の場合

series_position(ZGROUPITEM.ZPOSITION)

  • : INTEGER
  • 説明: シリーズ内の位置(0始まり)
  • : 0, 1, 14, 33
  • NULL値: シリーズに属さない書籍の場合

series_position_label(ZGROUPITEM.ZPOSITIONLABEL)

  • : VARCHAR
  • 説明: ユーザー表示用の位置ラベル
  • : "1", "15", "34"
  • 特徴: series_position + 1の文字列表現(多くの場合)
  • NULL値: シリーズに属さない書籍の場合
  • 手元で確認した限りにおいては、すべていわゆる巻数と一致していました。

位置とラベルの関係

series_position series_position_label 意味
0 "1" シリーズ第1巻
14 "15" シリーズ第15巻
33 "34" シリーズ第34巻
NULL NULL シリーズなし

実例

ワンパンマンシリーズ

SELECT
  ZBOOK.ZDISPLAYTITLE,
  ZGROUP.ZDISPLAYNAME as series_name,
  ZGROUPITEM.ZPOSITION,
  ZGROUPITEM.ZPOSITIONLABEL
FROM ZBOOK
INNER JOIN ZGROUPITEM ON ZBOOK.Z_PK = ZGROUPITEM.ZBOOK
INNER JOIN ZGROUP ON ZGROUPITEM.ZPARENTCONTAINER = ZGROUP.Z_PK
WHERE ZGROUP.ZDISPLAYNAME = 'ワンパンマン'
ORDER BY ZGROUPITEM.ZPOSITION;

結果例:

タイトル                                    | series_name | ZPOSITION | ZPOSITIONLABEL
-------------------------------------------|-------------|-----------|---------------
ワンパンマン 1 (ジャンプコミックスDIGITAL)  | ワンパンマン | 0         | 1
ワンパンマン 2 (ジャンプコミックスDIGITAL)  | ワンパンマン | 1         | 2
...
ワンパンマン 34 (ジャンプコミックスDIGITAL) | ワンパンマン | 33        | 34

LIAR GAMEシリーズ

タイトル                                   | series_name | ZPOSITION | ZPOSITIONLABEL
------------------------------------------|-------------|-----------|---------------
LIAR GAME 9 (ヤングジャンプコミックスDIGITAL)  | LIAR GAME   | 8         | 9
LIAR GAME 10 (ヤングジャンプコミックスDIGITAL) | LIAR GAME   | 9         | 10
LIAR GAME 15 (ヤングジャンプコミックスDIGITAL) | LIAR GAME   | 14        | 15
LIAR GAME 17 (ヤングジャンプコミックスDIGITAL) | LIAR GAME   | 16        | 17

シリーズなしの書籍

タイトル                          | series_name | ZPOSITION | ZPOSITIONLABEL
---------------------------------|-------------|-----------|---------------
一九八四年 (ハヤカワepi文庫)      | NULL        | NULL      | NULL
アンチマン 岡田索雲短編集        | NULL        | NULL      | NULL

関連テーブル

ZSERIESAUTHOR(シリーズ著者情報)

シリーズの著者情報を格納します(複数著者対応)。

SELECT
  ZGROUP.ZDISPLAYNAME,
  ZSERIESAUTHOR.ZAUTHORNAME,
  ZSERIESAUTHOR.ZAUTHORPRONUNCIATION
FROM ZGROUP
LEFT JOIN ZSERIESAUTHOR ON ZGROUP.Z_PK = ZSERIESAUTHOR.ZSERIES
WHERE ZGROUP.ZDISPLAYNAME = 'ワンパンマン';

ZSERIESIMAGE(シリーズ画像情報)

シリーズの表紙画像情報を格納します。

SELECT
  ZGROUP.ZDISPLAYNAME,
  ZSERIESIMAGE.ZIMAGEID,
  ZSERIESIMAGE.ZEXTENSION
FROM ZGROUP
LEFT JOIN ZSERIESIMAGE ON ZGROUP.Z_PK = ZSERIESIMAGE.ZSERIES
WHERE ZGROUP.ZDISPLAYNAME = 'ワンパンマン';

注意点

NULL値の扱い

  • シリーズ情報が未設定の書籍はseries_nameNULL
  • 注意: 実際にはシリーズ作品でもデータベースに登録されていない場合がある

位置とラベルの関係

  • 常にseries_position + 1 = series_position_labelの関係が成立すると思われる
  • そのため表示にはseries_position_labelを使った方が分かりやすい

免責

  • 本情報は、筆者が独自に調査・検証した非公式情報であり、AmazonまたはKindleとは一切関係ありません。
  • 正確性の保証はありません。誤りや不適切な認識が含まれる可能性があります。
  • 特定の環境・バージョンでの検証結果であり、すべての環境での動作を保証するものではありません。
  • 本記事の内容を利用した結果生じたいかなる損害についても、筆者は一切の責任を負いません。
  • 「Kindle」はAmazon.com, Inc.の登録商標です。本情報は、私的利用の範囲において自身の蔵書情報を参照するものであり、デジタル著作権管理(DRM)やコピープロテクション機構を改変、回避、妨害するものではありません。

Kindle の蔵書一覧を取得する(4) / plist 形式の取り扱い

続きです。今回はplist形式の取り扱いだけど、一般的なものなので知らなくても多分大丈夫ですよ。

ZSYNCMETADATAATTRIBUTES(plist)について

plistとは

  • フルネーム: Property List(プロパティリスト)
  • 形式: NSKeyedArchiver形式のバイナリプロパティリスト
  • プラットフォーム: macOS/iOSで一般的なデータシリアライゼーション形式
  • 用途: 書籍のメタデータを構造化して格納
  • サイズ: 通常1,000-2,000 bytes程度

詳しくはこちらを読んでください。

ja.wikipedia.org

なぜplistが重要か

以下の情報はplistからしか取得できません

  1. 著者名(人間が読める形式)⭐
    • ZBOOKのZDISPLAYAUTHORはハッシュ値/ID
    • plistのauthors.authorが実際の著者名
  2. 購入日時(ISO 8601形式)⭐
    • ZBOOKには購入日フィールドがない
  3. 純粋なASIN(プレフィックスなし)
    • ZBOOKのZBOOKIDは"A:B009DEMC8W-0"
    • plistのASINは"B009DEMC8W"

plistの構造

NSKeyedArchiveの階層

バイナリplistは以下の階層構造を持ちます:

{
  "$version": 100000,
  "$archiver": "NSKeyedArchiver",
  "$top": {
    "root": {
      "UID": 1
    }
  },
  "$objects": [
    "$null",
    {書籍メタデータのルートオブジェクト},
    {属性辞書},
    ...
  ]
}

UID参照の仕組み

  • $objects配列にすべてのオブジェクトが格納
  • 各オブジェクトは{"UID": n}形式で他のオブジェクトを参照
  • 再帰的に辿ることで完全なデータ構造を復元

辞書と配列の表現

辞書(NSDictionary):

{
  "NS.keys": [{"UID": 3}, {"UID": 4}],
  "NS.objects": [{"UID": 5}, {"UID": 6}],
  "$class": {"UID": 7}
}

配列(NSArray):

{
  "NS.objects": [{"UID": 8}, {"UID": 9}],
  "$class": {"UID": 10}
}

含まれる情報の完全リスト

基本情報

フィールド 説明 ZBOOKとの関係
ASIN 文字列 純粋なASIN "B009DEMC8W" ZBOOKIDから抽出可能だがプレフィックス付き
title 文字列 タイトル "一九八四年 (ハヤカワepi文庫)" ZDISPLAYTITLEと完全一致
authors.author 文字列/配列 著者 ["ONE", "村田雄介"] ⭐plistのみ、ZDISPLAYAUTHORはハッシュ値
publishers.publisher 文字列 出版社 "早川書房" ZRAWPUBLISHERと完全一致
purchase_date 文字列 購入日時 "2018-09-24T04:45:07+0000" ⭐plistのみ

コンテンツ情報

フィールド 説明 ZBOOKとの関係
content_type 文字列 MIMEタイプ "application/x-mobipocket-ebook" ZMIMETYPEと同じ
content_tags.tag 配列 コンテンツタグ ["DICT", "FREE_DICT"] ZCONTENTTAGSは";DICT;FREE_DICT"形式
cde_contenttype 文字列 CDEコンテンツタイプ "EBOK" plistのみ
content_size 文字列 ファイルサイズ "18755584" ZRAWFILESIZEは数値
target_language 文字列 対象言語 "en", "ja" ZLANGUAGEと類似

入手元情報

フィールド 説明
origins.origin.type 文字列 入手元タイプ "KindleDictionary", "Purchase"
origins.origin.id 文字列 入手元ID "Freebie", ASIN

その他の情報

フィールド 説明
short_item_name 文字列 短縮名 "Hindi-English"
accessibility_description 文字列 アクセシビリティ説明 "Hindi to English"
bisac_subject_description_code.code 文字列/配列 BISAC分類コード ["BUS000000", "BUS010000"]
default_dict_for_locales 文字列 辞書のデフォルトロケール "hi_IN", "es_ES, es_MX"

ZBOOKフィールドとの比較

plistのみに存在する情報

  1. 著者名(文字列形式)

    • plist: authors.author"ジョージ・オーウェル" または ["ONE", "村田雄介"]
    • ZBOOK: ZDISPLAYAUTHOR → ハッシュ値(6946abd8...
  2. 購入日時

    • plist: purchase_date"2018-09-24T04:45:07+0000"
    • ZBOOK: 該当フィールドなし
  3. 純粋なASIN

    • plist: ASIN"B009DEMC8W"
    • ZBOOK: ZBOOKID"A:B009DEMC8W-0"(プレフィックス・サフィックス付き)

完全一致する情報

  1. タイトル

    • plist: title"一九八四年 (ハヤカワepi文庫)"
    • ZBOOK: ZDISPLAYTITLE"一九八四年 (ハヤカワepi文庫)"
    • 差異: 0件/3,833件(100%一致)
  2. 出版社

    • plist: publishers.publisher"早川書房"
    • ZBOOK: ZRAWPUBLISHER"早川書房"
    • 差異: 0件/3,833件(100%一致)

形式が異なる情報

  1. コンテンツタグ

    • plist: content_tags.tag["DICT", "FREE_DICT"](配列)
    • ZBOOK: ZCONTENTTAGS";DICT;FREE_DICT"(セミコロン区切り文字列)
    • 先頭のセミコロンの有無が異なる
  2. ファイルサイズ

    • plist: content_size"18755584"(文字列)
    • ZBOOK: ZRAWFILESIZE18755584(整数)

著者情報の詳細

ZDISPLAYAUTHORとの違い

ZDISPLAYAUTHOR(BLOB): - ハッシュ値またはID - サイズ: 16-48 bytes - 例: 6946abd8db4a0ba12ca67a5ded9830876eae4caa1b46c47e044bdd79535aef0b - 人間が読めない

plist authors.author: - 実際の著者名 - 文字列または配列 - 例: "ジョージ・オーウェル" または ["ONE", "村田雄介"] - 人間が読める

単一著者の場合

データ型: 文字列

:

{
  "authors": {
    "author": "ジョージ・オーウェル"
  }
}

実例: - 一九八四年: "ジョージ・オーウェル" - LIAR GAME 15: "甲斐谷忍" - 路傍のフジイ(5): "鍋倉夫"

複数著者の場合

データ型: 配列

:

{
  "authors": {
    "author": ["ONE", "村田雄介"]
  }
}

実例: - ワンパンマン 34: ["ONE", "村田雄介"] - 株式会社マジルミエ 18: ["岩田雪花", "青木 裕"] - ケーキの切れない非行少年たち 11巻: ["宮口幸治", "鈴木マサカズ"] - 明日の敵と今日の握手を 7: ["フクダイクミ", "カルロ・ゼン"] - 怪談和尚 妖異の声: ["三木大雲", "森野達弥"]

デコード方法

NSKeyedArchive形式のバイナリplistは、bplist-parserなどのライブラリを使用してデコードできます。

主なライブラリ: - Node.js: bplist-parser (npm) - Python: biplist (PyPI)

実データ例

例1: 単一著者(一九八四年)

{
  "ASIN": "B009DEMC8W",
  "title": "一九八四年 (ハヤカワepi文庫)",
  "authors": {
    "author": "ジョージ・オーウェル"
  },
  "publishers": {
    "publisher": "早川書房"
  },
  "purchase_date": "2018-09-24T04:45:07+0000",
  "content_type": "application/x-mobipocket-ebook",
  "content_size": "2746368"
}

例2: 複数著者(ワンパンマン 34)

{
  "ASIN": "B0FGBZ6BLM",
  "title": "ワンパンマン 34 (ジャンプコミックスDIGITAL)",
  "authors": {
    "author": ["ONE", "村田雄介"]
  },
  "publishers": {
    "publisher": "集英社"
  },
  "purchase_date": "2025-09-03T15:04:26+0000",
  "content_type": "application/x-mobipocket-ebook",
  "content_tags": {
    "tag": ["MANGA"]
  },
  "content_size": "15350784"
}

例3: 辞書(Prabhat Advanced Hindi English Dictionary)

{
  "ASIN": "B06W9KK63F",
  "title": "Prabhat Advanced Hindi English Dictionary (Hindi Edition)",
  "authors": {
    "author": "Prabhat Prakashan"
  },
  "publishers": {
    "publisher": "Amazon Dictionaries"
  },
  "purchase_date": "2017-12-08T17:56:30+0000",
  "target_language": "en",
  "content_tags": {
    "tag": ["DICT", "FREE_DICT"]
  },
  "origins": {
    "origin": {
      "type": "KindleDictionary",
      "id": "Freebie"
    }
  },
  "content_type": "application/x-mobipocket-ebook",
  "short_item_name": "Hindi-English",
  "accessibility_description": "Hindi to English",
  "bisac_subject_description_code": {
    "code": ["BUS000000", "BUS010000"]
  },
  "content_size": "18755584",
  "default_dict_for_locales": "hi_IN"
}

注意点

著者フィールドの型

authors.author文字列または配列のどちらかです: - 単一著者: "ジョージ・オーウェル" (文字列) - 複数著者: ["ONE", "村田雄介"] (配列)

免責

  • 本情報は、筆者が独自に調査・検証した非公式情報であり、AmazonまたはKindleとは一切関係ありません。
  • 正確性の保証はありません。誤りや不適切な認識が含まれる可能性があります。
  • 特定の環境・バージョンでの検証結果であり、すべての環境での動作を保証するものではありません。
  • 本記事の内容を利用した結果生じたいかなる損害についても、筆者は一切の責任を負いません。
  • 「Kindle」はAmazon.com, Inc.の登録商標です。本情報は、私的利用の範囲において自身の蔵書情報を参照するものであり、デジタル著作権管理(DRM)やコピープロテクション機構を改変、回避、妨害するものではありません。