それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

which じゃなくて which brew が欲しい。

このコマンドは、どの brew

which brew package contains this command ? な疑問文に答えてほしい。

なんとかした。

function which-brew () {

  ! type $@ &>> /dev/null && { echo $@ not found.; return 1 ; }

  [[ $(realpath $( which $@) ) =~ Cellar/([^\/]+) ]] ;

  (( ${#BASH_REMATCH[@]} > 1  )) &&  echo ${BASH_REMATCH[1]};
}

解決!

これで、このコマンドはどのbrew パッケージから来たかわかる

takuya@~$ which-brew ls
coreutils
takuya@~$ which-brew find
findutils
takuya@~$ which-brew ffmpeg
ffmpeg
takuya@~$ which-brew chrome-canary-cli
chrome-cli

コレは嬉しい。

これで、コマンドがどのBrew由来かわかるよね。which して realpath するの、面倒だったもん。

which コマンドを見直してみる。which コマンドの活用法

which コマンド

which コマンドについて

which コマンドは、あってあたりまえで、特に詳しく調べることもしなかった。今回はwhich コマンドを見直してみることにする。

そもそも which コマンドって?

which コマンドは、指定されたコマンドがPATHの何処に出現するか調べてくれる。

利用場面は、此のコマンドどこにあるんだっけ?ときにつかう。which PATH is this comand in ?の疑問に答えてくれる。

たとえば、次のように使う。

takuya@~$ which bash
/usr/local/bin/bash

which コマンドを更に追求する

「此のコマンドどこに?」の「このコマンド」の定義を広くする。何もしないと、PATHを探すのだ。だけれどもコマンドはファイルとは限らない。funtion alias もコマンドとして機能する.これらを探せるのが which

だけど、その検索範囲は、非常に限られている。詳細に指定してあげなくてはいけない。

which ls 

これだと PATHから探してくれるだけだ。

このls は何の? which is ls

そのため、ls といっても、実際に使っているlsはどれだ?。この目的だと、type コマンドを用いて確認することが多いのだ。

takuya@~$ type ls
ls は `ls --color=auto --time-style=long-iso ' のエイリアスです

なので、which を使う場面は限られて、殆どの場合 type コマンドで済ませることが多いのだ。というか、実直な感想を言えば、type 万能。type 万歳。でも今回は、コレを which でやることが出来ることを知ったのでマトメていくのだ。

which コマンドで 検索に alias も含める。

エイリアスを含めるには、which に標準出力で エイリアスの一覧を与えて、 --read-alias / -i オプションを付けるのだ。

alias | which --read-alias ls

実行結果

takuya@~$ alias | which --read-alias ls
alias ls='ls --color=auto --time-style=long-iso '
    /Users/takuya/.bin/ls

which コマンドの検索に function も含める。

function を含めることも出来る。 declare -f で関数一覧を取り出して、--read-functions を使ってwhich の検索に関数を含めることが出来る。

declare -f | which --read-functions find

実行例

takuya@~$ declare -f | which --read-functions find  -a
find ()
{
  #略
}

alias も function もどちらも検索対象にしたい。

alias も function も PATH もまとめて、全てからからコマンドの存在を調べたい。 この意図だと ( alias; declare )とサブシェルで2つを同時に与える。

(alias;declare -f) | which --read-alias --read-functions--read-functions 
# またはグループ化で。 { alias;declare -f; } | which --read-alias --read-functions  find

実行例

takuya@~$ (alias;declare -f) | which --read-alias --read-functions  ls
alias ls='ls --color=auto --time-style=long-iso '
    /Users/takuya/.bin/ls

ここまでやるなら、もう type 使うよね?ねー

同名のコマンドをすべて列挙する

-a オプションを付ける。

実行例

takuya@~$ which -a bash
/usr/local/bin/bash
/bin/bash

コマンドが何処にあるか調べる意図だと -a のオプションが一番良いね。

ぶっちゃけ type でよくね?

調べるだけなら、type でいいんです。type でね

個人的には、 which は コマンドの探索 。 type はコマンドの判別に使っています。ただ、使い分けなくても which だけでも十分用途に足りるんだ。と感心してました。

which の活用法

which は type と違い、コマンドのフルパスが返ってくる効果があります。これを利用して、フルパス指定コマンドで場所がわからないときなどにとりあえず which しておけば便利です。。

$(which find) -type d

まぁこちらも env コマンドがあるから env でもいいですがね. env だと引数を与えられませんし、そもそも実行方式が違うんだ。

## できる
$(env find)
$(which find) -type d
$(which find) -type d ~/Desktop
## できない
$(env find) -type d ~/Desktop

which だけじゃわからないもの

which だけじゃ足りないことがある。
関数はわかりません、シンボリックリンクはたどってくれません。

関数は見えない。

takuya$ function grep { echo ... ; }
takuya$ which grep 
/bin/grep

関数は見えないので前述の通り type を使いましょう。

フルパスは見えない。

シンボリックリンクされているコマンドの実体パスはもちろん見えません。 home brew のようにコマンドファイルがsym link にされていの時があるのだ。

takuya@~$ which gls
/usr/local/bin/gls
takuya@~$ realpath /usr/local/bin/gls
/usr/local/Cellar/coreutils/8.26/bin/gls

このように実体ファイルを知りたいときには、 realpath ( または readink) を重ねがけする必要がある。

readlink $(which gls)

これはめんどくさいので、ショートカットにしておくと便利

function which-realpath(){
  realpath $( which $@ )  
}

which -a で全部

あれ、確かインストールしたはずだけど、パスがおかしいのかとか。同名のコマンドがいくつもあるときに、パスの優先順位を調べるとき whereis / which --all が便利です。

which -a  node 
which --all  node 

なお類似にコマンドに whereis があります。

whereis というコマンドでも類似のことが出来ます。

ただ、whereis は おもに locate の代わりになります。コマンドそのものを探すわけではありません。

windows だと where ですね。

whatis / who / which / whereis / whoami / while など whから始まる コマンドは何かと便利だ。

参考資料

  • man which ( GNU which )

関連記事

which コマンドでPATHにある同名のコマンドを全部列挙する - それマグで!

2019-08-23

記述を修正

アカウント・リカバリで電話番号・生年月日はやめてほしい

アカウントのパスワード復活で生年月日はやめてほしい

個人情報をクレクレするのは良いけれど。生年月日を使うのはやめてほしい。

f:id:takuya_1st:20170404035852p:plain:w300

生年月日を漏らされるとめんどくさい

個人情報が漏れたときに、生年月日が流出すると本当にめんどくさいことになる。

クレジットカード番号なら変更可能だが、名前、住所、生年月日、職場は変更することが困難だ。

変更が困難な情報を預けるのは本当にめんどくさい。

どんなにセキュリティを確保されても漏れるときは漏れる、個人情報が必要な場面はそうそうないでしょう。

しかも、名前、住所、生年月日、職場は公開情報。

これらの公開情報とアカウント情報を紐付けられるのがめんどくさい。

この会社が漏らしたら紐付いた情報がドンドン連鎖的に照合されていく。。。

だから本当の生年月日・名前など書くはずがなく。

公開情報で認証するのは本当に危険。

アカウント乗っ取りのリスクを考慮するなら、公開情報で認証するなんてナンセンスだと思いませんか。

この会社のIDの場合

  • メールアドレス
  • 生年月日
  • 電話番号
  • Pontaカード番号

で認証をしています。すべて公開情報です。まいったな。

かりにメールアカウントが乗っ取られていたらそれは此の会社の責任ではないだろう。だからメールとアカウント復活用の予備メアドだけで十分なんですよ。それでも足りないなら、ユーザーが希望してSMSによる2要素を追加することも出来るってのがお互い楽なのに。なんでこういうエセキュリティが増えちゃうんだろうか。

え?→「アドレスや任意の文字列を付加したようなメールアドレスについては、同一と判断します」

何のためにメアドを変えられるか理解してない。

ポンタにログイン使用して気づいた。

尚、Gmailau one netのメールサービス、Livedoorメール、HotmailYahoo!メールなどで1つのメールアドレスとして扱われる、複数のメールアドレスや任意の文字列を付加したようなメールアドレスについては、同一と判断します。 さらに詳しく

馬鹿なの?

Gmailエイリアスのメアドを同一に扱ってしまうと、「そのメアド」が登録されているかわかってしまう。

つまり、ユーザーIDが漏れてしまう。

どういうことか?

example@gmail.com
example+nospan@gmail.com
exam.ple@gmail.com

これらを「別の」メアドとして使えること、それ自体に意味があります。スパムよけではなく、「ログインIDの隠蔽」という意味があります。

ログインIDとして同じにしてしまうと、上記のメアドはすべてコレに丸められて

example@gmail.com

このオリジナルのメアドでログインが可能になってしまいます。

更に恐ろしいことに、そのメアドが登録されているかどうかの情報が漏洩します。

これはセキュリティ的には由々しき事態です。

エイリアスを同一視=セキュリティレベルの低下

サイトごとにメアドとパスワードを変えられません。

メアドとパスワードの両方をサイトごとに変更することでセキュリティを確保できているはずが、全く意味がなくなります。

Gmailエイリアスを同一視してしまうとセキュリティレベルの著しい低下を招きます。

なぜ、ログインにエイリアス使うのとセキュリティレベルが向上するのでしょうか

なぜか?

メアドは「公開情報」だからです。

メールアドレスのような公開情報でログインを可能にしてしまうと、<パスワード>の強度だけが純粋にセキュリティの強度です。

そのため、メールのエイリアスを使えることで、セキュリティを強化することが出来ます。つまり公開情報でのログインを不可にすることが出来る。

メールエイリアスを許可することでログインIDを不可視にすることが可能になっています。つまり攻撃を受けにくくなります。

また、別のサイトが「おもらし」してしまったとしても自サイトのログインのブルート・フォース攻撃には使われることはありませんし、もちろん同一IDではないでログインを拒否することが出来ます。

これが、メールエイリアスを使う最大の理由でしょう。現代の自衛策です。

ログインIDにメアドと電話番号は危険

たとえば、ドコモショップではドコモIDをドコモのキャリアメールにするように指示されます。まっぴらごめんです。

たとえば、au では au id が電話番号です。恐ろしいことです。

au id の場合は、2段階認証をオフにすることが出来ますが、乗っ取り事例を紹介されてトコトン警告されます。大きなお世話です。電話番号でログイン可能にしてるからそんな事例が起きたとしか考えられない。ランダムな文字列をパスワードだけでなくIDにも採用すれば危険性は少し減少する。

エイリアスはスパム避けだけではない。

何のためにメアドが複数作れるか全く理解出来てないんじゃなかろうか

どこかのサイトがおもらしして、メアド同一で乗っ取られたら、責任取ってくれるんでしょうかね。

エイリアスのメアドに変更が絶対に不可能です。

ドット入れると強制的にメアドを変えられません。この会社は本当にGmailエイリアスが嫌いなようです。

f:id:takuya_1st:20170404034612p:plain

公開情報で認証するのやばいよね。近づかないほうがいいです。この会社も

あ、、絵合わせセキュリティですか。

この会社、マジで近づかないほうが良さそうですね。

f:id:takuya_1st:20170404034005p:plain:w200

メールエイリアスが意味を失いつつある。

複数登録が多くなると、重複登録を許してしまうとか、本人確認がめんどくさいとか、会社の個人情報の収集の目的や、キャンペーン重複登録をさせたくないなどの一方的な理由でセキュリティレベルを下げられるのは全く嬉しくない状況が起きている。

仕方ないので、メールエイリアスicloud.com を使いましょう!

au id や livedoor メールを チェックするのに @googlemail.com @me.com を調べないのは本当にアホですね。ザルすぎて頭オカシイ

Pontaカードやめよう

個人情報の乞食されるのでも、多少はメリットあるから使ってましたが、今日から一切使わないことにします。

ローソンは頻繁に使うので、ポンタやめてdpoint にします。

f:id:takuya_1st:20170404042409j:plain:w300

libtrash でゴミ箱を扱う→obsolete → trash-cli

debian の wheezy あたりではもうobsoleteパッケージになってレポジトリから削除されてるっぽい

obsolete

http://usami-k.seesaa.net/article/2644852.html

現在はコッチ

https://github.com/andreafrancia/trash-cli/

takuya@:~$ apt install  trash-cli
alias rm='trash-put'

2017-05-14 修正

trash-rm は ゴミ箱の中から指定ファイルを消すものでした、勘違いです。

SpeakerDeck のスライドを取得してローカルで見る

SpeakerDeck をオフラインで見たい

Speaker Deck で良さげなスライドをEvernoteに溜め込みたいなと思った。

ブックマークしてても検索出てこないし。どうしようかな~っておもって。とりあえずダウンロードしてみることにした。

URLをスクレイピングするのに asyncio使おうとしたけど、あんまり早くならないし、 コードは煩雑だし。muliprocessは良く出来てるけど、それするくらいなら、 xargs でマルチプロセス作ったほうがずっとスッキリしてて楽だった。

speaker-deck.py

gist.github.com

neobundle から dein に乗り換えた

neobundle のメンテが面倒になったので

ここらで、マルっと dein に乗り換えようと思って dein に乗り換えました。

特徴

dein 乗換てよかったこと。

速い

起動速いんですね。

toml ファイルがいい

toml ファイルに設定がまとまるので、gitによる差分管理が楽になった。

インストールと初期設定

vim のインストール

macOS X

brew install vim --with-lua

debian

sudo apt install vim-nox
sudo update-alternatives --config editor

dein の準備

mkdir ~/.vim 
cd ~/.vim
curl -LJO  https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
bash installer.sh ~/.cache/dein

.vimrc から dein の起動

" dein の設定とインストール
" $> cd .vimrc
" $> bash installer.sh  ~/.cache/dein
"
if isdirectory( expand('~/.cache/dein')  )
    if &compatible
        set nocompatible               " Be iMproved
    endif
    set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim

   " Required:
    if dein#load_state('~/.cache/dein')
        call dein#begin('~/.cache/dein')

       " Let dein manage dein
       " Required:
        call dein#add('~/.cache/dein/repos/github.com/Shougo/dein.vim')

       " Add or remove your plugins here:
                call dein#load_toml(expand('~/.vim/dein.plugins.toml'),       {'lazy': 0} ) "  main 
        call dein#load_toml(expand('~/.vim/dein.plugins.colors.toml'),{'lazy': 0} ) " colorscheme
        call dein#load_toml(expand('~/.vim/dein.plugins-lazy.toml'),  {'lazy': 1} ) " others for lazy 

       " You can specify revision/branch/tag.
        call dein#add('Shougo/vimshell', { 'rev': '3787e5' })

       " Required:
        call dein#end()
        call dein#save_state()
    endif

   " Required:
    filetype plugin indent on
    syntax enable

   " If you want to install not installed plugins on startup.
    if dein#check_install()
      call dein#install()
    endif
endif

toml ファイルを書く

ぱぱっと移動させたのがこんな感じ。メモ程度にする。

[[plugins]]
repo = 'Shougo/dein.vim'

[[plugins]]
repo = 'cespare/vim-toml'
on_ft = 'toml'

[[plugins]]
repo =  'itchyny/lightline.vim'
[[plugins]]
repo = 'Shougo/neosnippet.vim'

[[plugins]]
repo = 'Shougo/neosnippet-snippets'

[[plugins]]
repo = 'Shougo/neocomplete'
hook_add = '  let g:neocomplete#enable_at_startup = 1'

[[plugins]]
repo = 'tomtom/tcomment_vim'
[[plugins]]
repo = 'Shougo/vimfiler'

[[plugins]]
repo = 'scrooloose/nerdtree'

[[plugins]]
## vim のコマンド入力でEmacsのように option で1単語ずつ移動できるように
repo = 'houtsnip/vim-emacscommandline'

[[plugins]]
repo = 'xolox/vim-misc'
[[plugins]]
repo = 'xolox/vim-colorscheme-switcher'
depends = ['misc.vim']

[[plugins]]
# カーソル位置のコンテキストに合わせてftを切り替える
repo = 'osyo-manga/vim-precious'
depends = ['context_filetype.vim']

[[plugins]]
repo = 'Shougo/context_filetype.vim'
[[plugins]]
repo = 'Shougo/neco-syntax'

#[[plugins]]
### python
repo = 'davidhalter/jedi-vim'
on_ft = 'python'

[[plugins]]
## C言語用
repo =  'Rip-Rip/clang_complete'
on_ft = ["c", "cpp"]
hook_add = '''
let g:clang_library_path="/usr/local/opt/llvm/lib"
'''

[[plugins]]
repo = 'pangloss/vim-javascript'
on_ft = ['js','javascript']

[[plugins]]
repo = 'tpope/vim-endwise'
on_ft = ['ruby']
[[plugins]]
repo = 'plasticboy/vim-markdown'
on_ft = ['md']

vim-precious 強い

toml 中にvim script 書いたら、ハイライトを切り替えてくれる vim-precious。これHTMLでも使えたりするので強い。

参考資料

https://qiita.com/delphinus/items/00ff2c0ba972c6e41542

python の subprocess 起動で、起動コマンドのstdin に書き込む

起動して入力をわたしたい。

cmd1= "cat"
p = subprocess.Popen(cmd1.strip().split(" "), stdin=subprocess.PIPE)
  p.stdin.write("Hello World\n".encode('utf8'))

コマンドを起動するときに、 stdin に PIPEを指定する。実行中の python と サブプロセスのSTDINを繋いでやる。

これで p.write が呼べる

複数パイプしたいとき

複数パイプの起動をしたいときは、こちらのエントリに書きました。

python でコマンド実行。サブプロセスの終了待ち・強制終了・親プロセスと一緒に殺す。 - それマグで!

正規表現の名前付きマッチで、scanf から卒業する

正規表現の名前付きなマッチを覚えました。

>> ret = '直通特急 阪神梅田行 18:29 発 3番のりば'.
match(/(?<type>.+) (?<dest>.+)(?<dep_time>.+)/)
=> #<MatchData "直通特急 阪神梅田行 18:29 発 " type:"直通特急" dest:"阪神梅田" dep_time:"18:29 ">
>> puts ret[:type]
=> "直通特急"

名前付きマッチの後方参照はとても楽しい!!便利!!これで scanf みたいなレガシーとバイバイできそう

php でも動いた

<?php

$str='直通特急 阪神梅田行 18:29 発 3番のりば';
$regex= "/(?<type>.+) (?<dest>.+)行 (?<dep_time>.+)発 /";
preg_match(  $regex, $str , $matches );

var_dump($matches);

実行結果

takuya@orm$ php test.php
array(7) {
  [0]=>
  string(39) "直通特急 阪神梅田行 18:29 発 "
  ["type"]=>
  string(12) "直通特急"
  [1]=>
  string(12) "直通特急"
  ["dest"]=>
  string(12) "阪神梅田"
  [2]=>
  string(12) "阪神梅田"
  ["dep_time"]=>
  string(6) "18:29 "
  [3]=>
  string(6) "18:29 "
}

bash でも出来ないか?

できなかった。

takuya@orm$ regex='(?<name>.+)';  [[ "aaaaaaa aaaaaaaaaa" =~ $regex ]];echo "${BASH_REMATCH[0]}"
takuya@orm$

SQLiteでの alter colmunの代替案

SQLite にはいくつかの機能がない。

たとえば、次の通り。

  • alter table rename columnがない
  • alter table drop column がない

SQLiteでの alter colmunの代替案

  1. いったん別のテーブルにデータを退避する
  2. drop table でテーブルを消す
  3. create table でテーブルを作り直す
  4. select / into で退避データを投入する

いったん別のテーブルにデータを退避する。

方法は2つある。一つは、テーブルを別名にする。もう一つは、create table as select でテーブルをコピーする

ALTER TABLE my_table RENAME TO my_table;
create table my_temp as select * from movie_info;

create table select from でコピーすると、SQLiteのデフォルトなTextメインのカラムになるので細かいConstrainsや型情報やdefault / unique が消える可能性がある。

drop table で消す

drop table my_table;

create table で作り直す

create table my_table  (  .... ) ;

insert select する。

insert into my_table select * from my_temp;

Alter table と column まわりはちょっとハマりますね

ffmpeg で mkv の字幕ファイルをmp4 にする

字幕も含めてコピーしたいな

mkvのストリームに字幕が含まれてて、これを維持したまま、mp4 に変換したいな。

h264 / aac はそのままでいいんだけど、字幕はそのまま copy で動かなかったので調査した。

"ffmpeg -i '#{src}.mkv' -y -map 0:0 -map 0:1 -map 0:2  -c:v copy -c:a:1 copy -c:s mov_text  '#{dst}.mp4'"

逆は

"ffmpeg -i '#{src}.mp4' -y -map 0:0 -map 0:1 -map 0:2  -c:v copy -c:a:1 copy -c:s srt  '#{dst}.mkv'"

mkv は srt で mp4 は mov_text らしい。

ストリームに何が含まれるかは ffprobe json

takuya-1st.hatenablog.jp

参考資料

Creating multiple outputs – FFmpeg

https://trac.ffmpeg.org/wiki/Map#Example1

http://stackoverflow.com/questions/8672809/use-ffmpeg-to-add-text-subtitles

画像がカラーか、白黒かを判別する

カラー画像かモノクロか判別する。

takuya@:$ convert sample.cl.jpg -colorspace HSB -separate -delete 0 -fx "u*v" -blur 2x2 -threshold 30% -format '%[fx:mean]\n' info:
0.693993
takuya@:$ convert sample.bw.jpg -colorspace HSB -separate -delete 0 -fx "u*v" -blur 2x2 -threshold 30% -format '%[fx:mean]\n' info:
0

スキャンしたデータがカラー(表紙)か本文(頁)かを判断したいので調べた。0に近くなれば白黒

彩度をみて -threashold で許容範囲を決めて、 -format で数字にしてる

コマンドはこんな感じ。

convert sample.cl.jpg \
  -colorspace HSB \ 
  -separate -delete 0 \
  -fx "u*v" -blur 2x2 \ 
  -threshold 30% \
  -format '%[fx:mean]\n' info:

参考資料

http://q.hatena.ne.jp/1340883203

プレイリストのファイル形式を色々試してみる。

プレイリスト扱えると便利

WEBサイトに動画や音声をたくさんおいていると、再生が面倒なのでプレイリストを作って対応したい。どのアプリが、どのプレイリストに対応しているか、そもそもプレイリストのファイル形式はどのようなものがあるのだろうか。

プレイリストファイルの形式。

ブラウザやOS標準になっているなど、すぐに使えるプレイリストのファイル形式には次のようなものがある。

幾つかあるけれどVLC をメインに考えることにした。

フォーマット ファイルの中身 対応アプリなど
XSPF XML VLC
ASX XML WMP / VLC
m3u/m3u8 TXT Safari/Android/iTunes
PLS TXT vlc

此の他にも類似物として podcast.xml がある。

また、プレイリストは入れ子に出来るようになっている。

XSPF の例

拡張子は xspf 。 Contet-Typeは application/xspf+xml

<?xml version="1.0" encoding="UTF-8"?>
<playlist version="1" xmlns="http://xspf.org/ns/0/">
<trackList>
<track>
<location>http://example.com/sample.mp4</location>
<title>自分のムービー</title>
</track>
</trackList>
</playlist>

ASX の例

拡張子は asx 。Content-Type は video/x-ms-asf

<asx version=”3.0”> 
<entry> 
<title> 自分のムービー </title> 
<ref href=http://example.com/sample.mp4” /> 
</entry> 
</asx>

ASXにはASFの類似物があり、そちらはテキストファイルでPLSに近い

WindowsメディアのフォーマットはiPhoneで使えないので、今回は調査対象から外します。

m3u / m3u8

拡張子 .m3u, .m3u8 。 Content-Type application/x-mpegURL

#EXTM3U 
#EXTINF:-1,自分のムービー
http://example.com/sample.mp4

メタデータは次の行に書くのがポイント

#EXTINF:time_duration,ムービータイトル - シリーズ名

m3u8 の中に記載するのは m3u8か TS(content-type video/MP2T)が要求される。

時間は -1 にすると指定をキャンセルできる(あとで登場します)

PLS

拡張子 pls。 Content-type はaudio/x-scpls

[playlist]
File0=http://example.com/sample.mp4
Length0=1499
File1=http://example.com/sample.mp4
Length1=1499
NumberOfEntries=2
Version=2

中身は ini ファイルと同じフォーマットだと思う

今回は iOS Safari / iTunes / VLC について

VLC は Win/Mac/iOS でほぼ動作は変わらずなんでも再生できた。

また、iTunesは m3u8 については、ポッドキャストとして取り込んでくれた。

app xspf m3u8 pls
VLC
iOS/Safari
Mac/Safari
iTunes

m3u8 の中身にTSを入れると、HLSのストリーミングになる。Safariはこのストリーミングとして読み込むので、m3u8の中身にTS以外をいれるのは厳しい。

AppleTV は iOSSafariと同じになる。AppleTV / iOSはm3u8のmp4未対応みたいだね

m3u8 の中身にアレコレ入れてみる

m3u の中身に、mp4 を入れた結果

app mp4(264/aac) mpegts(264/aac)
VLC
iOS/Safari
Mac/Safari
iTunes

此の時にチェックに使ったものは次の通り。

#EXTM3U
#EXTINF:-1,自分のムービー-sample_0
https://example.com/my-movie.ts
#EXTM3U
#EXTINF:60,自分のムービー-sample_0
https://example.com/my-movie.ts

再生時間には、INT秒以外を入れると動かなかった。正確に時刻を測定したら逆に動かなかったという。

再生時間には-1を入れておくのが無難なようです。

ちなみに、h264/aacの mpegts を mp4(h264/aac)から変換するには次のようにした。

ffmpeg -i input.mp4 -acodec copy -vcodec copy -bsf:v h264_mp4toannexb -t 60 -f mpegts out

ブラウザにキャッシュを許すためには

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:8

# 略...

#EXT-X-ENDLIST

EXT-X-TARGETDURATIONは、各エントリを全部まとめて此のファイルが再生時間が何秒あるか

MEDIA-SEQUENCE はどこから再生を始めるかをエントリ配列の最初から

AppleTV でも再生できる。

AppleTV でruby airplay を試したら、ちゃんと再生できた。

itunes に突っ込んだとき

itunes でもm3u8動作チェックはできる*1

ただしポッドキャストとして扱われるのに、ポッドキャストではなくミュージック一覧にでてきた

itunes に追加する方法

ストリームを開く

f:id:takuya_1st:20170330022721p:plain:w200

URLを入力する

f:id:takuya_1st:20170330022726p:plain:w200

プレイリストに出てくる

f:id:takuya_1st:20170330022730p:plain:w200

結論

m3u8 は mp4 を突っ込んでも iOSで動く。mpegtsに変換するのも時間はほとんどかからない。

また、HLSにあるような細切れになTSにする必要はなかった。

ハードディスクにたまったムービーファイルを AppleTV に配信して連続再生ができるようになった。

youtubeのファイルと組み合わせれば急にCMが入って目がさめること無く連続再生ができるね。

youtubeのプレイリストがm3u8 で取り出せばいいのになぁ。

追記

iOSは m3u8 の URL に GET のパラメータを入れても無視するようでした。

なので直接ファイルを指定しないと駄目なようです。GET引数でリダイレクト仕様としたけど駄目だった。

参考資料

https://en.wikipedia.org/wiki/PLS_(file_format)

https://en.wikipedia.org/wiki/Advanced_Stream_Redirector

*1:たぶんおなじAVFoundationだから?

pythonでHTMLをパースしてXpathする

python でも xpath したい。

libxml でパースするには、lxml を使うと楽

pip install lxml

使い方。

lxml.html を使うと確実に、パースする事ができる。parse は IO を取るのでStringIOを使うことになる。

lxml.html.parse(StringIO(page.html))

サンプル

import lxml.html
from io import StringIO, BytesIO

def parse( node , idx ) :
    name  = node.xpath(".//*[@class='desc-title']//text()")[0]
    url  = node.xpath(".//a/@href")[0]
    img_url  = node.xpath(".//img/@src")[0]
    price = node.xpath('.//div[contains(./@class, "desc-price")]//strong/text()')[0].replace(',','')
    identify_url = page.url + '#' + str(i+1)
    html = lxml.etree.tostring( node ,  pretty_print=True,method='xml', encoding='utf-8').decode('utf-8')
    item = Item(link=url,title=name,price=price,html=html, identify_url=identify_url,img_url=img_url  )
    return session.add(item)


if __name__ == '__main__' : 

    doc = lxml.html.parse(StringIO(page.html))
    ret = doc.xpath("//li[@class='list-item']")

    for i, node in enumerate(ret) : 
      parse( node,i)