ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English
Node.jsを使って、JSON:APIに準拠しているかを検証する

Node.jsを使って、JSON:APIに準拠しているかを検証する

概要 JSON:APIに準拠しているかを検証するにあたり、以下のリポジトリを使用してみましたので、備忘録です。 https://github.com/elliotttf/jsonapi-validator 本記事執筆時点において、7年前から更新がされていないようなので、最新のスキーマ等には非対応かもしれませんが、簡単な検証は行うことができました。 使い方 上記のライブラリを試すにあたり、以下のリポジトリを用意しました。 https://github.com/nakamura196/jsonapi-validator-demo インストール nvmの利用を前提していますが、必須ではありません。 git clone https://github.com/nakamura196/jsonapi-validator-demo cd jsonapi-validator-demo nvm i 22 nvm use 22 pnpm i 試す OKの例 { "jsonapi": { "version": "1.0", "meta": { "links": { "self": { "href": "http://jsonapi.org/format/1.0/" } } } }, "data": [ { "type": "record", "id": "10_A0024853", "attributes": { "title": "サンプル" } } ] } ./node_modules/jsonapi-validator/bin/jsonapi-validator.js -f ./01_valid.json 01_valid.json is valid JSON API. NGな例:不要なプロパティあり aaaという不要なプロパティがあります。 { "jsonapi": { "version": "1.0", "meta": { "links": { "self": { "href": "http://jsonapi.org/format/1.0/" } } } }, "aaa": { "bbb": "ccc" }, "data": [ { "type": "record", "id": "10_A0024853", "attributes": { "title": "サンプル" } } ] } ./node_modules/jsonapi-validator/bin/jsonapi-validator.js -f ./02_invalid_additional_properties.json Invalid JSON API. should NOT have additional properties. schemaPath: #/additionalProperties additionalProperty: aaa should NOT have additional properties. schemaPath: #/additionalProperties additionalProperty: aaa should NOT have additional properties. schemaPath: #/additionalProperties additionalProperty: data should have required property 'errors'. schemaPath: #/required missingProperty: errors should NOT have additional properties. schemaPath: #/additionalProperties additionalProperty: aaa should NOT have additional properties. schemaPath: #/additionalProperties additionalProperty: data should have required property 'meta'. schemaPath: #/required missingProperty: meta should match exactly one schema in oneOf. schemaPath: #/oneOf NGな例:必要なプロパティがない typeという必要なプロパティがない例です。 ...

virtual-museum-tour-threejsを試す

virtual-museum-tour-threejsを試す

概要 以下のリポジトリを試す機会がありましたので、備忘録です。 https://github.com/theringsofsaturn/virtual-museum-tour-threejs 以下でチュートリアル動画も公開されていました。 https://www.youtube.com/watch?v=8oQC0ICNtL0 フォーク リポジトリをフォークして、一部修正を加え、GitHub Pagesでビルド結果を確認できるようにしました。 https://nakamura196.github.io/virtual-museum-tour-threejs/ まとめ Three.jsを使ったアプリ開発にあたり、参考になるかと思います。

Omeka SのOaiPmhリポジトリモジュールにおいて、アイテムが公開されいているサイトページのURLを取得する

Omeka SのOaiPmhリポジトリモジュールにおいて、アイテムが公開されいているサイトページのURLを取得する

概要 Omeka SのOaiPmhリポジトリモジュールにおいて、アイテムが公開されいているサイトページのURLを取得する方法に関する備忘録です。 背景 以下の記事で、OaiPmhRepositoryを使った独自語彙の作成方法を紹介しています。 https://nakamura196.hatenablog.com/entry/2021/07/25/222651 こちらも参考にしてください。 アイテムが公開されいているサイトページのURLの取得 修正前 あるカスタマイズ事例において、以下のようにサイトページのURLを取得していました。以下は、Clean Urlモジュールにおいてdcterms:identifier以外が設定されている場合にはうまくいきません。また、/s/db/record/といったハードコーディングが見られます。 if ( $item->value( "dcterms:identifier" ) ) { $this->appendNewElement($oai, 'curation:relation', self::prefix."/s/db/record/".(string)$item->value("dcterms:identifier")->value()); } 修正後 以下のようにシンプルに記述することができました。これにより、当該アイテムが複数のサイトで公開されていても対応することができます。 $sites = $item->sites(); foreach ($sites as $key => $site) { $siteSlug = $site->slug(); $this->appendNewElement($oai, 'curation:relation', $item->siteUrl($siteSlug, true)); } まとめ Omeka Sを用いたOAI-PMHリポジトリの構築にあたり、参考になりましたら幸いです。

DrupalのREST APIを使って、複数のコンテンツを一括削除する

DrupalのREST APIを使って、複数のコンテンツを一括削除する

