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

ポッドキャストを聞く場合、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
タイムゾーンを追加しました。

  • このエントリーをはてなブックマークに追加

コメントをどうぞ

メールアドレスが公開されることはありません。 が付いている欄は必須項目です