メインコンテンツへスキップ

Pocketに保存したページを読み上げてPodcastとして配信

PocketへWebページを保存するとページの本文らしき部分を抽出し、Text-to-Speechでそれを読み上げた音声ファイルを作り、プライベートなPodcastとして配信するしかけを作った。

音声合成エンジンとしてVOICEVOXも試したが、手元の環境で安定して動作させるところまでいけず断念。

システムの概要
#

flowchart TD   
	Podcastアプリ[/Podcastアプリ\] --> |参照|nginx
	Pocket[/Pocket\] --> |新規保存|IFTTT
	IFTTT --> |Webhooks|nginx
	subgraph システムの概要
		nginx
		nginx --> |PodcastのRSSフィード参照|index.rss
		nginx --> |PocketしたURLを通知|sinatra
		subgraph PodcastのRSSフィード生成
			mp3 --> |参照|index.rss
			mp3 --> |参照|dropcaster
			cron --> |5分毎|dropcaster --> |存在するmp3からRSSフィード生成|index.rss
		end
		subgraph 音声ファイル生成
			sinatra
			sinatra --> readability
			readability --> |ページの本文|texttospeech
			texttospeech --> |本文からmp3生成|mp3[(mp3)]
		end
	end
	

使用したライブラリやサービス
#

関連記事

国立国会図書館サーチAPIでISBNから書誌情報と書影を取得する

国立国会図書館サーチAPIは個人・非営利団体等がデータ利用により利益を得ない場合は、利用申請不要で利用できる。 APIのご利用について « 国立国会図書館サーチについて ISBNをキーにして書誌情報を取得するのはOpenSearchがお手軽なようだ。 API仕様の概要 « 国立国会図書館サーチについて https://iss.ndl.go.jp/api/opensearch?isbn=ISBN 結果はXML(RSS)で得られる。 <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:dcndl="http://ndl.go.jp/dcndl/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <channel> <title>9784253265218 - 国立国会図書館サーチ OpenSearch</title> <link>https://iss.ndl.go.jp/api/opensearch?isbn=9784253265218</link> <description>Search results for isbn=9784253265218 </description> <language>ja</language> <openSearch:totalResults>2</openSearch:totalResults> <openSearch:startIndex>1</openSearch:startIndex> <openSearch:itemsPerPage/> <item> <title>海が走るエンドロール = Umi ga hashiru Endroll</title> <link>https://iss.ndl.go.jp/books/R100000002-I031602764-00</link> <description> <![CDATA[<p>1,秋田書店,9784253265218</p> <ul><li>タイトル: 海が走るエンドロール = Umi ga hashiru Endroll</li> <li>タイトル(読み): ウミ ガ ハシル エンド ロール</li> <li>責任表示: たらちねジョン 著,</li> <li>シリーズ名: BONITA COMICS</li> <li>NDC(10): 726.1</li> <li>NDC(9): 726.1</li> </ul>]]> </description> <author>たらちねジョン 著,たらちね, ジョン,</author> <category>本</category> <guid isPermaLink="true">https://iss.ndl.go.jp/books/R100000002-I031602764-00</guid> <pubDate>Wed, 29 Sep 2021 09:00:00 +0900</pubDate> <dc:title>海が走るエンドロール = Umi ga hashiru Endroll</dc:title> <dcndl:titleTranscription>ウミ ガ ハシル エンド ロール</dcndl:titleTranscription> <dc:creator>たらちね, ジョン</dc:creator> <dcndl:creatorTranscription>タラチネ, ジョン</dcndl:creatorTranscription> <dcndl:volume>1</dcndl:volume> <dcndl:seriesTitle>BONITA COMICS</dcndl:seriesTitle> <dc:publisher>秋田書店</dc:publisher> <dc:date>2021.8</dc:date> <dcterms:issued xsi:type="dcterms:W3CDTF">2021</dcterms:issued> <dcndl:price>600円</dcndl:price> <dc:extent>158p ; 19cm</dc:extent> <dc:identifier xsi:type="dcndl:ISBN">9784253265218</dc:identifier> <dc:identifier xsi:type="dcndl:NDLBibID">031602764</dc:identifier> <dc:identifier xsi:type="dcndl:JPNO">23585081</dc:identifier> <dc:identifier xsi:type="dcndl:TOHANMARCNO">07471697</dc:identifier> <dcndl:genre>漫画</dcndl:genre> <dc:subject xsi:type="dcndl:NDLC">Y84</dc:subject> <dc:subject xsi:type="dcndl:NDC10">726.1</dc:subject> <dc:subject xsi:type="dcndl:NDC9">726.1</dc:subject> <dc:description>機器種別 : 機器不用</dc:description> <dc:description>キャリア種別 : 冊子</dc:description> <dc:description>表現種別 : テキスト</dc:description> <dc:description>表現種別 : 静止画</dc:description> <dc:description>NDC(9版)はNDC(10版)を自動変換した値である。</dc:description> <rdfs:seeAlso rdf:resource="http://id.ndl.go.jp/bib/031602764"/> <rdfs:seeAlso rdf:resource="https://opac.lib.city.yokohama.lg.jp/opac/OPP1500?SELDATA=TOSHO&amp;SSNO=3-0500928436"/> </item> <item> <title>海が走るエンドロール = Umi ga hashiru Endroll</title> <link>https://iss.ndl.go.jp/books/R100000098-I000372329-00</link> <description> <![CDATA[<p>1,秋田書店,9784253265218</p> <ul><li>タイトル: 海が走るエンドロール = Umi ga hashiru Endroll</li> <li>タイトル(読み): ウミ ガ ハシル エンド ロール</li> <li>責任表示: たらちねジョン 著,</li> <li>シリーズ名: BONITA COMICS</li> <li>NDC(9): 726.1</li> </ul>]]> </description> <author>たらちねジョン 著,,</author> <category>本</category> <guid isPermaLink="true">https://iss.ndl.go.jp/books/R100000098-I000372329-00</guid> <dc:title>海が走るエンドロール = Umi ga hashiru Endroll</dc:title> <dcndl:titleTranscription>ウミ ガ ハシル エンド ロール</dcndl:titleTranscription> <dc:creator></dc:creator> <dcndl:volume>1</dcndl:volume> <dcndl:seriesTitle>BONITA COMICS</dcndl:seriesTitle> <dc:publisher>秋田書店</dc:publisher> <dc:date>2021.08</dc:date> <dcterms:issued xsi:type="dcterms:W3CDTF">2021-08</dcterms:issued> <dcndl:price>600円</dcndl:price> <dc:extent>158p ; 19cm</dc:extent> <dc:identifier xsi:type="dcndl:ISBN">9784253265218</dc:identifier> <dc:identifier xsi:type="dcndl:JPNO">23585081</dc:identifier> <dc:subject xsi:type="dcndl:NDC9">726.1</dc:subject> <dc:description>単行本全巻ID : C451417</dc:description> <dc:description>マンガ単行本備考 : 機器種別 : 機器不用 / キャリア種別 : 冊子 / 表現種別 : テキスト / 表現種別 : 静止画 / NDC(9版)はNDC(10版)を自動変換した値である。</dc:description> <dc:description>ID : M852583</dc:description> <dc:description>登録番号(館固有割り振りID):031602764(国立国会図書館)</dc:description> <rdfs:seeAlso rdf:resource="https://mediaarts-db.bunka.go.jp/id/M852583"/> </item> </channel> </rss> 書影はhttps://iss.ndl.go.jp/thumbnail/ISBNで得られる。