概要 DrupalのREST APIを使って、複数のコンテンツを一括削除する機会がありましたので、備忘録です。 参考 REST APIを使用せずにコンテンツを一括削除する方法として、以下も参考にしてください。 準備 まず、HTTP Basic AuthenticationモジュールとJSON:APIモジュールを有効化します。 さらに、REST resourcesにおいて、DELETEを有効化します。 /admin/config/services/rest 実行例 以下の自作ライブラリを使用します。 https://github.com/nakamura196/drupal_tools 以下でも処理内容をご確認いただけます。 https://nakamura196.github.io/drupal_tools/ インストール pip install git+https://github.com/nakamura196/drupal_tools .envの準備 DRUPAL_URL=http://example.org/drupal DRUPAL_USERNAME=username DRUPAL_PASSWORD=password 実行 以下のように実行します。 item_idsは、field_name(ここでは、field_item_id)に対応する一意の値のリストです。 from drupal_tools.api import DrupalAPIClient import pandas as pd def get_item_ids(): # Load a CSV file containing item ids into a DataFrame. df = pd.read_csv("./uuids.csv") item_ids = [row["asset_uuid"] for _, row in df.iterrows()] return item_ids # Call the function to get the list of item ids. item_ids = get_item_ids() # Load Drupal credentials from a .env file using the DrupalAPIClient. DRUPAL_URL, DRUPAL_USERNAME, DRUPAL_PASSWORD = DrupalAPIClient.load_credentials("../.env") # Create an instance of the DrupalAPIClient with the loaded credentials. drupal = DrupalAPIClient(DRUPAL_URL, DRUPAL_USERNAME, DRUPAL_PASSWORD) field_name = "field_item_id" nids = drupal.get_nids(item_ids, field_name) results = drupal.delete_from_nids(nids) まとめ 不具合等が含まれる可能性がありますので、使用される際は十分にご注意ください。 ...

音声資料に関するIIIFマニフェストファイルに画像を追加する

音声資料に関するIIIFマニフェストファイルに画像を追加する

概要 以下のAudio Presentation with Accompanying Imageを試した結果の備忘録です。 https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/ 以下はCloverで表示した例ですが、設定した画像がプレイヤーに表示されます。 https://samvera-labs.github.io/clover-iiif/docs/viewer/demo?iiif-content=https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json マニフェストファイルの記述 以下に例を格納しています。 https://github.com/nakamura196/ramp_data/blob/main/docs/demo/3571280/manifest.json 具体的には、以下のように、CanvasにaccompanyingCanvasを追加する必要がありました。 { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas", "type": "Canvas", "duration": 156.07999999999998, "accompanyingCanvas": { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/accompanying", "type": "Canvas", "height": 1024, "width": 1024, "items": [ { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/accompanying/annotation/page", "type": "AnnotationPage", "items": [ { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/accompanying/annotation/image", "type": "Annotation", "motivation": "painting", "body": { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/3571280_summary_image.jpg", "type": "Image", "height": 1024, "width": 1024, "format": "image/jpeg" }, "target": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/accompanying/annotation/page" } ] } ] }, わかりにくいですが、iiif_prezi3を使った記述例です。create_accompanying_canvas()によってaccompanyingCanvasを作成し、それをcanvasに関連づけています。 def add_accompanying_image(self): if self.verbose: print("Adding accompanying image") print(self.image_path) if os.path.exists(self.image_path): accompanyingCanvas = self.create_accompanying_canvas() self.canvas.accompanyingCanvas = accompanyingCanvas def create_accompanying_canvas(self): im = Image.open(self.image_path) w, h = im.size accompanyingCanvas = iiif_prezi3.Canvas(id=f"{self.prefix}/canvas/accompanying") anno_page, anno = self.create_image_annotation(w, h) accompanyingCanvas.set_hwd(height=h, width=w) accompanyingCanvas.add_item(anno_page) return accompanyingCanvas def create_image_annotation(self, width, height): anno_page = iiif_prezi3.AnnotationPage(id=f"{self.prefix}/canvas/accompanying/annotation/page") anno = iiif_prezi3.Annotation( id=f"{self.prefix}/canvas/accompanying/annotation/image", motivation="painting", body=iiif_prezi3.ResourceItem( id=f"{self.prefix}/{self.item_id}_summary_image.{self.image_format}", type="Image", format="image/jpeg", height=height, width=width ), target=anno_page.id ) anno_page.add_item(anno) return anno_page, anno (参考)画像ファイルの作成 国立国会図書館 歴史的音源(れきおん)では、画像データは提供されていないため、Dall-E 3を使用してサンプル画像を作成しました。 ...

IIIF Audio/Visual: 複数のvttファイルを記述する

