mp3ファイルのタグ編集 eyeD3

ポッドキャストをスマートフォンにダウンロードして聞いています。あるフォルダ以下のmp3ファイルをまとめて聞きたいので、全mp3ファイルのアルバム名をフォルダ名に変更できないか試してみました。

mp3ファイルのタグ名を変更するツールとしてeyeD3を使いました。eyeD3はpythonのライブラリですが、コマンドで呼び出すこともできました。

インストールはFreeBSDの場合、portsを使いました。

cd /usr/ports/audio/py-eyed3/
sudo make
sudo make install

Ubuntuでは、easy_install、pipを入れてからeyeD3を入れました。
* easy_install http://pypi.python.org/pypi/setuptools

sudo /home/hiroki/Downloads/setuptools-0.6c11-py2.7.egg

* pip

sudo easy_install pip

* eyeD3 http://eyed3.nicfit.net/installation.html

sudo pip install eyeD3</pre>

mp3ファイルのアルバム名は以下のようにしました。ID3タグのv2.2だと書き込みがうまくいかなかったので、v2.3への書き換えも指定しました。eyeD3のバージョン0.7.1-finalでは-Qオプション(標準出力を減らす)が使えます。以下は0.6.18で確認しました。

eyeD3 --to-v2.3 -A タイトル mp3ファイル

参考:

mp3 ファイルの id3 タグをいじる(python で日本語で id3v2)

moshを使う

mosh(mobile shell)はモバイル環境での使用を想定したsshに似たコマンドです。特徴としては、リモートマシンへの接続がスリープやハイバネートによる、マシンの中断から再開した後も保持される、ネットワークのローミングに対応している、などです。(似たコマンドにtmuxというコマンドもあるようです。)

使用の際は、クライアント側・サーバ側の両方で、文字コードをUTF-8にする
必要があります。

サーバ側(FreeBSD)では、~/.login_confを以下のように作成して、接続を確認しました。

me:\
   :charset=utf-8:\
   :lang=ja_JP.UTF-8:

参考:

http://mosh.mit.edu/

http://www.sssg.org/blogs/naoya/archives/2267

http://d.hatena.ne.jp/mutsune/20120416/1334590736

githubを使う

ポッドキャストをダウンロードするスクリプトをgithubにおいてみました。

https://github.com/hrktir/download_podcast_mp3

–sinceの指定がうまくいってなかったのを修正しています。

githubの接続に、Windows用のgitを試してみましたがうまく行かなかったのでCygwin用でリトライしてみました。sshの公開鍵をgithubに登録する必要があって、それをしていなたったため、コケていたようです。(Windows用のgitクライアントでは気づきませんでした。)

mp3ファイルの音量を調整する

「ポッドキャストをダウンロードする」で、用意したmp3ファイルを聞くとファイルによって音量が違っていることに気づきました。

mp3ファイルの音量を調整するツールにmp3gainがあるようなので、これを使ってみました。

インストールはpkg_addで行いました。

# pkg_add -r mp3gain

音量の調整は、-rオプション(指定したファイルの音量を同じ大きさにする)で行いました。ファイルのタイムスタンプを変えないように、-pもつけます。

$ mp3gain -r -p *.mp3

すべてのmp3ファイルを対象にすると、処理に時間がかかるので、音量が小さいファイルのみを指定すると良いようです。

ポッドキャストをダウンロードする

ポッドキャストを聞く場合、PCを使っている時はiTunesを使うのですが、車中で聞く場合は、USBメモリをチューナーに差して聞いています。

このUSBメモリにPC上のmp3のファイルを手作業でコピーするのが少々面倒なので、スクリプトでやってみることにしました。

やることは、ポッドキャストのデータから過去n時間以内に公開されたのmp3ファイルをダウンロードする、です。幾つかのファイルが揃ったらそれをDropbox側に移動させます。(Dropbox側へのファイルコピーはdropbox-apiを使ってみるを使うことにします。)

ポッドキャストのデータからmp3ファイルをダウンロードする方法ですが、スクリプトを書いてみました(download_podcast_mp3.py)。ネットで似たようなスクリプトを見つけたのですが、公開時期でファイルを選択させる機能がほしかったので書いた次第です。

