風柳メモ

ソフトウェア・プログラミング関連の覚書が中心

船を出すのなら九月…その船は今どこにふらふらと浮かんでいるのか?

九月というと反射的に、中島みゆきさんの「船を出すのなら九月」とか
アルバム「生きていてもいいですか」に収録に収録されています

生きていてもいいですか【リマスター(HQCD)】

生きていてもいいですか【リマスター(HQCD)】

シギサワカヤさんの「九月病」
九月病 上巻 (ジェッツコミックス)

九月病 上巻 (ジェッツコミックス)

九月病 下巻 (ジェッツコミックス)

九月病 下巻 (ジェッツコミックス)

とかを連想してしまう、業の深い(?)自分がいます。
いずれも名作ですので、体験したことのない方はぜひご体感ください。
なお、心身ともに良好なときに視聴することをおすすめします


船を出すのなら九月 [作詞・作曲:中島みゆき]

船を出すのなら九月 誰も見ていない星の九月
人を捨てるなら九月 人は皆 冬の仕度で夢中だ

あなたがいなくても 愛は愛は愛は
愛は まるで星のようにある

船を出すのなら九月 誰も皆 海を見飽きた頃の九月

夢をとばすなら九月 たくさんの愛がやせる九月
海へ逃げるなら九月 知らぬまに夜が誘いをのばしてる

あなたがいなくても 愛は愛は愛は
愛は どうせ砂のようにある

人を捨てるなら九月 誰も皆 冬を見ている夜の九月
船を出すのなら九月 誰も皆 海を見飽きた頃の九月

宙船(そらふね) [作詞・作曲:中島みゆき]

その船を漕いでゆけ おまえの手で漕いでゆけ
おまえが消えて喜ぶ者に おまえのオールをまかせるな

その船は今どこに ふらふらと浮かんでいるのか
その船は今どこで ボロボロで進んでいるのか
流されまいと逆らいながら
船は挑み 船は傷み
すべての水夫が恐れをなして逃げ去っても
その船を漕いでゆけ おまえの手で漕いでゆけ
おまえが消えて喜ぶ者に おまえのオールをまかせるな

その船は自らを宙船(そらふね)と 忘れているのか
その船は舞い上がるその時を 忘れているのか
地平の果て 水平の果て
そこが船の離陸地点
すべての港が灯りを消して黙り込んでも
その船を漕いでゆけ おまえの手で漕いでゆけ
おまえが消えて喜ぶ者に おまえのオールをまかせるな

何の試験の時間なんだ 何を裁く秤(はかり)なんだ
何を狙って付き合うんだ 何が船を動かすんだ
何の試験の時間なんだ 何を裁く秤なんだ
何を狙って付き合うんだ 何が船を動かすんだ
その船を漕いでゆけ おまえの手で漕いでゆけ
おまえが消えて喜ぶ者に おまえのオールをまかせるな
その船を漕いでゆけ おまえの手で漕いでゆけ
おまえが消えて喜ぶ者に おまえのオールをまかせるな

こちらはアルバム「ララバイSINGER」に収録されています

ララバイSINGER

ララバイSINGER

このブログにしては異色の記事ですが、せっかくはてなブログでJASRAC管理の歌詞を掲載できるようになったのに、そのことに気がついてからもそういえばまだ一度も利用したことなかったなとちょっと思ったので……。

関連

Twitterのカユイところに手が届くブラウザ拡張/スクリプト


覚え書きを兼ねて、今後も更新される可能性のある自作のTwitter用ブラウザ拡張機能/スクリプト類をまとめてみました。

はてなブログの記事に更新日付を表示&古い記事に警告を出す試み

はてなブログが配信しているサイトマップの仕様が変わっていることに、今更ながら気が付きました
変化したのが2020/04/01からなので、何ヶ月気が付かなかったのか、という話ですが。
sitemap.xml の中身を覗いてみたら、クエリで年月を指定することにより、指定月に作成した記事の更新日付を取得できるようです。

これを利用して、フッタなどに貼り付けることで

  • 個別記事に更新日付を表示
  • 更新日付が古い場合には、警告を表示

するようなスクリプトを試作してみました。

f:id:furyu-tei:20200818053148p:plain
はてなブログの記事に更新日付を入れてみる&古い記事には警告を表示する



更新日付の取得方法について

はてなブログの記事には作成日付は最初から入っており、例えば

var entry_date = new Date( document.querySelector( 'time[datetime][pubdate].updated' ).getAttribute( 'datetime' ) );