IIIF Audio/Visual: 複数のvttファイルを記述する

概要 IIIFを用いたAudio/Visual資料の記述について、複数のvttファイルを記述する方法に関する備忘録です。 ここでは、以下のように、日英の文字起こしテキストを記述します。 https://ramp.avalonmediasystem.org/?iiif-content=https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json マニフェストファイルの記述 以下に例を格納しています。 https://github.com/nakamura196/ramp_data/blob/main/docs/demo/3571280/manifest.json 以下の記事も参考にしてください。 具体的には、以下のように複数のアノテーションとして記述することで、rampビューアによって正しく処理されました。 ... "annotations": [ { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/page/2", "type": "AnnotationPage", "items": [ { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/annotation/webvtt", "type": "Annotation", "label": { "ja": [ "日本語 (machine-generated)" ] }, "motivation": "supplementing", "body": { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/3571280.vtt", "type": "Text", "format": "text/vtt", "label": { "ja": [ "日本語 (machine-generated)" ] } }, "target": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas" }, { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas/annotation/webvtt/2", "type": "Annotation", "label": { "ja": [ "English (machine-generated)" ] }, "motivation": "supplementing", "body": { "id": "https://nakamura196.github.io/ramp_data/demo/3571280/3571280_en.vtt", "type": "Text", "format": "text/vtt", "label": { "ja": [ "English (machine-generated)" ] } }, "target": "https://nakamura196.github.io/ramp_data/demo/3571280/canvas" } ] } ] ... なお、Cloverでは、2つの文字起こしテキストが連続して表示されました。 ...

ZoteroのAPIとStreamlitを使ったアプリ開発

ZoteroのAPIとStreamlitを使ったアプリ開発

概要 ZoteroのAPIとStreamlitを使ったアプリを試作しました。 https://nakamura196-zotero.streamlit.app/ 本記事は、このアプリ開発におけるメモです。 Streamlit 以下の記事がとても参考になりました。 https://qiita.com/sypn/items/80962d84126be4092d3c ZoteroのAPI ZoteroのAPIについて、以下で説明されています。 https://www.zotero.org/support/dev/web_api/v3/start 今回は上記のページで紹介されている以下のライブラリを使用しました。 https://github.com/urschrei/pyzotero APIの利用にあたっては、personal library IDやAPI keyを取得する必要がありますが、READMEのQuickstartの手順に従うと、それらを取得することができました。 以下は、API keyを発行した際の画面です。 Streamlitを用いた開発 以下のリポジトリでソースコードを公開しています。 https://github.com/nakamura196/zotero_streamlit 機密情報 機密情報は、/.streamlit/secrets.tomlというファイルを作成し、そこに記載するようでした。.gitignoreに記載することも忘れないようにしてください。 [zotero] library_id="xxx" library_type="user" api_key="xxx" そして、以下のように呼び出すことができました。 def init_zotero(): library_id = st.secrets["zotero"]["library_id"] library_type = st.secrets["zotero"]["library_type"] api_key = st.secrets["zotero"]["api_key"] return zotero.Zotero(library_id, library_type, api_key) Zoteroライブラリのコレクション一覧の取得 以下ので、Zoteroライブラリからコレクションの一覧を取得することができました。 def fetch_collections(zot): """ Zoteroライブラリからコレクション一覧を取得する """ collections = zot.collections() # 各コレクションからタイトルとキー(ID)を取得 collection_list = [{"name": collection['data']['name'], "key": collection['data']['key']} for collection in collections] return collection_list コレクション内のアイテムの取得 以下でコレクション内のアイテムを取得できました。itemTypeがattachmentのものはスキップする処理を加えています。 # 文献データをDataFrameに変換 def create_df(zot, collection_id): if not collection_id: return pd.DataFrame() try: items = zot.collection_items(collection_id) rows = [{ 'title': item['data']['title'], "itemType": item['data']['itemType'], "creators": ", ".join(f"{creator['firstName']} {creator['lastName']}" for creator in item['data'].get('creators', [])), "date": item['data'].get('date', "") } for item in items if item['data']['itemType'] != "attachment"] return pd.DataFrame(rows) except Exception as e: st.error(f"Failed to load items from collection: {e}") return pd.DataFrame() メタタグ設定 以下のような形で、タイトルなどのページ設定を行うことができました。 ...

字幕付きの音声ファイルをIIIFビューアで表示する

字幕付きの音声ファイルをIIIFビューアで表示する