import urllib2
from xml.dom.minidom import parse
from time import strptime
from datetime import datetime
from datetime import timedelta
import time
import re
import os
import sys


# The following url is feed format and can not be accepted. 
# url = "http://www.bbc.co.uk/worldservice/learningenglish/general/sixminute/index.xml"
# The following url is rss format and can be accepted.
# url = "http://downloads.bbc.co.uk/podcasts/worldservice/how2/rss.xml"

def getPodcastXmlDom(url):
    response = urllib2.urlopen(url)
    #msg = response.read()
    dom1 = parse(response)
    return dom1

def getItemList(dom):
    items = dom.getElementsByTagName('item')
    if len(items) > 0:
        return parseItemsAsRSS(items)
    else:
        raise Exception("no item element found")

def parseItemsAsRSS(items):
    results = []
    for item in items:
        idict = dict()

        enc = item.getElementsByTagName('enclosure')
        if len(enc) == 1:
            idict["url"] = enc[0].getAttribute("url")

        idate = item.getElementsByTagName('pubDate')
        if len(idate) == 1:
            idict["date"] = getGMTDatetime(idate[0].firstChild.wholeText)

        ititle = item.getElementsByTagName('title')
        if len(ititle) == 1:
            idict["title"] = ititle[0].firstChild.wholeText

        if idict["url"] is not None and idict["date"] is not None and idict["title"] is not None:
            results.append(idict)
    return results

def getGMTDatetime(idateStr):
    tlag = 0
    if re.search("[\+\-][0-9]{4}",idateStr):
        tlag = int( re.findall("[\+\-][0-9]{4}", idateStr)[0] ) / 100     
        idateStr = re.sub("[\+\-][0-9]{4}", "GMT", idateStr)
    for s, v in {
       "ADT":-3,
       "AST":-4,
       "EDT":-4,
       "EST":-5,
       "PDT":-7,
       "PST":-8,
       "JST":9
    }.iteritems():
        if re.search(s, idateStr):
            tlag = v
            idateStr = re.sub(s, "GMT", idateStr)
    idateValue = strptime(idateStr, "%a, %d %b %Y %H:%M:%S %Z")
    idate = datetime(idateValue.tm_year,idateValue.tm_mon, idateValue.tm_mday, idateValue.tm_hour, idateValue.tm_min, idateValue.tm_sec)
    idate = idate - timedelta(hours = tlag)
    return idate
 
def getFilename4mp3(idict):
    ret = re.sub("[ :]", "_", idict["title"])
    ret = ret + "_"
    ret = ret + idict["date"].strftime("%Y_%m_%d_%H_%M")
    ret = ret + ".mp3"
    return ret

def downloadFile(url, filename):
    print "download " + url + " as " + filename
    response = urllib2.urlopen(url)
    tofile = open(filename,"w")
    tofile.write(response.read())        
    response.close()
    tofile.close()

def changeAccessTime(filename, pubdate):
    t = int(time.mktime(pubdate.timetuple()))
    os.utime(filename, (t,t))

def getLatestItem(items, nhoursago):
    tdy = datetime.today()
# make t as GMT 
    t = datetime(tdy.year, tdy.month, tdy.day, tdy.hour, tdy.minute)
# assume this environment is in JST (+0900)
    t = t - timedelta(seconds = 9 * 3600)

    ndaysago = nhoursago % 24
    nsecsago = (nhoursago - 24 * ndaysago) * 3600
    
    results = filter(lambda i:i["date"] > t - timedelta(days = ndaysago, seconds = nsecsago) ,items)
    return results

def main():
    if len(sys.argv) < 2:
        print "Usage:" + sys.argv[0] + " url_of_podcast_rss [options]"
        print """Options:
    --since n      : gets mp3s newer than n hours ago. 
                     default is 148 (24hours * 7days) 
    --title TITLE  : uses TITLE as filename
"""
        sys.exit()
    url = sys.argv[1]
    nhoursago = 7 * 24
    alttitle = None
    for i in range(2, len(sys.argv)):
        if sys.argv[i] == "--since" and i + 1 < len(sys.argv):
            nhoursago = int(sys.argv[i + 1])
        if sys.argv[i] == "--title" and i + 1 < len(sys.argv):
            alttitle = sys.argv[i + 1]