2ホップリンク

ホップ数 # flowchart LR B1 & B2 --> A G --> O1 H --> O1 A --> O1 & O2 O2 --> E F --> O2 B1:::hop1 B2:::hop1 O1:::hop1 O2:::hop1 F:::hop2 G:::hop2 H:::hop2 style A fill:#f9f,stroke:#333,stroke-width:4px classDef hop1 fill:#a9a classDef hop2 fill:#f96 ホップ数とは自身から任意のページまでたどり着くまでのリンクの数である。 このようなリンク関係がある場合、ページAから見て、B1 B2 O1 O2は1ホップリンクと呼ばれる。 2ホップリンクの意味 # このため、上記のリンク関係で言えば、ページAから見たG H E Fは2ホップリンクとなる。 Scrapboxでは2ホップリンクの内、アウトゴーイングリンクのページへリンクしているページ、つまり、 AからリンクしているO1へリンクしている Gと H AからリンクしているO2へリンクしている F を関連リンクとして表示している。これは、 A→C, B→Cというリンクが存在するとき、AとBの間にはなんらかの関連があると考えてよい。 「和歌山」→「みかん」、「愛媛県」→「みかん」 ならば「和歌山県」と「愛媛県」はみかんつながりになっているわけだし、 「増井」→「Rubyプログラミング」、「高林」→「Rubyプログラミング」 ならば「増井」⇔「高林」は意味がある。 出典: 2ホップリンクの考察 - 増井俊之 上記の考え方に基づく仕様であり、本サイトでもQuartzを拡張し同様の2ホップリンクを表示している(各ページ配下の「関連リンク」) QuartzにScrapbox的な2ホップリンクを追加する Obsidiaのリンク表示 参考情報 # 2ホップリンクの考察 - 増井俊之

Hugo