概要 字幕付きの音声ファイルをIIIFビューアで表示する機会がありましたので、備忘録です。 国立国会図書館 歴史的音源で公開されている「日本のアクセントと言葉調子(下)」を対象に、OpenAIのSpeech to textを使用しています。文字起こし結果には誤りが含まれていますので、その点はご注意ください。 以下は、Rampでの表示例です。 https://ramp.avalonmediasystem.org/?iiif-content=https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json 以下は、Cloverでの表示例です。 https://samvera-labs.github.io/clover-iiif/docs/viewer/demo?iiif-content=https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json 以下は、Aviaryでの表示例です。こちらについては、残念ながら今回使用したマニフェストファイルの形式では、文字起こしテキストは表示できませんでした。 https://iiif.aviaryplatform.com/player?manifest=https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json 以下、これらのマニフェストファイルの作成方法について紹介します。 mp4ファイルの準備 以下の記事を参考に、mp4ファイルを取得します。 vttファイルの作成 OpenAIのAPIを使用して、文字起こしを行います。 from openai import OpenAI client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) audio_file= open(output_mp4_path, "rb") transcript = client.audio.transcriptions.create( model="whisper-1", file=audio_file, response_format="vtt") with open(output_vtt_path, "w", encoding="utf-8") as file: file.write(transcript) マニフェストファイルの作成 不完全なコードですが、以下のようなプログラムによって、マニフェストファイルを作成します。 from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config from moviepy.editor import VideoFileClip def get_video_duration(filename): with VideoFileClip(filename) as video: return video.duration config.configs['helpers.auto_fields.AutoLang'].auto_lang = "ja" duration=get_video_duration(mp4_path) manifest = Manifest(id=f"{prefix}/manifest.json", label=label) canvas = manifest.make_canvas(id=f"{prefix}/canvas", duration=duration) anno_body = ResourceItem(id=mp4_url, type="Sound", format="audio/mp4", duration=duration) anno_page = AnnotationPage(id=f"{prefix}/canvas/page") anno = Annotation(id=f"{prefix}/canvas/page/annotation", motivation="painting", body=anno_body, target=canvas.id) anno_page.add_item(anno) canvas.add_item(anno_page) # VTT URLを追加 vtt_body = ResourceItem(id=vtt_url, type="Text", format="text/vtt") vtt_anno = Annotation( id=f"{prefix}/canvas/annotation/webvtt", motivation="supplementing", body=vtt_body, target=canvas.id, label = "WebVTT Transcript (machine-generated)" ) vtt_anno_page = AnnotationPage(id=f"{prefix}/canvas/page/2") vtt_anno_page.add_item(vtt_anno) canvas.annotations = [vtt_anno_page] with open(output_path, "w") as f: f.write(manifest.json(indent=2)) ライブラリとして、iiif-prezi3を使用しています。以下の記事も参考にしてください。 ...

mdx.jpのオブジェクトストレージに複数ファイルをアップロードする

mdx.jpのオブジェクトストレージに複数ファイルをアップロードする

概要 mdx.jpのオブジェクトストレージに複数ファイルをアップロードする方法の備忘録です。以下の動画を参考にしています。 https://youtu.be/IN_4NS9hO2Y 準備 macOSで作業します。 brew install s3cmd 設定(内容は動画を確認してください。) s3cmd --configure 一括登録(同期) 以下は、ローカルのrekionフォルダ内のファイルをs3://rekion/iiif/と同期します。 s3cmd sync docs/rekion/ s3://rekion/iiif/ --exclude '.DS_Store' 参考 find . -name '.DS_Store' -type f -delete aclの一括変更 s3cmd setacl s3://rekion/iiif/ --acl-public --recursive 注意(corsの許可) 以下のxmlファイルを用意して、corsの許可を試みました。 <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration> ただし、以下の結果となり、この方法ではcorsの許可ができませんでした。 s3cmd setcors cors.xml s3://rekion/ ERROR: S3 error: 501 (NotImplemented): A header or parameter you provided implies functionality that is not implemented. 設定方法について、引き続き調べたいと思います。 まとめ mdx.jpのオブジェクトストレージの利用にあたり、参考になりましたら幸いです。

国立国会図書館 歴史的音源で公開されている音声をmp4に変換する

国立国会図書館 歴史的音源で公開されている音声をmp4に変換する