のようにすることで、簡単に取得することができます。
これを用いて記事が古いかどうかを判断して表示するスクリプトは以前から存在します。
sprint-life.hatenablog.com

しかし、実際には記事は更新されることもよくあり、その記事の情報が古いかどうかは更新日付を元に判断したいところです。

2020/04/01より前のサイトマップ仕様

2020/03/31まで、サイトマップの仕様は

/sitemap.xml?page=<ページ番号>

のような形式で、1ページ毎に作成日付の新しいものから順に100件ずつ、記事のURLと更新日付が含まれる仕様になっていました。
なお、当概仕様のサイトマップには現在でもアクセス可能です。
これだと、特定記事の更新日付を取得するためには、当該記事のURLが現れるまでひたすらページ番号を増やしてアクセスする必要があります。
上記の記事やコメント中でも、サイトマップから更新日を取得することは可能ではあるものの、記事と一致させることが手間なので実用的ではない旨書かれています。

このサイトマップを使った更新日付表示の実装例は
www.tsubasa-note.blog

等があるようです。
また、サイトマップの場合には何度もアクセスが発生してしまう問題を解消するため、AMP(更新日付が埋め込まれている)を利用した実装もあるようです。
psn.hatenablog.jp

2020/04/01 以降のサイトマップ仕様

2020/04/01から配信されるようになったサイトマップの仕様では、

/sitemap_periodical.xml?year=<作成年>&month=<作成月>

のようにすると、

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://memo.furyutei.work/entry/20161015/1476495230</loc>
        <lastmod>2016-12-06T09:08:18+09:00</lastmod>
    </url>
    <url>
        <loc>https://memo.furyutei.work/entry/20161008/1475863694</loc>
        <lastmod>2016-12-06T09:08:56+09:00</lastmod>
    </url>
    <url>
        <loc>https://memo.furyutei.work/entry/20161008/1475860031</loc>
        <lastmod>2017-11-14T07:08:24+09:00</lastmod>
    </url>
    <url>
        <loc>https://memo.furyutei.work/entry/20161007/1475839249</loc>
        <lastmod>2020-03-07T03:29:59+09:00</lastmod>
    </url>
</urlset>

のように、指定した年月に作成した記事のURLと更新日の一覧を取得することが出来るようになっていました。
これならアクセスが1回だけで済むので、実用的だと思われます。

個別記事に更新日付を表示&古い記事に警告を表示するスクリプトとCSSのサンプル

注意事項
  • スクリプトをブログのフッタなどに貼り付ける場合、<script>~</script>で囲むのを忘れないこと
  • サンプルソースコードはGist上にあります。なお、残念ながら Gist 上のコードは外部スクリプトとしては読み込めません(Content-Type: text/plain; charset=utf-8 のため)
  • async/await とか使っているので、モダンブラウザじゃないと動きません(笑)
    それじゃ嫌だというかたはこちらの記事等を参考にして、新しいサイトマップ仕様に対応させてみてください

余談

記事の更新時刻が例えば

2017-11-14T07:08:24+09:00

という文字列で与えられたとき、閲覧者のタイムゾーンによらずに日本標準時の年月日で

2017-11-14

という文字列に変換するためにはどうするのがスマートなんですかね……?
いや、上記サンプル中ではT以降の文字を消す、という手抜き実装ですが……

また、同様に

2017-11-13T22:08:24Z

で与えられた場合には?

var modified_date = new Date( '2017-11-13T22:08:24Z' );
modified_date.setHours( modified_date.getHours()+9 );
var jst_date_string = modified_date.toISOString().replace( /T.*$/, '' );

のようにすれば一応できるけれど、正攻法ではないですね……。

Git for WindowsのGit BASHでウィンドウタイトルだけが文字化けする現象(winptyが原因)と対処方法

[2020.10.27追記] Git for Windows 2.29.1-64-bit(mintty 3.4.0 / winpty 0.4.3 の組み合わせ)では、exec winpty bash した後も Git Bash のウィンドウタイトルが文字化けしなくなった模様。以下は古いバージョンについての記述であり、新バージョンでは環境変数 PS1 を書き換えるとかえって文字化けしてしまうので、注意。



Git BASHで、たまたま日本語を含むフォルダ下で作業していたら、ウィンドウのタイトルだけが文字化けしていることに気がついた(ウィンドウ内については正常に表示されている)。
Windows 10 Pro バージョン 1909 (OS ビルド 18363.959)、Git for Windows 2.28.0-64-bit、mintty 3.2.0 (x86_64-pc-msys) [Windows 18363]