オープンソースの静的サイトジェネレーター。go言語で記述されておりページ生成の速度が速くカスタマイズ性が高い。 The world’s fastest framework for building websites | Hugo Hugo関連のノート # Hugoメモ Hugoのショートコードをうまく使い回す方法 Hugoのローカルサーバでページが表示されない場合 Hugoで本文の先頭画像をアイキャッチとして使用する Hugoでローカルサーバのみ実行する処理を書く方法 Hugoで楽譜を描画する(abcjs) Hugoのレンダーフックを使ったMermaidの利用 Hugoのショートコード入力を支援するChrome拡張 Hugoでイメージギャラリーを表示するhugo-shortcode-gallery Hugoで写真をリサイズしExif情報を表示する

Hugoのレンダーフックを使ったMermaidの利用

独自構文のテキストから、各種のダイアグラムを生成できるMermaidという便利なライブラリがありますが、現時点ではHugoでサポートされていません。 このため通常、 独自のショートコードを作成する 言語としてmermaidを指定したコードブロックを使用し、mermaidでlanguage-mermaidクラスの要素を変換対象として指定する などの実装が多かったと思うのですが、公式サイトを調べていたところv0.93.0からサポートされたcodeブロックに対するレンダーフックを用いた例が載っており、よりスマートに実装できそうでした。 ここでは公式サイトのレンダーフックを用いたMermaidの組み込み方法を説明します。 レンダーフックの追加 # codeブロックに対するレンダーフックを定義するには、 layouts/_default/_markup/render-codeblock-言語名.html というファイルを作成します。今回ファイル名を、 layouts/_default/_markup/render-codeblock-mermaid.html とすることで、 ```mermaid flowchart LR Start --> Stop ``` というような、言語にmermaidを指定したコードブロックに対してレンダーフックが起動します。レンダーフックの内容は以下の通りです。 <div class="mermaid"> {{- .Inner | safeHTML }} </div> {{ .Page.Store.Set "hasMermaid" true }} <div class="mermaid">でコードブロックの内容を囲む Mermaidの記述があることを表すhasMermaidフラグをtrueにする テンプレートの修正 # テンプレートについては、 layouts/_default/baseof.html layouts/_default/single.html など、Mermaidのコンテンツを表示したいテンプレートへ以下の内容を追加します。私の場合、通常エントリでのみ表記できれば良いためsingle.htmlへ追加しました。 {{ if .Page.Store.Get "hasMermaid" }} <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script> <script> mermaid.initialize({ startOnLoad: true }); </script> {{ end }} このコードはhasMermaidフラグがtrueの場合のみ、MermaidのJavascscript読み込みと初期化を行います。これにより、Mermaidの記述がないページではコードが展開されずムダな処理を抑止できるわけです。 上記処理をテンプレートへ追記する場合の注意点としては、.Contentが出現する箇所より下へ書く必要があるということです。Hugoでは.Contentが実行(評価)されるまではレンダーフックは処理されないためです。 参考サイト # mermaid.js で Markdown 中に UML 図を埋め込む - まくまくHugoノート Markdown Render Hooks mermaid - Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.

Webページから本文らしき部分を抽出する

さまざまなパターンの日本語文章をデータとして欲しいケースがあったので、指定したURLから本文らしき内容を抽出するスクリプトを書いた。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 require 'playwright' require 'readability' require 'html2text' # 指定したURLから本文らしき内容を抽出して返却する def html2text(url) Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright| playwright.chromium.launch(headless: true) do |browser| begin page = browser.new_page page.goto(url, waitUntil: 'load') doc = Readability::Document.new(page.content) sleep 1 return {:title => page.title, :content => Html2Text.convert(doc.content) } rescue return {:title => nil, :content => nil } end end end end url = ARGV.shift doc = html2text(url) puts "#{doc[:title]}\n#{doc[:content]}" Javascriptでコンテンツを生成するページに対応するためPlaywrightを使用。 使用したライブラリ # cantino/ruby-readability: Port of arc90’s readability project to Ruby YusukeIwaki/playwright-ruby-client: Playwright client for Ruby soundasleep/html2text_ruby: A Ruby component to convert HTML into a plain text format.

D2 Declarative Diagramming

terrastruct/d2: D2 is a modern diagram scripting language that turns text to diagrams. テキストからダイアグラムを生成するツール。類似のツールとしてはMermaid、GraphViz、PlantUMLなどがあり、以下のサイトでこれらのツールで同じダイアグラムを書く場合の比較が可能。このサイトはD2開発元によるものらしい。 Text to diagram テキストと出力の例 # 公式サイトからの引用 # Actors hans: Hans Niemann defendants: { mc: Magnus Carlsen playmagnus: Play Magnus Group chesscom: Chess.com naka: Hikaru Nakamura mc -> playmagnus: Owns majority playmagnus <-> chesscom: Merger talks chesscom -> naka: Sponsoring } # Accusations hans -> defendants: 'sueing for $100M' # Offense defendants.naka -> hans: Accused of cheating on his stream defendants.mc -> hans: Lost then withdrew with accusations defendants.chesscom -> hans: 72 page report of cheating インストール # d2/INSTALL.md at master · terrastruct/d2 Macの場合はbrew install d2でOK