概要 国立国会図書館 歴史的音源(以下、れきおん)で公開されている音声をmp4に変換する機会がありましたので、備忘録です。 れきおんの提供形式 れきおんでは、m3u8形式のファイルが公開されていました。 例えば、以下の「講演:道徳、経済合一論(一)Union of Morality of Economy」を確認してみます。 https://rekion.dl.ndl.go.jp/pid/3574643 開発者ツールなどで確認すると、以下のURLからアクセスできることが確認できます。 https://rekion.dl.ndl.go.jp/contents/3574643/83389ec6-2b45-4fdd-88d6-89628841039f/317d6ab4-32ec-4085-88e6-cfe36ffd34c3/317d6ab4-32ec-4085-88e6-cfe36ffd34c3_hls.m3u8 このURLを構成するIDなどは、以下のAPIの返却結果の中で確認できました。 https://rekion.dl.ndl.go.jp/api/item/search/info:ndljp/pid/3574643 pidから上記のURLを取得するAPIの開発 上記のJSONを処理することで、m3u8ファイルのURLを取得します。 この部分をAPI化したので、試していただけますと幸いです。 https://iiif-demo-next.vercel.app/api/rekion/3574643 以下のような結果が得られます。 { "data": { "type": "rekion", "id": "3574643", "attributes": { "title": "講演:道徳、経済合一論(一)Union of Morality of Economy", "url": "https://rekion.dl.ndl.go.jp/pid/3574643", "hls": "https://rekion.dl.ndl.go.jp/contents/3574643/83389ec6-2b45-4fdd-88d6-89628841039f/317d6ab4-32ec-4085-88e6-cfe36ffd34c3/317d6ab4-32ec-4085-88e6-cfe36ffd34c3_hls.m3u8" } } } ソースコードは以下です。 https://github.com/nakamura196/iiif-demo-next/blob/main/src/app/api/rekion/[id]/route.ts ffmpegを使ってmp4に変換する 以下のようなコマンドにより、m3u8ファイルをmp4形式に変換できました。 ffmpeg -i "https://rekion.dl.ndl.go.jp/contents/3574643/83389ec6-2b45-4fdd-88d6-89628841039f/317d6ab4-32ec-4085-88e6-cfe36ffd34c3/317d6ab4-32ec-4085-88e6-cfe36ffd34c3_hls.m3u8" -c copy 3574643.mp4 まとめ 音声ファイルの利用にあたり、参考になりましたら幸いです。

Rampをカスタマイズする

Rampをカスタマイズする

概要 Rampのカスタマイズ方法に関する備忘録です。カスタマイズの結果、以下のように、UIの一部を日本語化し、メディアプレイヤーとメタデータおよび文字起こしを左右に並べて表示します。また、クエリパラメータtを使って、音声の再生開始時間を指定できるようにします。 例えば、以下のURLから、140秒時点から再生することができます。 https://ramp-iiif.vercel.app/?iiif-content=https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json&t=140 以下がカスタマイズ前です。 セットアップ 以下の記事の参考にしてください。 カスタマイズ 音声の再生開始時間の指定 以下のマニュアルにおいて、startCanvasTimeプロパティが使えることがわかります。 https://samvera-labs.github.io/ramp/#!/IIIFPlayer そこで、以下のindex.jsファイルに対して、startCanvasTimeをクエリパラメータから取得する処理を追加します。 import React from 'react'; import ReactDOM from 'react-dom'; import App from './app'; // import config from './config'; const manifestURL = () => { const params = new URLSearchParams(window.location.search); // let url = `${config.url}/manifests/${config.env}/lunchroom_manners.json`; let url = "https://nakamura196.github.io/ramp_data/demo/3571280/manifest.json" if (params.has('iiif-content')) { url = params.get('iiif-content'); } return url; }; const startCanvasTime = () => { const params = new URLSearchParams(window.location.search); if (params.has('t')) { return parseFloat(params.get('t')); } return 0; } ReactDOM.render(<App manifestURL={manifestURL()} startCanvasTime={startCanvasTime()} />, document.getElementById('root')); そして、app.jsに対して、startCanvasTimeプロパティを与えます。これにより、クエリパラメータから、メディアの再生開始時間を指定できます。 ... <IIIFPlayer manifestUrl={manifestUrl} startCanvasTime={canvasTime} > ... 日本語化およびレイアウトの変更 上記と同様、demo/app.jsファイルを編集することで、日本語化およびレイアウトの変更を行うことができます。 Vercelへのデプロイ Build & Development Settingsを以下のように指定します。 Build Commandにnpm run demo:build、Output Directoryにdemo/distを設定します。 また、Node.js Versionを18.xにする必要がありました。20.xの場合、パッケージのインストール時にエラーが発生しました。 まとめ Rampの開発に関わる方々に感謝いたします。RampおよびIIIF Presentation API v3の利用にあたり、参考になりましたら幸いです。 ...

Rampをローカルで起動する

Rampをローカルで起動する

概要 Rampをローカルで起動してみましたので、備忘録です。 背景 Rampは以下のように説明されています。 Interactive, IIIF powered audio/video media player React components library. (日本語訳)インタラクティブな、IIIF対応のオーディオ/ビデオメディアプレイヤーReactコンポーネントライブラリ 以下のGitHubリポジトリでソースコードが公開されています。 https://github.com/samvera-labs/ramp 起動 以下で起動できました。 git clone https://github.com/samvera-labs/ramp pnpm i pnpm demo 以下に記載があります。 https://github.com/samvera-labs/ramp?tab=readme-ov-file#styleguidist-development 以下の場合は、スタイルガイドのページが表示されますので、ご注意ください。 pnpm dev まとめ 参考になりましたら幸いです。

