Pull to refresh

Скрипт для скачивания подкастов Python + Google Reader

Website development *

Введение


Был полезный пост "Автоматизация закачки подкастов на mp3 плеер". Полезный для меня, поскольку ну не использую iTunes и прочий подобный софт (я не хочу это обсуждать :). Мне только нужно скачать пачку подкастов, которые периодически собираются в ленте ридера. И PHPу предпочитаю Python.

Хотелось бы услышать советы — я только изучаю Python. И мне нравится писать посты с примерами для начинающих. Замечаний бы, критики… Но к делу.

Организация процесса

Список подкастерских лент я храню в Google Reader. Ленты помечены своим тегом, и аккуратно лежат в своей папке:


Для выкачивания новых подкастов, попавших в папку Podcasts, написал небольшой скрипт на Python. В качестве основы взял библиотеку />pyrfeed, в которой реализован полезный класс GoogleReader.

Исходный код библиотеки доступен и включает небольшой пример работы с ней. Есть документация. Правда, я нашел документацию только по API к Google Reader, а не работе с самой библиотекой. Там же есть пример утилиты с Gui-интерфейсом для чтения RSS-лент.

Исходный код

Ссылка на архив с исходником в конце.
А здесь исходник главного скрипта:
import sys
import os
import time
import urlparse
import urllib

import progressBar
import GoogleReader

downloadDir = "myDownloadDir";
logFile = downloadDir + "PodcastsDownloadTool.log";
tag = "Podcasts";
login = "myGoogleReaderLogin";
password = "myGoogleReaderPassword";

def GetLocalFileNameFromURL(fullpath):
    (filepath, filename) = os.path.split(urlparse.urlparse(fullpath).path)
    return downloadDir + filename

def LogMessage(message):
    f = open(logFile,"a")
    print >> f, message;
    f.close();
    pass

def DownloadFile(url, filename):
    progressBar.ResetProgressBar();
    urllib.urlretrieve(url, filename, reporthook = progressBar.ProgressBarReportHook);
    pass

def ProcessPodcastDownloading():
    # Check and create dir
    if not os.path.exists(downloadDir):
        os.mkdir(downloadDir);
        
    # Login to Google Reader
    gr = GoogleReader.GoogleReader();
    gr.identify(login, password);
    if gr.login():
        print "Login OK";
    else:
        print "Login KO";
        return

    xmlfeed = gr.get_feed(feed = "user/-/label/%s" % tag, n = 17, xt = "user/-/state/com.google/read");
    for entry in xmlfeed.get_entries():
        try:
            googleID = entry['google_id'];
            if entry.has_key('enclosure'):
                # Prepare vars and print info
                URLToDownload = entry['enclosure'];
                localFilePath = GetLocalFileNameFromURL(URLToDownload);
                print "Title: %s" % entry['title'];
                print "Download from URL: %s ..." % URLToDownload;
                print "Local file: %s" % localFilePath;

                # Download file
                DownloadFile(url=URLToDownload,filename=localFilePath)
                
                # Log message
                LogMessage("%s %s %s %s\n" % (time.strftime('%x %X'), URLToDownload, googleID, entry['published']));
                
                print "Downloaded.";
                # Mark as readed
                gr.set_read(googleID);
                print "Marked.";
        except:
            #Print and log error
            print "Error: ", sys.exc_info();
            LogMessage("%s\nError: %s\nEntry: %s\nException info: %s\n%s\n" % ("="*80, time.strftime('%x %X'), entry, sys.exc_info(), "="*80));
    pass

if __name__=='__main__' :
    ProcessPodcastDownloading();


Пояснения к коду

Основные параметры задаются в начале скрипта:
  • downloadDir – каталог, куда будут скачиваться подкасты
  • logFile – лог файл
  • tag – имя тега/папки в Google Reader, в которой будут просматриваться ленты
  • login и password – логин и пароль в Google Reader

А дальше ничего сложного:
  • аутентификация в сервисе Google Reader
  • получение распарсенной RSS-ленты
  • цикл по записям с выводом информации и записью в лог
  • собственно, скачивание файлов
  • метка записей прочитанными

Саму библиотеку pyrfeed в приложение не включаю. Её достаточно скачать, внести пару строчек (о которых далее), и положить в допустимое для import’а место. Например, в директорию Lib каталога, куда установлен Python — тогда библиотека станет доступна всем скриптам.
У меня каталоги GoogleReader и web располагаются в той же директории, где находится мой скрипт.

Интерфейс

Это консольная утилита. Делайте выводы.
Просто отображение процесса загрузки выглядит так:


Прогресс-бар взят из какого-то примера. Точно не помню откуда. Примеров в интернете много и большинство друг на друга похожи. Исходник есть в приложении.

Патч для feed.py

К сожалению, класс GoogleFeed не извлекает из полученного XML ссылку на файл для скачивания.
Я решил эту проблему, добавив к парсингу XML после такого фрагмента:
elif dom_entry_element.localName == 'link' :
    if dom_entry_element.getAttribute('rel')=='alternate' :
        entry['link'] = dom_entry_element.getAttribute('href')


Такой кусочек:
if dom_entry_element.getAttribute('rel')=='enclosure' :
    entry['enclosure'] = dom_entry_element.getAttribute('href')


Получилось вот так:
elif dom_entry_element.localName == 'link' :
    if dom_entry_element.getAttribute('rel')=='alternate' :
        entry['link'] = dom_entry_element.getAttribute('href')
    if dom_entry_element.getAttribute('rel')=='enclosure' :
        entry['enclosure'] = dom_entry_element.getAttribute('href')
elif dom_entry_element.localName == 'category' :


Недостатки, которые меня устраивают

  • Не поддерживается докачка. В случае сбоя RSS-запись не будет помечена как прочитанная. При следующем запуске скрипта файл будет выкачан заново.
  • Отсюда следующий момент – при следующем запуске скрипта, ошибочные записи (например, в записи нет ссылки на файл для скачивания, так бывает) будут повторно обрабатываться. Можно бы их метить специальным тегом и пропускать в дальнейшем. Но меня устраивает последующий ручной просмотр ленты на предмет не прочитанных записей.
  • Хранение конфигурации – логин и пароль в открытом виде. Логин еще не так страшно, а вот пароль… Можно использовать функцию getpass() или хранить его в другом месте.
    Можно автоматизировать запуск скрипта при подключении USB-флешки или плеера, например при помощи утилиты USB Detect & Launch (о нем уже было сказано на хабре).

Финиш

И Исходники в архиве.
А заметку скопипастил со своей страницы.
Tags:
Hubs:
Total votes 33: ↑31 and ↓2 +29
Views 5K
Comments Comments 29