👌

vttファイルからTEI/XMLを作成する

2025/02/21に公開

概要

vttファイルからTEI/XMLファイルを作成する方法の備忘録です。

さらに、IIIFマニフェストから、vttファイルおよびTEI/XMLファイルにアクセスできるようにしてみます。結果、以下のように、TEI/XMLファイルがSeeAlsoに関連づけられ、また「Annotations」タブから、vttファイルの内容にアクセスできます。

https://clover-iiif-demo.vercel.app/?manifest=https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177_vtt.json

参考

以下の「The Ethiopian Language Archive」における取り組みを参考にしました。特に、TEI/XMLの構造化方法が特に参考になりました。

https://dev.jael.info/documentation/

以下で作成したvttファイルを対象とします。

https://zenn.dev/nakamura196/articles/e2693462e4b404

具体的には、以下の『県政ニュース 第1巻』(県立長野図書館)を使用します。

https://www.ro-da.jp/shinshu-dcommons/library/02FT0102974177

TEI/XMLの作成

作成したTEI/XMLファイルの例は以下です。

https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177.xml

具体的には以下です。

<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml"
        schematypens="http://purl.oclc.org/dsdl/schematron"?>
<teiCorpus xmlns="http://www.tei-c.org/ns/1.0">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>県政ニュース 第1巻</title>
      </titleStmt>
      <publicationStmt>
        <distributor>中村覚</distributor>
        <availability>
          <licence target="http://creativecommons.org/licenses/by/4.0/">http://creativecommons.org/licenses/by/4.0/</licence>
        </availability>
      </publicationStmt>
      <notesStmt>
        <note>昭和30年に長野県が制作した記録映像。次の8タイトルを収録する。「地方選挙終る」、「地方選挙後初の県議会開かる」、「三十年度を賄う県のお台所」、「すすむ土木建設」、「明るく正しく健やかに」、「幕をとじた善光寺の御開帳」、「勇ましい水防訓練」、「お国じまん民謡大会」</note>
      </notesStmt>
      <sourceDesc>
        <biblStruct>
          <monogr>
            <title>県政ニュース 第1巻</title>
            <availability>
              <licence target="https://creativecommons.org/publicdomain/zero/1.0/">cc0</licence>
            </availability>
            <imprint>
              <publisher>信州デジタルコモンズ 県立長野図書館所蔵資料</publisher>
            </imprint>
          </monogr>
          <ref target="https://www.ro-da.jp/shinshu-dcommons/library/02FT0102974177">信州デジタルコモンズ 県立長野図書館所蔵資料</ref>
        </biblStruct>
      </sourceDesc>
    </fileDesc>
  </teiHeader>
  <TEI>
    <teiHeader>
      <fileDesc>
        <titleStmt>
          <title>県政ニュース 第1巻</title>
        </titleStmt>
        <publicationStmt>
          <p />
        </publicationStmt>
        <notesStmt>
          <note />
        </notesStmt>
        <sourceDesc>
          <p />
        </sourceDesc>
      </fileDesc>
      <revisionDesc>
        <change when="2025-02-18"> 作成 </change>
      </revisionDesc>
    </teiHeader>
    <text>
      <body>
        <timeline unit="ms">
          <when absolute="00:00:00.000" xml:id="t1" />
          <when absolute="00:00:25.500" xml:id="t2" />
          <when absolute="00:00:38.500" xml:id="t3" />
          <when absolute="00:00:50.500" xml:id="t4" />
          <when absolute="00:00:55.500" xml:id="t5" />
          <when absolute="00:01:03.500" xml:id="t6" />
          <when absolute="00:01:08.500" xml:id="t7" />
          <when absolute="00:01:18.500" xml:id="t8" />
          <when absolute="00:01:23.500" xml:id="t9" />
          <when absolute="00:01:33.500" xml:id="t10" />
            ...
        </timeline>
        <annotationBlock xml:id="ab1">
          <u start="#t1" end="#t2">♪♪♪</u>
        </annotationBlock>
        <annotationBlock xml:id="ab2">
          <u start="#t2" end="#t3">今年は選挙の当たり年。2月の総選挙に引き続いて、4月の県市町村と八木早の選挙で、長野県116万有権者の関心は非常な高まりようです。</u>
        </annotationBlock>
        <annotationBlock xml:id="ab3">
          <u start="#t3" end="#t4">男女青年や婦人層はもちろんのこと、この老人も今年88を迎えたとはいえ、その慎重な投票ぶりが老いの表に一徹さを伺わせています。</u>
        </annotationBlock>
        <annotationBlock xml:id="ab4">
          <u start="#t4" end="#t5">♪〜</u>
        </annotationBlock>
        <annotationBlock xml:id="ab5">
          <u start="#t5" end="#t6">かくて県下における投票率、全国の上位を占める立派な成績を収めました。</u>
        </annotationBlock>
        <annotationBlock xml:id="ab6">
          <u start="#t6" end="#t7">♪ ♪</u>
        </annotationBlock>
        <annotationBlock xml:id="ab7">
          <u start="#t7" end="#t8">その日午後8時 きっかり、県下一斉に即日開票が行われました。</u>
        </annotationBlock>
        <annotationBlock xml:id="ab8">
          <u start="#t8" end="#t9">その結果、長野県知事には、前知事の林寅氏が当選。</u>
        </annotationBlock>
        <annotationBlock xml:id="ab9">
          <u start="#t9" end="#t10">またこれと同時に、県議会議員61名の当選も決定しました。</u>
        </annotationBlock>
        ...
      </body>
    </text>
  </TEI>
</teiCorpus>

IIIFマニフェストファイルの作成