Mirador 3でScroll Viewを使う

Mirador 3でScroll Viewを使う

概要 Mirador 3でScroll Viewを使う方法についての備忘録です。 以下、「鹿児嶋征討記之内 高瀬口河通ノ戦争野津公聯隊旗を取返ス図(国立国会図書館所蔵)」を例としています。 このIIIFマニフェストは3つのキャンバス(画像)から構成されており、通常の表示方法(Single, 単一モード)では、画像ごとに表示されます。 これを3つ繋げて表示することを目指します。 デモ 以下からお試しいただけます。 https://nakamura196.github.io/mirador-multi-image/ IIIFマニフェストファイルについては、国立国会図書館で公開されているIIIFマニフェストファイルを一部変更しています。 変更前 https://dl.ndl.go.jp/api/iiif/1301543/manifest.json 変更後 https://nakamura196.github.io/mirador-multi-image/manifest.json 変更箇所として、今回の記事の目的であるScroll表示と直接関係がありませんが、画像が右から左に表示されるように、"viewingDirection": "right-to-left"を追加しています。 Miradorの設定 Mirador 2では事前設定なしにScroll Viewが使えましたが、Mirador 3のデフォルト設定では、Scroll Viewは無効化されているようでした。 https://projectmirador.org/embed/?iiif-content=https://nakamura196.github.io/mirador-multi-image/manifest.json そこで、Mirador 3の初期設定を以下のように修正します。 https://github.com/nakamura196/mirador-multi-image/blob/main/docs/index.html const config = { id: "mirador", windows: [ { manifestId: "./manifest.json", }, ], language: "ja", window: { sideBarOpenByDefault: true, defaultSideBarPanel: "info", defaultView: "scroll", views: [{ key: "single" }, { key: "gallery" }, { key: "scroll" }], }, }; Mirador.viewer(config); ポイントは、views: [{ key: "single" }, { key: "gallery" }, { key: "scroll" }]です。ここで、Scroll Viewを追加することで、以下のように選択肢として表示されるようになりました。 参考 defaultView未指定時のバグ デフォルト表示を未指定の場合、上記の例ではSingle(単一)表示が使用されますが、その状態からScroll Viewボタンを押すと、表示がうまく切り替わらないケースがありました。 この問題について、上記のように、defaultView: "scroll"を設定しておくことで回避できました。根本的な解決方法は改めて調査したいと思います。 ...

Traefikでhttpsにリダイレクトさせる

Traefikでhttpsにリダイレクトさせる

概要 以下の記事でTraefikを使ったhttps化したコンテナの運用例を紹介しました。 ただ、(現在は修正済み)http接続をhttps接続にリダイレクトする設定が漏れており、80ポートにアクセスすると、not foundになっていました。 この点の修正方法に関する備忘録です。 変更前 log: # level: DEBUG entryPoints: web: address: :80 websecure: address: :443 api: dashboard: true providers: docker: exposedByDefault: false certificatesResolvers: myresolver: acme: email: aaa@bbb storage: /acme.json caServer: https://acme-v02.api.letsencrypt.org/directory # caServer: https://acme-staging-v02.api.letsencrypt.org/directory httpChallenge: entryPoint: web 変更後 log: # level: DEBUG entryPoints: web: address: :80 http: redirections: entryPoint: to: websecure schema: https permanent: true websecure: address: :443 api: dashboard: true providers: docker: exposedByDefault: false certificatesResolvers: myresolver: acme: email: na.kamura.1263@gmail.com storage: /acme.json caServer: https://acme-v02.api.letsencrypt.org/directory # caServer: https://acme-staging-v02.api.letsencrypt.org/directory httpChallenge: entryPoint: web entryPointsの部分について、以下のようにリダイレクトの設定を追加しています。 ...

Chromeでサイズが大きい動画が再生できない

Chromeでサイズが大きい動画が再生できない