f:id:furyu-tei:20200812030339p:plain
Git BASHでウィンドウタイトルだけが文字化けしている様子

この現象の原因と、対処方法についての覚え書きを残しておく。




原因

どうやら、~/.bash_profile にて

exec winpty bash

を記述していたためらしい。

試しにこの記述を外すと、ウィンドウタイトルは化けなくなる。
ただし当然ながら、対話型コマンドがそのままではうまく動作しなくなる。

f:id:furyu-tei:20200812040929p:plain
exec winpy bash の記述を外した場合


Python なんかの Windows ネイティブな対話型コマンドを呼び出すのに、いちいち

$ winpty python

としたり、あるいは ~/.bashrc で対話型コマンド毎に

alias python="winpty python.exe"

のように alias 定義するのが面倒だったので bash 自体を winpty で呼び出していたのだけれど、これが原因でウィンドウタイトルが化けてしまうのは想定外……。

対処方法

A. 必要なコマンド毎に個別に winpty を付けて呼び出す alias を定義しておく

bash そのものを winpty 経由で呼び出しているのが原因なのでこれを止め、個別のコマンド毎に winpty 付き呼び出しを行うようにすれば問題はなくなる。
その場合、標準では /etc/profile.d/aliases.sh にて

    for name in node ipython php php5 psql python2.7
    do
        case "$(type -p "$name".exe 2>/dev/null)" in
        ''|/usr/bin/*) continue;;
        esac
        alias $name="winpty $name.exe"
    done

のように、いくつかのコマンドについて対応されているのを参考にして ~/.bashrc に必要なコマンドについて同様の記述を追記するというのが一つの方法。

B. 環境変数 PS1 を書き換える

A. のようにすると、対話型コマンドの種類が増えるごとにメンテナンスしなければならないため、面倒なのが難点。
そこで、bash を winpty で呼び出したときにウィンドウタイトルのみが化けている点に着目し、プロンプト定義用の環境変数(PS1)を書き換えてやれば良いのではないか? と考えた。
状況的に、bash を winpty 経由にした際には、mintty はウィンドウタイトル文字列としては Shift-JIS(CP932) で渡されることを期待しているのではないかと推測、$PS1 中に含まれる $PWD の文字コードを変換するように定義してみると、

export PS1=`echo "$PS1" | sed "s~\\$PWD~\\\`echo \\$PWD | iconv -f utf-8 -t cp932 2>/dev/null\\\`~"`

これでうまくいった。
ウィンドウタイトルに関してだけはなんとかなったということで、winpty bash したときに出る潜在的な問題は他にもあるかも知れない。

f:id:furyu-tei:20200812042525p:plain
ウィンドウタイトルも文字化けせず、対話型コマンドも正常に起動できている

覚え書きを兼ねて、現状の ~/.bash_profile および ~/.bashrc を残しておく。

~/.bash_profile

#【覚書】
# ※参考:[bashの.profileや.bashrc等を実行する動作仕様 - sgryjp.log](https://blog.sgry.jp/entry/2019/11/09/232927)
#===============================================================================
# ・ ~/.bash_profile はログインシェルで一度だけ実行される
#   このため、主に
#
#   - ログイン時に一度だけ実行したい処理
#   - 対話操作では必要のない(対話操作以外のコマンド実行に必要な)設定(環境変数 LANG 定義等)
#   - ログインシェル/サブシェルに関わらず基本変更不要な設定(環境変数 PATH 定義等)
#
#   を記述するのに向く
#
# ・ ~/.bashrc はサブシェルでは自動的に呼ばれる(ログインシェルでは自動では呼ばれない)
#   このため、~/.bash_profile からも呼び出されるよう設定の上で (^1)
#
#   - alias や関数等、暗黙的に引き継がれない設定
#   - 対話操作のみで必要となる設定(環境変数 PS1、EDITOR 等)
#
#   を記述するのに向く
#
#   (^1) ~/.bashrc があるのに ~/.bash_profile, ~/.bash_login or ~/.profile が無い環境は推奨されず、
#        例えば Git for Windows においては、その場合、/etc/profile.d/bash_profile.sh により
#        ~/.bashrc を呼び出す記述が入った ~/.bash_profile が生成される
#===============================================================================

# ■ ~/.bashrc 実行
#   ※ログインシェルでは ~/.bashrc は自動的には実行されないため、この設定が必要
#test -f ~/.profile && . ~/.profile
test -f ~/.bashrc && . ~/.bashrc

# ■ 各種定義
export PYTHONUTF8=1
export PYTHONSTARTUP=~/.pythonstartup

# ■ bash を winpty 経由で起動
#   ※ Windows ネイティブな対話型コマンド(Python 等の、interactive mode が mintty に対応していないもの)に対応
exec winpty bash
#   ※ exec によりシェルプロセス自体を置換しているため、これ以降に書いた内容は反映されないことに注意

~/.bashrc

if [[ $TERM_PROGRAM = "mintty" ]]; then
    # ■ mintty 専用設定
    case `tty` in
        /dev/cons*) # winpty
            # winpty 経由だと $PWD が日本語を含む場合ウィンドウタイトルが文字化けする(mintty 3.2.0)問題に対処
            # → mintty 3.4.0 / winpty 0.4.3 の組み合わせでは発生しなくなったため、必要がなくなった
            # export PS1=`echo "$PS1" | sed "s~\\$PWD~\\\`echo \\$PWD | iconv -f utf-8 -t cp932 2>/dev/null\\\`~"`
            ;;
        /dev/pty*) # (default)
            ;;
    esac
fi


# ■ 暗黙的にサブシェルに引き継がれない設定(alias・関数定義)
# ※サブシェルでは、
#   - profile系スクリプト(/etc/profile、/etc/profile.d/*、~/.bash_profile等)は実行されない
#   - ログインシェルで定義された alias や関数は引き継がれない
#   ことに注意
shopt -q login_shell || {
    # サブシェル専用設定
    # ※必要に応じて /etc/profile や /etc/profile.d/* (aliases.sh等)で定義されている alias 等をコピーしておく
    alias ls='ls -F --color=auto --show-control-chars'
    alias ll='ls -l'
}

# ~/.bash_profile 経由/サブシェル共用設定
alias ls='ls -aF --color=auto --show-control-chars'
alias tree='tree -N'
alias python2='py -2'
alias python3='py -3'
alias python='python3'
alias pip2='python2 -m pip'
alias pip3='python3 -m pip'
alias pip='pip3'


# ■ 非対話ログインで不要かつ対話ログインで使いたい設定(環境変数定義)
export EDITOR=vim

その他の覚え書き等

ユーザー独自のファイル(bashスクリプト)をログインシェル/サブシェルどちらでも呼び出す(Git BASH 独自仕様?)

/etc/profile.d/git-prompt.sh
の最後の方に、以下のような記述があることに気づいた。

# Evaluate all user-specific Bash completion scripts (if any)
if test -z "$WINELOADERNOEXEC"
then
        for c in "$HOME"/bash_completion.d/*.bash
        do
                # Handle absence of any scripts (or the folder) gracefully
                test ! -f "$c" ||
                . "$c"
        done
fi
  • /etc/profile.d 下のファイルは通常はログインシェルからしか呼ばれないものだが、git-prompt.sh に限り、サブシェルからも呼び出される(/etc/bash.bashrc 経由)
  • ~/bash_completion.d/ というディレクトリを作成し、この下に拡張子 .bash の付いた任意の bash スクリプトを置いておくと、/etc/profile.d/git-prompt.sh 経由で呼び出される(結果的にはログインシェル/サブシェルの区別なく呼ばれることになる)

参考

winpty・mintty 関連

mseeeen.msen.jp

bash 関連ファイル(~/.bash_profile・~/.bashrc 等)の動作仕様について

blog.sgry.jp
なんとなくで設定しがちだった bash の ~/.bash_profile や ~/.bashrc といったファイルの動作仕様が分かりやすくまとまっていて非常に参考になった。

Google ドライブの共用 PDF を画像データとしてダウンロードするユーザースクリプトを試作

Google ドライブで共用されている PDF ファイルを、画像データにして ZIP 化し、ダウンロードできるユーザースクリプトを作ってみました。
通常は PDF をそのままダウンロードすればよいのですが、まれにダウンロード権限が「閲覧者はダウンロードできません」となっている場合があるため、主にその対策用です。
画像として取得しても、PDF 化したり OCR にかけたりと結局は別途手間はかかってしまいますが……まぁ、手動で1ページずつ落としたりするよりは幾分マシかなと。

インストール・使い方など

github.com
をご参照下さい。

ユーザースクリプトのソースコード


はてなブログでは Gist 貼り付けしかできないみたいなので、gist-it.appspot.com - Embed files from a github repository like a gist を使って GitHub 上のソースコードを貼り付けてみました