#    items = getItemList(getPodcastXmlDom(url))
    items = getLatestItem(getItemList(getPodcastXmlDom(url)),nhoursago)
    for item in items:
        if alttitle:
            item["title"] = alttitle
        downloadFile(item["url"], getFilename4mp3(item))
        changeAccessTime(getFilename4mp3(item), item["date"])

def testGetGMTDatetime():
    print getGMTDatetime("Sun, 22 Jan 2012 13:00:01 +0000")
    print getGMTDatetime("Thu, 27 Jan 2012 22:48:45 PDT")
    print getGMTDatetime("Thu, 26 Jan 2012 08:44:15 -0800")
    print getGMTDatetime("Fri, 27 Jan 2012 03:30:33 EST")

if __name__ == '__main__':
#    testGetGMTDatetime()
    main()

以下使い方です。


$ python download_podcast_mp3.py ポッドキャストのURL [--since n] [--title TITLE]

対象となるmp3ファイルがあれば、カレントディレクトリにそのファイルが保存されます。ファイル名は「title_2012_01_27_01_23_45.mp3」のようにポッドキャストXML内のtitle要素 + pubDate要素を使います。

「–since n」は今からn時間前以降に公開されたファイルを対象とすることを指定します。デフォルトは148(一週間前)になります。
「–title TITLE」はファイル名にtitle要素以外の文字列を指定する場合に使用します。これはtitleに日本語が含まれる場合にうまく保存できないのを避けるための用意しています。

タイムゾーンの扱いは、きっちりやっていません。PDT、EDT、JST以外のタイムゾーンを扱う場合は、該当するタイムゾーン文字列とGMTとの時間差をdictで書いている部分がありますので、そこを変更してみてください。

追記:20120328
タイムゾーンを追加しました。

svg から png に変換する

ある形式の画像ファイルを別の画像ファイルに変換するには、
ImageMagickのconvertコマンドが使えるのですが、svg形式から
png形式に変換する場合、convertはrsvgというコマンドを呼び
出して変換処理を実行しているようでした。

ぐぐってみるとrsvgはlibrsvg2に付属しているようです。
パッケージからインストールするため、管理者ユーザで次のコマンドを実行しました。

# pkg_add -r librsvg2

変換処理は、次のように実行できました。

$ rsvg hoge.svg hoge.png

ImageMagickをインストールしている場合は、次のコマンドでも可能でした。

$ convert hoge.svg hoge.png

ではまた

dropbox-apiを使ってみる

ご存じと思いますがDropboxはPCやスマートフォンでファイルを共有するサービスです。

このDropboxにコマンドでファイルの操作ができるか試してみました。
事前にDropbox developers https://www.dropbox.com/developers
にてアプリ鍵、アプリ秘密鍵を取得しておきます。

使用するのはdropbox-api-commandです。portsにありますのでそれを使いました。

cd /usr/ports/net/dropbox-api-command
sudo make install
sudo make clean

インストール後、セットアップします。
鍵を入力後、ブラウザでURLにアクセスするとDropbox側の認証が完了するようです。

$ dropbox-api setup
Please Input API Key: XXXXXXXXXXXXX アプリ鍵
Please Input API Secret: XXXXXXXXXXXXXXX アプリ秘密鍵
URL: https://www.dropbox.com/0/oauth/authorize?oauth_token=XXXXXXXXXXXXXXXXXX&oauth_callback=
Please Access URL and press Enter
OK?
success! try
> dropbox-api ls
> dropbox-api find /
$ dropbox-api ls

以下のコマンドを使ってみました。

ヘルプ
dropbox-api help

コマンドの詳細を見る
dropbox-api help ls

ファイルアップロード(ディレクトリが無い場合自動的に作成)
dropbox-api put test.txt dropbox:/test_dir

ファイルの同期(ディレクトリが無い場合自動的に作成)
dropbox-api sync test_dir2 dropbox:/test_dir2

ファイル・ディレクトリの削除(ディレクトリはファイルがあっても削除できます。)
dropbox-api rm test_dir2

このコマンドを利用して例えばスクリプトでダウンロード
したファイルをDropboxにアップロード、などできますね。

ではまた