概要 Chromeにおいて、サイズが大きい動画が再生できないことがありました。一方、Safariでは再生できました。 開発者ツールで確認すると、ダウンロードがキャンセルされていました。 ビューア部分は以下のようになっています。 <video controls="controls" preload="none" style="width: 620px; height: 465px;" width="100%" height="100%"> <source src="https://omeka.aws.ldas.jp/files/original/c486fe4ae8d926034678fa11b0d6b2fd55b0e695.mp4" type="video/quicktime" title="undefined"> </video> このHTMLは、以下の記事で紹介した、Omeka S + IIIF Serverの組み合わせによって作成されたものです。 原因 先ほどのhtmlを確認すると、type="video/quicktime"となっており、拡張子はmp4となっていますが、中身は異なる(movファイル?)ことがわかります。 おそらく動画の拡張子のみが変更され、Omeka Sに登録された際、Omeka Sが中身からtypeを指定したように思われます。 Safariで再生できたのも、これが原因かと思われます。 対処法 例えば、macの場合は、以下によりmp4に変換できます。 brew install ffmpeg ffmpeg -i aaa.mov aaa.mp4 まとめ Omeka Sなどで動画ファイルを配信する際の参考になりましたら幸いです。

Omeka SのSetEnv APPLICATION_ENVのproductionとdevelopmentの違い

Omeka SのSetEnv APPLICATION_ENVのproductionとdevelopmentの違い

Omeka Sでのエラー詳細の表示を有効にする手順は次の通りです。この設定を行うことで、「Omeka S has encountered an error」というページに具体的なエラーメッセージと詳細が表示されるようになります。また、PHPレベルのエラーや警告もページ上に表示されるようになります。これは開発中に問題の特定と解決を容易にするためのものですが、セキュリティ上の理由から本番環境では使用しないことが推奨されます。 エラー詳細の表示を有効にする手順 .htaccessファイルを見つける : Omeka Sのインストールフォルダのメインディレクトリに.htaccessファイルがあります。このファイルはWebサーバーの設定をカスタマイズするために使用されるものです。 .htaccessファイルを編集する : .htaccess ファイルをテキストエディタで開きます。 ファイル内の次の行を探します。 SetEnv APPLICATION_ENV "production" * この行を次のように変更します。 SetEnv APPLICATION_ENV "development" 変更を保存してサーバーを再起動する : 変更を保存した後、Webサーバーを再起動する必要がある場合があります。これはサーバーの設定に依存します。 この変更により、Omeka Sは「開発」モードで実行されるようになり、エラーが発生した際には詳細な情報が表示されるようになります。これは問題の診断と解決に非常に役立ちますが、セキュリティ上のリスクも伴うため、公開環境では使用しないようにしてください。

TraefikでHTTPS化した複数コンテナを運用する

TraefikでHTTPS化した複数コンテナを運用する

概要 TraefikでHTTPS化した複数コンテナを運用する方法に関する備忘録です。 https://github.com/traefik/traefik 背景 これまで、jwilder/nginx-proxyとjrcs/letsencrypt-nginx-proxy-companionを使い、以下のような構成で運用していました。 プロキシ version: '3' # proxy services: nginx-proxy: image: jwilder/nginx-proxy container_name: nginx-proxy ports: - "80:80" - "443:443" volumes: - html:/usr/share/nginx/html - dhparam:/etc/nginx/dhparam - vhost:/etc/nginx/vhost.d - certs:/etc/nginx/certs:ro - /var/run/docker.sock:/tmp/docker.sock:ro - /srv/docker/nginx-proxy-with-encrypt/log:/var/log/nginx labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy" restart: always letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: nginx-proxy-lets-encrypt depends_on: - "nginx-proxy" volumes: - certs:/etc/nginx/certs:rw - vhost:/etc/nginx/vhost.d - html:/usr/share/nginx/html - /var/run/docker.sock:/var/run/docker.sock:ro volumes: certs: html: vhost: dhparam: networks: default: external: name: common_link コンテナ 以下は、Djangoの例です。 ...

Omeka S GoogleAnalyticsモジュールの不具合対応

Omeka S GoogleAnalyticsモジュールの不具合対応

