「フィルターされたNotionページによるMediaWiki」の版間の差分

Notion-MW
 
Notion-MW
 
(同じ利用者による、間の6版が非表示)
21行目: 21行目:
== データベース部分の設計 ==
== データベース部分の設計 ==


<div class="res-img">[[File:5DD93D25-3A2D-4987-B89C-AB487E67C355.jpg]]</div>
<div class="res-img">https://turgenev.cloudfree.jp/mw1/imgs/notion-mw-db.jpg</div>


このような感じで、「使うNotionページへのリンク」「スクリプトによる変換&amp;更新の対象にするかどうか」(←これは今はもう使われていない)「MediaWikiでのID」「MediaWikiでのタイトル」「MediaWikiでのカテゴリー」「サイトの更新日時(=スクリプトによってMediaWiki側での編集が完了したタイミング)」をデータベースとして保持している。
このような感じで、「使うNotionページへのリンク」「スクリプトによる変換&amp;更新の対象にするかどうか」(←これは今はもう使われていない)「MediaWikiでのID」「MediaWikiでのタイトル」「MediaWikiでのカテゴリー」「サイトの更新日時(=スクリプトによってMediaWiki側での編集が完了したタイミング)」をデータベースとして保持している。
37行目: 37行目:
大まかな流れは以下の通り。
大まかな流れは以下の通り。


* 上記データベースの内容をNotion APIから取得する。以下、各行ごとに処理。
# 上記データベースの内容をNotion APIから取得する。以下、各行ごとに処理。
* ページの内容を取得し、黄色い見出しだけ残す変換を行う。Notionのブロックのリストができる
# ページの内容を取得し、黄色い見出しだけ残す変換を行う。Notionのブロックのリストができる
* notion&#45;to&#45;mdのblocksToMarkdownでマークダウン形式に変換する。
# notion&#45;to&#45;mdのblocksToMarkdownでマークダウン形式に変換する。
* いくつか前処理を行う。
# いくつか前処理を行う。
* pandocを用いてMediaWikiに変換する。
# pandocを用いてMediaWikiに変換する。
* いくつか後処理(整形)を行う
# いくつか後処理(整形)を行う
* 完成した記事データをMediaWiki APIで投稿する。
# 完成した記事データをMediaWiki APIで投稿する。


