X-Git-Url: https://disinclined.org/git/?a=blobdiff_plain;f=likes_pandora.py;h=181cda7fc3e3605a66d064335200a92533432e00;hb=c781e8de3d210801af58a05160e0fff12ff0b0b6;hp=cd066e880a58ad79a68885c9a9b001d3c3a59012;hpb=8e57a07a7ec649864e8152b8d3e1e1a1e5fba14f;p=i_like_pandora.git diff --git a/likes_pandora.py b/likes_pandora.py old mode 100644 new mode 100755 index cd066e8..181cda7 --- a/likes_pandora.py +++ b/likes_pandora.py @@ -1,26 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + __author__ = ("Dylan Lloyd ") __license__ = "BSD" -# SETTINGS +default_options = { + 'notifications' : 'true', + # NOTIFICATIONS must be a string due to issues noted here: + # http://bugs.python.org/issue974019 + # ConfigParser.getboolean fails when falling back to the default value + # if the value type is bool. + 'youtube-dl' : '/usr/bin/youtube-dl', + 'default_icon' : '/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-shockwave-flash.png', + 'youtube-dl_options' : '--no-progress --ignore-errors --continue --max-quality=22 -o "%(stitle)s---%(id)s.%(ext)s"' +} + +import ConfigParser # This module has been renamed to configparser in python 3.0 +import sys +import os -USER = 'alphabethos' -DIR = '/home/dylan/pandora/' -YT_DL = '/usr/bin/youtube-dl' # Path to youtube-dl -NOTIFICATIONS = True -DEFAULT_ICON ='/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-shockwave-flash.png' -YT_OPT = '--no-progress --ignore-errors --continue --max-quality=22 -o "%(stitle)s---%(id)s.%(ext)s"' -# END OF SETTINGS +CONFIG_FILE= os.path.join(os.path.expanduser('~'), '.i_like_pandora.config') +config = ConfigParser.ConfigParser(default_options) +loaded_files = config.read(CONFIG_FILE) # config.read returns an empty array if it fails. +if len(loaded_files) == 0: + print 'Can\'t find a configuration file at', CONFIG_FILE + sys.exit() +try: + USER = config.get('settings', 'username') + DIR = os.path.expanduser(config.get('settings', 'download_folder')) + NOTIFICATIONS = config.getboolean('settings', 'notifications') + YT_DL = config.get('settings', 'youtube-dl') + DEFAULT_ICON = config.get('settings', 'default_icon') +except: + print 'There is a formatting error in the configuration file at', CONFIG_FILE + sys.exit() +from BeautifulSoup import BeautifulSoup import urllib import urllib2 -from BeautifulSoup import BeautifulSoup -import pynotify -import tempfile -import string -import hashlib -import os -import shlex, subprocess import re +import copy +import shlex, subprocess + +if NOTIFICATIONS: + import pynotify + import hashlib + import tempfile + import string def fetch_stations(user): """ This takes a pandora username and returns the a list of the station tokens that the user is subscribed to. """ @@ -36,10 +62,9 @@ def fetch_stations(user): return stations def fetch_tracks(stations): - """ Takes a list of station tokens and returns a list of youtube search urls. - What this should really do is just return the Title + Artist strings. + """ Takes a list of station tokens and returns a list of Title + Artist strings. """ - search_urls = [] + search_strings = [] for station in stations: page = urllib.urlopen('http://www.pandora.com/favorites/station_tablerows_thumb_up.vm?token=' + station + '&sort_col=thumbsUpDate') page = BeautifulSoup(page) @@ -54,48 +79,56 @@ def fetch_tracks(stations): if len(titles) == len(artists): i = 0 for title in titles: - search_url = 'http://youtube.com/results?search_query=' + urllib.quote_plus(title + ' ' + artists[i]) - search_urls.append(search_url) + search_string = title + ' ' + artists[i] + search_strings.append(search_string) i += 1 else: - pass ## ERROR - return search_urls + # This would mean something strange has happened: there + # aren't the same number of titles and artist names on a + # station page. + pass + return search_strings -def fetch_search_video_ids(search_urls): - """ This takes a list of youtube search urls and tries to find the first result. It returns a list of youtube video ids. - It really should take a list of ids instead. +def search_youtube(search_strings): + """ This takes a list of search strings and tries to find the first result. It returns a list of the youtube video ids of those results. """ video_list = [] - for url in search_urls: - page = urllib.urlopen(url) + for search_string in search_strings: + search_url = 'http://youtube.com/results?search_query=' + urllib.quote_plus(search_string) + page = urllib.urlopen(search_url) page = BeautifulSoup(page) result = page.find('div', attrs={'class':'video-main-content'}) + if result == None: + print 'odd feedback for search, could not find div at ', search_url + continue for attr, value in result.attrs: if attr == 'id' and len(value[19:]) == 11: video_list.append(value[19:]) elif attr == 'id': - print 'odd feedback for url', url, " : ", value[19:] + print 'odd feedback for search', search_url, " : ", value[19:] return video_list -def check_for_existing(): - """ Checks the download-folder for existing videos with same id and removes from videolist. """ - videolist = get_video_ids() +def check_for_existing(video_list): + """ Checks the download-folder for existing videos with same id and removes from video_list. """ filelist = os.listdir(DIR) - for video in copy.deepcopy(videolist): + i = 0 + for video in copy.deepcopy(video_list): for files in filelist: if re.search(video,files): - del videolist[video] - return videolist + del video_list[i] + i -= 1 + i += 1 + return video_list -def fetch_videos(videolist): +def fetch_videos(video_list): """ Uses subprocess to trigger a download using youtube-dl of the list created earlier, and triggers notifications if enabled. """ os.chdir(DIR) args = shlex.split(YT_DL + ' ' + YT_OPT) if NOTIFICATIONS: regex = re.compile("\[download\] Destination: (.+)") - for item in videolist: - if item: - thread = subprocess.Popen(args + [item], stdout=subprocess.PIPE) + for video in video_list: + if video: + thread = subprocess.Popen(args + ["http://youtube.com/watch?v=" + video], stdout=subprocess.PIPE) output = thread.stdout.read() if NOTIFICATIONS: video_file = regex.findall(output) @@ -110,7 +143,7 @@ def fetch_videos(videolist): if not os.path.isfile(thumbnail): opener = urllib2.build_opener() try: - page = opener.open('http://img.youtube.com/vi/' + item + '/1.jpg') + page = opener.open('http://img.youtube.com/vi/' + video + '/1.jpg') thumb = page.read() # The thumbnail really should be saved to # ~/.thumbnails/normal (Thumbnail Managing @@ -131,12 +164,14 @@ def fetch_videos(videolist): note = pynotify.Notification(title, 'video downloaded', thumbnail) note.show() - def main(): stations = fetch_stations(USER) - search_urls = fetch_tracks(stations) - video_list = fetch_search_video_ids(search_urls) - fetch_videos(video_list) + if len(stations) == 0: + print 'Are you sure your pandora profile is public? Can\'t seem to find any stations listed with your account.' + search_strings = fetch_tracks(stations) + videos = search_youtube(search_strings) + videos = check_for_existing(videos) + fetch_videos(videos) if __name__ == "__main__": main()