LoginSignup
2
2

More than 5 years have passed since last update.

演奏時間とその合計を出力する

Last updated at Posted at 2015-09-17

実行例

まず、結論からいってこのような出力を得られる

lMusic 交響曲 | perl -lne 'system "exif $_ "' | nkf -w | ~/Python_instance/exif2name_time.py
1:33:13
---------
  0:07:39 交響曲第25番ト短調.wav
  0:07:40 交響曲第40番ト短調.wav
  0:06:36 交響曲第40番ハ短調.wav
  0:13:00 Dvorak交響曲第9番_新世界より_第4楽章.wav
  0:19:25 チャイコフスキー_交響曲第6番_ロ短調_悲愴_第1楽章.wav
  0:35:53 メニューイン指揮ドヴォルザーク交響曲第8番.wav
  0:03:00 メンデルスゾーン_交響曲3番_スコットランド_序曲_フィンガルの洞窟.wav

解説

概要としては lMusic でHDD内のwavファイルを絞り込みそれをプレイリストとして見立て
る。それにsoxなどのplayを繋げば該当するwavが全て聞けるわけだが、終わるまでにどの
程度の時間が掛かるのか気になるところだ。
ファイルから再生時間を得るにはexiftoolがお手軽だ。cygwinでは/usr/bin/exif として
インストールしたか、或いはプリインストールされていた。Linuxならaptなどでインストー
ルすることになる。
exifは1つのファイルに対して[[File Name:filename], .., [Duration:0:03:00]]のよう
な連想配列を思わせる出力をする。ここでは0:03:00のような時間を合計するのに適した
pythonを使って処理する。時間を取り扱うdatetimeが最初から入っているから手軽という
意味で適しているだろう。

lMusic

これは前回紹介した関数で、引数を1つ与えるとwavファイル名からgrepしてフルパスを出力する。

.zshrc
lMusic () {
        if [[ $# -eq 0 ]]
        then
                cd f:/Music_Movie > /dev/null
                ls -v -F --color=auto **/*wav
                cd $OLDPWD > /dev/null
                return
        fi
        ls -v -F --color=auto f:/Music_Movie/**/*wav | grep --color -P "$1"
}

perl

ワンライナーでexifにフルパスを繋ぐ。"exif $_"と処理の形が露出するので分かりやすい。

exif

-h から抜粋すると「exiftool - Read and write meta information in files」である。
今回は再生時間を抜き出すには大げさな道具である。pythonコードはこれの出力処理といっ
ても過言ではない。nkfを使っているのは何故かexiftoolの標準出力がshift-jisで漢字が
文字化けするからその対策。cygwinのみ化ける。Linuxの方では化けなかった。つまり、
utf-8からshift-jisの間で壊れるファイル名の場合にはエラーが出るだろう。
なおオプションで演奏時間とファイル名だけ抜き出すと今回2倍以上の高速化ができる。

python script

exif2name_time.py
#!/usr/bin/env python3
import sys
import datetime


exif_out = sys.stdin
name = []
play_time = []
total_time = datetime.timedelta(0, 0, 0)


def total_timer(time_form):
    """time_form sample is (0:02:18, 0:01:23) """
    td = datetime.timedelta(0)
    time_hms = [[int(time) for time in times.split(':')]
        for times in time_form]
    duration = sum([datetime.timedelta(hours=h, minutes=m, seconds=s)
        for h, m, s in time_hms], td)
    return duration

for line in exif_out:
    key_and_value = [ l.strip() for l in line.partition(':')]
    if key_and_value[0] == "File Name":
        name.append(key_and_value[2])
    if key_and_value[0] == "Duration":
        play_time.append(key_and_value[2])

duration = total_timer(play_time)
print("{0}".format(duration))
print("-" * 9)

for (name, play_time) in zip(name, play_time):
    print("{0:>9} {1:<}".format(play_time, name))

標準入力を受け取るためにsysを、時間を処理するためにdatetimeをインポートする。
次の段落ではグローバル変数の宣言と初期化をする。
さらに次の段落ではtotal_timer関数を定義し、これの引数はhh:flag_mm:ss型の文字列を1つの
要素として持つリストである。返り値は合計時間で数字型だ。datetime.timedeltaの中は
数字型なのでintを使う。
for段落は標準入力を処理する。文字列メソッドpartitionは引数にマッチする最初の1つ
で分解するので、Durationの右側の0:02:18のような時間表示がそのまま受け取れる。
最後の2つの段落は出力部分である。前者は総合時間を書き出し、後者はプレイ時間とファ
イル名を書き出す。左端から9つの固定長レコードを時間のために割き、左寄せと右寄せ
と上下関係で総合時間とそれぞれの時間を差別化しながら"---------"で時間表示区分と
いうまとまりを作った。

環境

python --version ; uname
Python 3.4.3
CYGWIN_NT-6.0
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2