その他、ページのリネーム、新規作成時のIDの反映(<code>&#45;</code>を数字に変える)、既存の記事を新規作成しようとした場合のエラーなど、前後に多少の処理がある。
その他、ページのリネーム、新規作成時のIDの反映(<code>&#45;</code>を数字に変える)、既存の記事を新規作成しようとした場合のエラーなど、前後に多少の処理がある。
64行目: 64行目:
=== pandocの実行 ===
=== pandocの実行 ===


<pre class="dummy_str_python">cp.spawn(&quot;pandoc&quot;, [&quot;-f&quot;,&quot;gfm&quot;,&quot;-t&quot;, &quot;mediawiki&quot;, &quot;--shift-heading-level-by=1&quot;]);</pre>
<syntaxhighlight lang="python">cp.spawn("pandoc", ["-f","gfm","-t", "mediawiki", "--shift-heading-level-by=1"]);</syntaxhighlight>
<code>gfm</code>(Github Flavored Markdown)から<code>mediawiki</code>に変換する。<code>&#45;&#45;shift&#45;heading&#45;level&#45;by&#61;1</code>は、[https://www.mediawiki.org/wiki/Help:Formatting/ja Help&#58;書式整形 &#45; MediaWiki]にもある通り、MediaWikiの記事内ではレベル1の見出しは非推奨だからである。
<code>gfm</code>(Github Flavored Markdown)から<code>mediawiki</code>に変換する。<code>&#45;&#45;shift&#45;heading&#45;level&#45;by&#61;1</code>は、[https://www.mediawiki.org/wiki/Help:Formatting/ja Help&#58;書式整形 &#45; MediaWiki]にもある通り、MediaWikiの記事内ではレベル1の見出しは非推奨だからである。


96行目: 96行目:


上記のような良い感じのMediaWikiに変換する目的と、単純にできたばかりでバグが多いため、色々変えている。
上記のような良い感じのMediaWikiに変換する目的と、単純にできたばかりでバグが多いため、色々変えている。
=== リポジトリ ===
[https://github.com/ge9/notion-to-md-mediawiki Githubリポジトリ]を作成したので、最新情報はそちらから。


=== 数式関連 ===
=== 数式関連 ===
117行目: 121行目:
コードにおいて、言語がpythonなどの良く知られたものに設定されていると、pandocによって<strong>syntaxhighlight</strong>タグに変えられてしまう。今回はSyntaxHightlight拡張機能が無効のMediaWikiを使っているので、言語にダミー文字列を付加する(付加ではなくダミー文字列だけにしても変わらないが、情報を落とすのは勿体ない気がしたので)。またpandoc側の問題で<code>visual basic</code>のように言語名にスペースが入っていると<code>visual</code>だけになってしまうようなので、スペースをアンダースコアに置換。
コードにおいて、言語がpythonなどの良く知られたものに設定されていると、pandocによって<strong>syntaxhighlight</strong>タグに変えられてしまう。今回はSyntaxHightlight拡張機能が無効のMediaWikiを使っているので、言語にダミー文字列を付加する(付加ではなくダミー文字列だけにしても変わらないが、情報を落とすのは勿体ない気がしたので)。またpandoc側の問題で<code>visual basic</code>のように言語名にスペースが入っていると<code>visual</code>だけになってしまうようなので、スペースをアンダースコアに置換。


<pre class="dummy_str_python">language = &quot;dummy_str_&quot;+language?.replace(&quot; &quot;, &quot;_&quot;);//for MediaWiki without SyntaxHightlight extension</pre>
<syntaxhighlight lang="python">language = "dummy_str_"+language?.replace(" ", "_");//for MediaWiki without SyntaxHightlight extension</syntaxhighlight>
<span id="notion&#45;to&#45;mdts内"></span>
<span id="notion&#45;to&#45;mdts内"></span>
=== <code>notion&#45;to&#45;md.ts</code>内 ===
=== <code>notion&#45;to&#45;md.ts</code>内 ===
127行目: 131行目:
解説が面倒なのでコードだけとりあえず。
解説が面倒なのでコードだけとりあえず。


<pre class="dummy_str_javascript">//`のみcodeに変え、```は```のままという仕様の場合
<syntaxhighlight lang="javascript">//`のみcodeに変え、```は```のままという仕様の場合
           if (content.type === &quot;text&quot;){
           if (content.type === "text"){
             if (type == &quot;code&quot;){
             if (type == "code"){
               //```の内部では&lt;&gt;は無効なので本来は不要だが、detailsまわりが修正されるまで、&lt;&gt;を最強エスケープの対象としておく。
               //```の内部では<>は無効なので本来は不要だが、detailsまわりが修正されるまで、<>を最強エスケープの対象としておく。
               //無事修正されたので、対象外に
               //無事修正されたので、対象外に
               //plain_text =  plain_text.replace(/[&lt;&gt;]/g, (c) =&gt;&quot;m_esc_&quot; + c.charCodeAt(0)+&quot;_m&quot;)
               //plain_text =  plain_text.replace(/[<>]/g, (c) =>"m_esc_" + c.charCodeAt(0)+"_m")
               //バッククォートはmarkdownの```の中でも有害になる珍しい文字であるが、外側と対処法が異なる。
               //バッククォートはmarkdownの```の中でも有害になる珍しい文字であるが、外側と対処法が異なる。
               //markdownでコード内に`を書くには、両側をそれより多い`で囲うしかなく(\`や&amp;#96;ではそれがそのまま表示されてしまう)、その実装が面倒である。
               //markdownでコード内に`を書くには、両側をそれより多い`で囲うしかなく(\`や&#96;ではそれがそのまま表示されてしまう)、その実装が面倒である。
               //そこで、最強エスケープをかけて、MediaWikiに変換してから元に戻す。ちなみにMediaWikiでは`は特殊文字ではないのでエスケープ文字ではなくベタ書きに戻す。
               //そこで、最強エスケープをかけて、MediaWikiに変換してから元に戻す。ちなみにMediaWikiでは`は特殊文字ではないのでエスケープ文字ではなくベタ書きに戻す。
               plain_text =  plain_text.replace(/`/g, (c) =&gt; &quot;m_esc_&quot; + c.charCodeAt(0)+&quot;_m&quot;)
               plain_text =  plain_text.replace(/`/g, (c) => "m_esc_" + c.charCodeAt(0)+"_m")
                
                
             }else{//テキストエリア
             }else{//テキストエリア
               //以下は、MediaWikiの特殊文字であるにもかかわらずpandocがそのままべた書きしてしまう文字。最強エスケープが必要。
               //以下は、MediaWikiの特殊文字であるにもかかわらずpandocがそのままべた書きしてしまう文字。最強エスケープが必要。
               //これらはMarkdownの```およびMediaWikiのpreの内側では無害である。(外側では特殊文字であるものとそうでないものがある。)
               //これらはMarkdownの```およびMediaWikiのpreの内側では無害である。(外側では特殊文字であるものとそうでないものがある。)
               plain_text = plain_text.replace(/[=;:#*'{}~\-\[\]]/g, (c) =&gt; &quot;m_esc_&quot; + c.charCodeAt(0)+&quot;_m&quot;)
               plain_text = plain_text.replace(/[=;:#*'{}~\-\[\]]/g, (c) => "m_esc_" + c.charCodeAt(0)+"_m")
                
                
               //これらは、Markdownのテキストエリアでは特殊文字だが、MediaWikiの特殊文字ではないあるいはpandocがちゃんと扱えるもの。
               //これらは、Markdownのテキストエリアでは特殊文字だが、MediaWikiの特殊文字ではないあるいはpandocがちゃんと扱えるもの。
               //(ただし、&quot;.&quot;(ピリオド)のみ、「リンクテキストもURLになっているリンク及びcode内に書かれた(リンクでない)URLがpandocの変換でおかしくなるのを防ぐ」という目的で入れている。)
               //(ただし、"."(ピリオド)のみ、「リンクテキストもURLになっているリンク及びcode内に書かれた(リンクでない)URLがpandocの変換でおかしくなるのを防ぐ」という目的で入れている。)
               //この変換は先ほどの最強エスケープより後でなければいけない。(#が最強エスケープされるのを防ぐため)(もちろん同時でもいい)
               //この変換は先ほどの最強エスケープより後でなければいけない。(#が最強エスケープされるのを防ぐため)(もちろん同時でもいい)
               //スラッシュでのエスケープだと`&lt;`でバグったことがあった(おそらくpandocのせい)ので、&amp;#xx;を使用
               //スラッシュでのエスケープだと`<`でバグったことがあった(おそらくpandocのせい)ので、&#xx;を使用
               plain_text = plain_text.replace(/[`$+&amp;&lt;&gt;\\.]/g, (c) =&gt; &quot;&amp;#&quot; + c.charCodeAt(0)+&quot;;&quot;)
               plain_text = plain_text.replace(/[`$+&<>\\.]/g, (c) => "&#" + c.charCodeAt(0)+";")


               //2つ以上の連続する空白文字は(そのように表示したい特別な理由があると考えて)&amp;nbsp;に変換。これは&amp;のエスケープより後である必要がある。
               //2つ以上の連続する空白文字は(そのように表示したい特別な理由があると考えて)&nbsp;に変換。これは&のエスケープより後である必要がある。
               plain_text = plain_text.replace(/ {2,}/g, (c) =&gt; c.split('').map(function() { return '&amp;nbsp;'; }).join(''))
               plain_text = plain_text.replace(/ {2,}/g, (c) => c.split('').map(function() { return '&nbsp;'; }).join(''))


               //notion-to-mdがブロック内改行に対応していないので対応。nbspへの変換より後に行う。
               //notion-to-mdがブロック内改行に対応していないので対応。nbspへの変換より後に行う。
               plain_text = plain_text.replace(/\n/g, &quot; \n&quot;)
               plain_text = plain_text.replace(/\n/g, " \n")
             }
             }
             //また、&quot;も、mediawikiでの特殊文字ではないが、pandocでは&amp;quot;に変換される。
             //また、"も、mediawikiでの特殊文字ではないが、pandocでは&quot;に変換される。
             //ベタ書きでも表示には影響ないが、span id=&quot;&quot;の中身に生のダブルクォーテーションが入ってしまう副作用があるし、その他問題が起きる可能性がある。
             //ベタ書きでも表示には影響ないが、span id=""の中身に生のダブルクォーテーションが入ってしまう副作用があるし、その他問題が起きる可能性がある。
             //下記のように最強エスケープすればそのまま書けるが、&amp;quot;を&quot;にしてデータ量を削減するより安全を取ったほうが良さそうである。
             //下記のように最強エスケープすればそのまま書けるが、&quot;を"にしてデータ量を削減するより安全を取ったほうが良さそうである。
             //ちなみに1文字減らすために最強エスケープから&amp;#34;に戻す方法もあるが、&amp;quot;のほうが自動でspan id=&quot;&quot;の中身から除去されるようなのでそのほうが良さそう。
             //ちなみに1文字減らすために最強エスケープから&#34;に戻す方法もあるが、&quot;のほうが自動でspan id=""の中身から除去されるようなのでそのほうが良さそう。
             //plain_text = plain_text.replace(/[&quot;]/g, (c) =&gt; &quot;m_esc_&quot; + c.charCodeAt(0)+&quot;_m&quot;)
             //plain_text = plain_text.replace(/["]/g, (c) => "m_esc_" + c.charCodeAt(0)+"_m")
           }</pre>
           }</syntaxhighlight>
==== ブロック内改行 ====
==== ブロック内改行 ====