はてなブログにおける脚注メモ(Markdown方式)

Markdownの脚注記法に対応しました

はてなブログの記事編集画面で利用できるMarkdownモードで、Makrndownの脚注記法に対応しました。

 :

今回サポートした脚注は、PHP Markdown Extra由来の記法です。

はてな記法Markdownの脚注に互換性はなく、それぞれ個別にフォーマットされます。


Footnotes

Footnotes work mostly like reference-style links. A footnote is made of two things: a marker in the text that will become a superscript number; a footnote definition that will be placed in a list of footnotes at the end of the document.

いままでのはてなダイアリー由来の脚注*1Markdown 方式の脚注1とは残念ながら全く別個なのよね。書く側が統一しなきゃいけないので、なんだかなあと思う。はてなダイアリーの脚注で表記しておけば、マウスポインタを当てたときに脚注の内容が表示されるので便利、でも Markdown 方式の脚注では表示されない。結局、はてなブログでは旧来のはてな記法で脚注しておくほうが良いと思う。


  1. こっちがMarkdown方式の脚注

*1:こっちがはてなダイアリー由来の脚注

はてなブログでブログ外リンクを別ウィンドウ/タブで開くように(JS解説付き)

ポイント

はてなブログで全てのリンクを別ウィンドウで開くならば <base target="_blank"> を設定しておけば済むのだけど、しかしこの状況でははてなブログ内のリンクまで別ウィンドウで開いてしまう。これはウザい。ってことで先人の知恵を借りた。けど若干のチューニングをしたのでメモっておく。

どうするの?

はてなブログの「設定>デザイン>カスタマイズ>ヘッダ」の「タイトル下」に HTML を書く欄があるので、そこに

<script>window.addEventListener("DOMContentLoaded",()=>document.querySelectorAll("a[href^='http']:not([href*='"+location.hostname+"'])").forEach(anchor=>anchor.setAttribute('target','_blank');));</script>

をコピペして「変更を保存する」ボタンを押して保存。これでおk。

スクリプトを読みやすくして解釈していく

<script>
window.addEventListener("DOMContentLoaded", () => {
  document.querySelectorAll("a[href^='http']:not([href*='" + location.hostname + "'])").forEach( (anchor) => {
    anchor.setAttribute('target', '_blank');
  })
});
</script>

1. document.querySelectorAll を解釈

document.querySelectorAll の引数は CSS セレクタで指定します。その中身である

"a[href^='http']:not([href*='" + location.hostname + "'])"

を解釈していきましょう。

まず a[href^='http'] から…との記事を書いていたのですが、先に location.hostname から。location.hostname は「現在ページURLのホスト名」の文字列です(参考:location.hostname-JavaScriptリファレンス)。ここでは本ブログのホスト名 riocampos-tech.hatenablog.com になります。次に、その前後をみると '" + location.hostname + "' とあります。シングルクオートとダブルクオートとが並んでいて読みづらい上、なぜシングルクオートとダブルクオートとが並んでいるのか?と悩んでしまいます。結論から言ってしまうと、+ location.hostname の前のダブルクオートは冒頭 a から続く文字列を閉じるものです。CSS セレクタは当然ながら文字列なので、文字列の中にさらに文字列であるURLを引用するにはシングルクオートを使う必要があります。しかし文字列の中に引用を入れるのは従来の JavaScript では不可能だった1ので、シングルクオートとダブルクオートとを並べることになるわけです。ややこしいので、先に location.hostname の部分を文字列にしましょう。すると[href*='riocampos-tech.hatenablog.com'] という文字列になります。CSS セレクタ全体を見直してみると

"a[href^='http']:not([href*='riocampos-tech.hatenablog.com'])"

となりました。では改めて解釈していきましょう。

まず a[href^='http'] は「a 要素のうち href 属性の値が文字列 http から始まる要素」という意味です(参考:E[foo^="bar"]-CSS3リファレンス)。

次に :not(〜) は「引数(〜)に該当しない要素」なので a[href^='http']:not(〜) は「a 要素のうち href 属性の値が文字列 http から始まり、且つ引数(〜)に該当しない要素」という意味になります2(参考:E:not(s)-CSS3リファレンス)。で、引数の部分は [href*='riocampos-tech.hatenablog.com'] となっています。ここは「href 属性の値が文字列 riocampos-tech.hatenablog.com を含む要素」という意味です(参考:E[foo*="bar"]-CSS3リファレンス)。