上述したTEI/XMLファイルをseeAlsoに持つIIIFマニフェストファイルを作成しました。

https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177_vtt.json

具体的には以下です。

{
  "@context": "http://iiif.io/api/presentation/3/context.json",
  "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177_vtt.json",
  "type": "Manifest",
  "label": {
    "ja": [
      "県政ニュース 第1巻"
    ]
  },
  "metadata": [
    {
      "label": {
        "ja": [
          "distributor"
        ]
      },
      "value": {
        "ja": [
          "中村覚"
        ]
      }
    }
  ],
  "summary": {
    "ja": [
      "昭和30年に長野県が制作した記録映像。次の8タイトルを収録する。「地方選挙終る」、「地方選挙後初の県議会開かる」、「三十年度を賄う県のお台所」、「すすむ土木建設」、「明るく正しく健やかに」、「幕をとじた善光寺の御開帳」、「勇ましい水防訓練」、「お国じまん民謡大会」"
    ]
  },
  "requiredStatement": {
    "label": {
      "ja": [
        "Attribution"
      ]
    },
    "value": {
      "ja": [
        "『県政ニュース 第1巻』(信州デジタルコモンズ 県立長野図書館所蔵資料)を改変"
      ]
    }
  },
  "rights": "https://creativecommons.org/publicdomain/zero/1.0/",
  "provider": [
    {
      "id": "http://example.org/iiif/4",
      "type": "Agent",
      "label": {
        "ja": [
          "信州デジタルコモンズ 県立長野図書館所蔵資料"
        ]
      }
    }
  ],
  "seeAlso": [
    {
      "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177.xml",
      "type": "Dataset",
      "label": {
        "ja": [
          "TEI/XML"
        ]
      },
      "format": "application/xml"
    }
  ],
  "homepage": [
    {
      "id": "https://www.ro-da.jp/shinshu-dcommons/library/02FT0102974177",
      "type": "Text",
      "label": {
        "ja": [
          "信州デジタルコモンズ 県立長野図書館所蔵資料"
        ]
      },
      "format": "text/html"
    }
  ],
  "items": [
    {
      "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas",
      "type": "Canvas",
      "height": 480,
      "width": 640,
      "duration": 619.648005,
      "items": [
        {
          "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas/page",
          "type": "AnnotationPage",
          "items": [
            {
              "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas/page/annotation",
              "type": "Annotation",
              "motivation": "painting",
              "body": {
                "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177.mp4",
                "type": "Video",
                "height": 480,
                "width": 640,
                "duration": 619.648005,
                "format": "video/mp4"
              },
              "target": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas"
            }
          ]
        }
      ],
      "annotations": [
        {
          "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas",
          "type": "AnnotationPage",
          "items": [
            {
              "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas/annotation/webvtt",
              "type": "Annotation",
              "label": {
                "ja": [
                  "日本語 (machine-generated)"
                ]
              },
              "motivation": "supplementing",
              "body": {
                "id": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177.vtt",
                "type": "Text",
                "format": "text/vtt",
                "label": {
                  "ja": [
                    "日本語 (machine-generated)"
                  ]
                }
              },
              "target": "https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177/canvas"
            }
          ]
        }
      ]
    }
  ]
}

iiif-prezi3の使い方

上記のIIIFマニフェストファイルを作成するにあたり、iiif-prezi3を使用しました。

https://github.com/iiif-prezi/iiif-prezi3

以下などで使用方法を確認できます。

https://iiif-prezi.github.io/iiif-prezi3/code/

以下、いくつかの例です。

class CustomManifest:
    """IIIF Manifest v3のカスタムラッパークラス

    IIIF Manifestを生成・編集するためのユーティリティクラス。
    基本的なメタデータの追加機能を提供します。
    """

    def __init__(self, manifest_path: str):
        """
        Args:
            manifest_path (str): マニフェストJSONファイルのパス
        """
        manifest_json = json.load(open(manifest_path))
        self.manifest = Manifest(**manifest_json)

    def add_seeAlso(self, url: str, type: str, label: str, format: str) -> None:
        """関連リソースへの参照を追加

        Args:
            url (str): 関連リソースのURL
            type (str): リソースの種類
            label (str): 表示ラベル
            format (str): リソースのMIMEタイプ
        """
        seeAlso = ExternalItem(
            id=url,
            type=type,
            label=label,
            format=format
        )
        self.manifest.seeAlso = seeAlso

    def add_requiredStatement(self, label: str, value: str) -> None:
        """必須の権利表示を追加

        Args:
            label (str): 表示ラベル
            value (str): 表示内容
        """
        requiredStatement = KeyValueString(
            label=label,
            value=value
        )
        self.manifest.requiredStatement = requiredStatement

    def add_provider(self, label: str) -> None:
        """提供機関情報を追加

        Args:
            label (str): 機関名
        """
        provider = ExternalItem(
            type="Agent",
            label=label
        )
        self.manifest.provider = provider

    def add_homepage(self, id: str, label: str) -> None:
        """ホームページ情報を追加

        Args:
            id (str): ホームページのURL
            label (str): 表示ラベル
        """
        homepage = ExternalItem(
            id=id,
            type="Text",
            label=label,
            format="text/html"
        )
        self.manifest.homepage = homepage

    def save(self, output_path: str) -> None:
        """マニフェストをJSONファイルとして保存

        Args:
            output_path (str): 出力先のパス
        """
        with open(output_path, 'w') as f:
            json.dump(self.manifest.json(), f, indent=2, ensure_ascii=False)

まとめ

不完全な点もありますが、動画資料に関するTEI/XMLおよびIIIFマニフェストファイルの作成にあたり、参考になりましたら幸いです。

Discussion