概要 Omeka Sにおいて、Google Analyticsを有効するにするためのモジュールとして、Google Analyticsがあります。 https://github.com/Libnamic/Omeka-S-GoogleAnalytics/ 本モジュールを有効化した際、以下のエラーメッセージが表示されるケースがありました。 Undefined index: additional_snippet in (...) /modules/GoogleAnalytics/Module.php on line 316 これについて、以下のIssueも上がっていました。 https://github.com/Libnamic/Omeka-S-GoogleAnalytics/issues/9 本件の対応方法について共有します。 対応方法 以下のように変更します。 https://github.com/Libnamic/Omeka-S-GoogleAnalytics/pull/10/commits/0123ce557d0f38834c5c37fa1ac9c986c87cbc90 具体的には、以下です。 変更前 if (empty($extra_snippet)) { $settings = $this->getServiceLocator()->get('Omeka\Settings'); $settings = $settings->get('googleanalytics', ''); if ($settings != null) $extra_snippet = $settings['additional_snippet']; } if (empty($extra_snippet)) { $settings = $this->getServiceLocator()->get('Omeka\Settings'); $settings = $settings->get('googleanalytics', ''); if ($settings != null) $extra_snippet = $settings['additional_snippet']; } 変更後 if (empty($extra_snippet)) { $settings = $this->getServiceLocator()->get('Omeka\Settings'); $settings = $settings->get('googleanalytics', ''); if ($settings != null) // Assuming this is part of the code where you handle the extra snippet if (isset($settings['additional_snippet']) && !empty($settings['additional_snippet'])) { $extra_snippet = $settings['additional_snippet']; } else { $extra_snippet = ''; // Default value if 'additional_snippet' key is not set } } if (empty($extra_snippet)) { $settings = $this->getServiceLocator()->get('Omeka\Settings'); $settings = $settings->get('googleanalytics', ''); if ($settings != null) // Assuming this is part of the code where you handle the extra snippet if (isset($settings['additional_snippet']) && !empty($settings['additional_snippet'])) { $extra_snippet = $settings['additional_snippet']; } else { $extra_snippet = ''; // Default value if 'additional_snippet' key is not set } } まとめ 上記の変更が完全に正しいか自信はありませんが、プルリクエストも出しておきました。 ...

Amazon S3とRoute 53を使ってリダイレクトする

Amazon S3とRoute 53を使ってリダイレクトする

概要 あるURLから他のURLにリダイレクトさせる必要があり、Amazon S3とRoute 53を使用して実現することができたので、備忘録です。 方法 この方法では、S3バケットを使ってリダイレクトを行い、DNS設定にはRoute 53を使用します。以下にその手順を説明します。 ステップ1: Amazon S3バケットの設定 Amazon S3で新しいバケットを作成します。バケット名はリダイレクトさせたいドメイン名と一致させます(例:example.com)。 バケットのプロパティで「静的ウェブサイトホスティング」を選択します。 「静的ウェブサイトホスティング」のオプションで、「リダイレクト要求」を選び、リダイレクト先のURL(http://example.net など)を入力します。 ステップ2: Route 53でのDNS設定 Route 53で、リダイレクトするドメイン名のホストゾーンを開きます。 新しいレコードセットを作成します。レコードのタイプは A を選択します。 「エイリアス」を「はい」に設定します。 エイリアスターゲットとして、ステップ1で設定したS3バケットの静的ウェブサイトホスティングのエンドポイントを選択します(例:example.com.s3-website-us-east-1.amazonaws.com)。 これで、指定したドメインにアクセスがあった場合、設定したURLにリダイレクトされるようになります。この方法は、簡単でありながら効果的にドメインから別のURLへのリダイレクトを実現することができます。 まとめ 参考になりましたら幸いです。

Docker版のOmeka SでCORS対応を行う

Docker版のOmeka SでCORS対応を行う

概要 Docker版のOmeka Sで、以下の記事のようにCORS対応を実施した際、サーバエラーが発生しました。その備忘録を記載します。 Dockerfile 以下のようなDockerfileを対象とします。 FROM php:apache LABEL maintainer="Satoru Nakamura <na.kamura.1263@gmail.com>" RUN a2enmod rewrite ENV DEBIAN_FRONTEND noninteractive RUN apt-get -qq update && apt-get -qq -y upgrade RUN apt-get install -y \ zlib1g-dev \ libpng-dev \ libjpeg-dev \ libfreetype6-dev \ imagemagick \ unzip \ wget # PHP extensions RUN docker-php-ext-install -j$(nproc) iconv pdo pdo_mysql mysqli gd RUN docker-php-ext-configure gd --with-jpeg=/usr/include/ --with-freetype=/usr/include/ # Download Omeka-s ARG version=4.1.1 RUN wget https://github.com/omeka/omeka-s/releases/download/v${version}/omeka-s-${version}.zip -O /var/www/omeka-s-${version}.zip \ && unzip -q /var/www/omeka-s-${version}.zip -d /var/www/ \ && rm /var/www/omeka-s-${version}.zip \ && rm -rf /var/www/html/ \ && mv /var/www/omeka-s/ /var/www/html/ COPY ./.htaccess /var/www/html/.htaccess # Configure volumes and permissions COPY ./database.ini /var/www/html/volume/config/ RUN mkdir -p /var/www/html/volume/files/ \ && rm /var/www/html/config/database.ini \ && ln -s /var/www/html/volume/config/database.ini /var/www/html/config/database.ini \ && rm -Rf /var/www/html/files/ \ && ln -s /var/www/html/volume/files/ /var/www/html/files \ && chown -R www-data:www-data /var/www/html/ \ && find /var/www/html/volume/ -type f -exec chmod 600 {} \; VOLUME /var/www/html/volume/ CMD ["apache2-foreground"] 原因と対策 以下を追記する必要がありました。 ...