まとめると「a 要素のうち href 属性の値が文字列 http から始まり、且つhref 属性の値が文字列 riocampos-tech.hatenablog.com含まない要素」が document.querySelectorAll で選び出されることが分かります。

2. forEach 以降を解釈

(いずれ書きます)

先人の情報

この記事の内容は、基本的には一つ目のリンク先のままなのだけど、空白や改行を削除したり、jQuery のリンク先をはてな内にしたり、<script>タグの表現を変更したり jQuery から ES5 へ変更したり、ヘッダじゃなくフッタへの設定に変更したり、 function を Fat arrowにしたりしてます。

補足

じつは Document.querySelectorAll() の返値 NodeListNodeList.forEach() を使えなかったのですよ。最近のブラウザは使えるようになったようなので、それで使ってます。古いブラウザ対応は無視w (参考:NodeList.prototype.forEach() - Web APIs | MDN

はてなブログスマホビューのとき

でもね。iPhoneスマホビューで見たときには別タブで開いてくれないのです…なんでなの。 jQuery$(document).ready なのがスマホだとダメなときがあるという話を読んで「これは jQuery を止めちゃおう」と思って ES5 に書き換えたのにな。 HTML 読み込みなどの設定はスマホ用サイトだと別設定になっているし、はてなブログ PRO じゃないとスマホ用の HTML を書けないということに気付きました…うーむ。2年まとめ払いでも月額600円だから、はてなダイアリープラスの価格より大幅値上げに感じてしまうのよね…。 まあそれぞれのブログの末尾に

<script>document.querySelectorAll("a[href^='http']:not([href*='"+location.hostname+"'])").forEach(anchor=>anchor.setAttribute('target','_blank'))</script>

って毎回追記しておいてもいいのだけどね。面倒だけど3

なお、ブログ末尾に上記のスクリプトを追記するのであれば、はてなブログの設定のスクリプト

<script>window.addEventListener("DOMContentLoaded",()=>document.querySelectorAll("a[href^='http']:not([href*='"+location.hostname+"'])").forEach(anchor=>{if(anchor.getAttribute('target')!=='_blank')return;anchor.setAttribute('target','_blank');}));</script>

のように target="_blank" がある場合にはスクリプトを実行しないようにしておいたほうがいいかなと思います。


  1. いまはテンプレートリテラル``を使えば読みやすく書ける。今回の場合だと`a[href^='http']:not([href*='${location.hostname}'])`

  2. セレクタを続けて書くとandになると思われます。

  3. セコイねw

はてなブログ記事を改善するためのメモ

はてなブログを将来改善するためのメモが投げ込まれてます

今回はちょっと古めの記事ばかりですが、どうせチューニングしてないので今なら古め記事でも大いに役立つはずなのです。

…とはいえ、jQuery じゃなく ES2018 で書きたいものですなあ。

ってことでコレ欲しいな。(pdf 版を買いました→ JavaScript コードレシピ集 | Gihyo Digital Publishing … 技術評論社の電子書籍

JavaScript コードレシピ集

JavaScript コードレシピ集

↑の著者blog:

「気になる展覧会」記事での表をなんとかしたい

ソートしたり限定したり。これが役立つはず。

(2019/2/26追記:ソートは入れずに必要部分のみ目立つようにした。 「気になる展覧会」記事の表部分に使ったJavaScriptのメモ - 別館 子子子子子子(ねこのここねこ)はてブロ部

はてなブログでも、はてブホッテントリのRSSフィードリーダを使いたい(未完

本館も引っ越ししました

はてダが使えなくなる日が近いので、この別館だけではなく本館も子子子子子子(ねこのここねこ)はてブロ部としてはてなブログへ引っ越ししました。 しかし、以前使っていたサイドバーが簡単に使えないのが気に入らない。特にRSSフィードリーダを使う設定が無いので、以前から使っていたホッテントリ表示が出来ない。ぶつぶつ。

先人の知恵

サイドバーにRSSを表示させるツールに関してはこちらで情報を得ました。

ってことで私もRSS・SNS表示用ブログパーツ|FeedWind(フィードウィンド)を使ってホッテントリのフィード http://b.hatena.ne.jp/hotentry.rss を流し込み本館のサイドバー*1に登録しました。

しかし…

いま FeedWind を日本語化して気付きましたが、無料で使えるプランは無くなったようです…>_<。
FeedWind Plansのご案内 | FeedWind
「29日後に作成したウィジェットは無効になります。有料版の利用をご検討くささい。」くささい じゃねーよ!

ってことで未完

無料で優秀なRSSフィードリーダは無いのかしら…ということで探し中。

検討中情報(2019/1/21追記)

jQuery で作ってしまう、ってやり方も。

おまけ:日英の表現ちがい

サイドバーに使うようなツールを日本語だとブログパーツと言うけど、英語だと Web widget と言うのだなあ、と Wikipedia で気付いたのであった。

さらにおまけ:日付

はてなダイアリーだと翌日5時までが前日の日付扱いで投稿出来たのだけど、いま見たら0時で日付の取扱が変わってますね。まあしゃあないのかな。

*1:と言いつつブログが全幅使ってるのでサイドじゃなくフッタの上なんだけどな

デジカメで撮影したMotion JPEGな動画ファイルをPhotos.appに登録してもiOS端末に同期されない

はてなblogでのお初記事です。よろしくお願いします。

状況説明

別記事にも載せていますが、デジカメは RICOH CX5 を使っています。このデジカメで動画を撮影すると Motion JPEG 形式(拡張子は .avi)になります。macOS の写真.app(以下 Photos.app )に Motion JPEG を登録すれば再生可能なのですが、残念ながら iOS では Motion JPEG を再生出来ないようで、Photos.app に Motion JPEG を登録しても iOS に同期されません。さらに残念なことに、Photos.app は iOS 向け変換をしてくれないのです(してくれればいいのに)。ということで、このような動画ファイルを iOS 端末へ同期するようにするには、動画をPhotos.app に登録する前に iOS で再生可能な形式に変換しておく必要があります。つまり H.264 形式(拡張子は .mp4)にしておけば良いわけです。

変換にはやはりFFmpegでやるのですが

ただし、ごく単純に FFmpeg

ffmpeg -i RMOV0001.AVI RMOV0001.mp4

とやっても、生成されたファイル RMOV0001.mp4 は iOS 端末や MacQuickTime)で再生出来ません。YUV420 という形式にしておかないと再生出来ないのです。Motion JPEG は YUV422 なので、FFmpeg は何もオプション指定していないとそのまま YUV422 の H.264 形式の動画ファイルを作ってしまうんですね*1

ということで動画変換には

適切なオプションを付けておく必要があります。今回は YUV420 にするために -pix_fmt yuv420p を付けておきます。そして iOS 端末で撮影した動画ファイルの拡張子は .mov なので今回の変換後ファイルの拡張子も揃えておきましょう。

ffmpeg -i RMOV0002.AVI -pix_fmt yuv420p RMOV0002.mov

この変換後の動画ファイル RMOV0002.mov を Photos.app に登録すれば、問題無く iOS 端末へ同期できます。

時刻情報はどうする

さて。上で FFmpeg で動画形式を変換しましたが、撮影時刻情報が全く消えています。このままでは FFmpeg で変換した時刻が撮影時刻であると Photos.app が判断してしまいます。困りますよね。

① 変換後の動画ファイルの作成時刻を変換前の動画ファイルと同じにしちゃえ

touch コマンドで変換後の動画ファイル RMOV0003.mov を変換前の動画ファイル RMOV0003.AVI の作成時刻と同じにしてやってもOKなようです。

touch -r RMOV0003.AVI RMOV0003.mov

もちろんこの作業を行った後に Photos.app へ登録します。登録後に行っても意味ありません。

② 変換後の動画ファイルに時刻のメタ情報を書き込んじゃえ

私が最近お気に入りの exiftool を使うと、撮影時刻情報を変換後の動画ファイルに書き込むことができます。どうやら QuickTime:CreateDate というメタ情報が撮影時刻情報になるようです。変換前の動画ファイル RMOV0003.AVI の作成時刻、もしくは RMOV0003.AVI の撮影時刻のメタ情報を使って、QuickTime:CreateDate に書き込んでやれば OK です。変換前の動画ファイルの作成時刻のメタ情報は、私の使っている RICOH CX5 の場合だと RIFF:DateTimeOriginal に入っていました。

$ exiftool -s -G -RIFF:DateTimeOriginal RMOV0003.AVI
[RIFF]          DateTimeOriginal                : 2019:01:01 07:13:24:

この RIFF:DateTimeOriginal には時差情報が入っていません。一方、 Photos.app は QuickTime:CreateDate を基本的にUTCとして取り扱うようです。ですので、日本で撮影した場合には時差を考慮してやる必要があります。いちいち手作業でこんなことをやっていては間違うでしょう。ということでシェルスクリプトなどをつかってやります。私は bash をほとんど分かっていないので、慣れている Ruby で大半の変換作業を行いました。

$ exiftool -P -overwrite_original -QuickTime:CreateDate="$(ruby -rtime -e 'print Time.strptime(`exiftool -DateTimeOriginal RMOV0003.AVI`[/\d{4}:\d\d:\d\d \d\d:\d\d:\d\d/], "%Y:%m:%d %T").utc.strftime("%Y:%m:%d %T")')" RMOV0003.mov
    1 image files updated

-QuickTime:CreateDate= 以降にある $()bash のコマンド展開です。ので、丸括弧の中に Ruby ワンライナーを入れておけばワンライナーの実行結果が反映されるってわけです。今回は文字列としての日付が欲しいのでさらに外側をダブルクオートで括っておきます。

Ruby での処理内容は以下の通りです。

  1. `exiftool -DateTimeOriginal RMOV0003.AVI` で作成時刻のメタ情報の文字列を取得。
  2. メタ情報の文字列から [/\d{4}:\d\d:\d\d \d\d:\d\d:\d\d/] で時刻情報のみを抜き出す。
  3. Time.strptime メソッドを使って時刻情報文字列を Time オブジェクトへ変換。
  4. Time#utc メソッドでUTCに変換。
  5. Time#strftime メソッドでフォーマットを指定して時刻表示文字列に変換(目的としていた UTC 表記時刻)。
  6. Kernel.#print メソッドで文字列を出力

この後に Photos.app へ登録します。(しつこいですが)登録後に行っても意味ありません。

*1:JPEG ファイルも YUV422 なので、FFmpeg で複数枚の JPEG ファイルから動画ファイルを造るときにも同様の現象が生じます。そんなことをメモ書きしたのが連番静止画からタイムラプス動画を作る - Qiitaです。

Photoshop Elementsで複数の写真にすかしをバッチ処理で入れるときの個人設定めも

バッチ処理のやりかたは公式さんのヘルプサイトを参照。
バッチ処理をしてみよう(Photoshop Elements 15/2018)

めも内容

画面解像度
  • 画面横幅: 1024 pixel
  • 縦横比を固定
クイック補正
  • 自動レベル補正
  • シャープ
ラベル
  • 透かし
  • カスタムテキスト: @riocampos
  • 位置:中央
  • フォント: Grand Hotel
  • テキストサイズ:72
  • 不透明度:20
  • カラー:10%グレー(RGBそれぞれ230)

写真ファイルのEXIF情報にコピーライト情報を追加する安価なやり方(Mac & CUIツール版)

コピーライト情報を追加する先は、正確には EXIF 情報ではなく TIFF 情報と IPTC 情報なんですけどね。まあどーでもいいです*1
また今回も前回と同じく ExifTool を使います。

コピーライト情報を追加する手順

まずExifToolをインストール

やはり Homebrew を使って

$ brew install exiftool

で。

コピーライト情報を写真ファイルへ上書きする

書き込みたいコピーライト情報が 2018 ©riocampos だとすると

$ exiftool -copyright="2018 &#169;riocampos" -overwrite_original /Users/riocampos/Pictures/target_photo_file.jpg

で OK(いわゆる「まるしー」が © とかに文字化けしてるかもしれませんけど、はてなダイアリーの都合*2なので気にしないでね)。-overwrite_original オプションは上書きするためのものです。上書きせずにコピーライト情報を入れた新規写真ファイルを作るのならば省いてください。
また、実行するとこのような警告が出ます

Warning: [minor] Entries in IFD0 were out of sequence. Fixed. - /Users/riocampos/Pictures/target_photo_file.jpg

が、単に「情報の書き込み先が無かったから追加したよ」という意味なので気にしないで。

書き込めたか確認

確認も ExifTool で。

$ exiftool /Users/riocampos/Pictures/target_photo_file.jpg
 :
Copyright                       : 2018 &#169;riocampos

はい、大丈夫ですね。
もしくはプレビューの「インスペクタを表示(⌘I)」で表示したインスペクタの IPTC またはTIFF タブで表示されます。

自分のモノだと主張することはホント大事

残念なことに「Webに上がってる写真はフリー素材」と思ってるひとは非常に多いようです。つまり、写真をフリー素材として扱われないために、写真をWebへ上げる場合には対策を講じる必要があります。私なんぞだと盗まれるのは写真ぐらいしかありませんが、イラストや動画をアップロードすることがある人はもっともっと注意してください。

*1:実際分かってない

*2:はてダの問題点:EUCで未だに作られてる