2 # -*- coding: utf-8 -*-
4 __author__
= ("Dylan Lloyd <dylan@psu.edu>")
8 'notifications' : 'true',
9 # NOTIFICATIONS must be a string due to issues noted here:
10 # http://bugs.python.org/issue974019
11 # ConfigParser.getboolean fails when falling back to the default value
12 # if the value type is bool.
13 'youtube-dl' : '/usr/bin/youtube-dl',
14 'default_icon' : '/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-shockwave-flash.png',
15 'youtube-dl_options' : '--no-progress --ignore-errors --continue --max-quality=22 -o "%(stitle)s---%(id)s.%(ext)s"'
18 import ConfigParser
# This module has been renamed to configparser in python 3.0
22 CONFIG_FILE
= os
.path
.join(os
.path
.expanduser('~'), '.i_like_pandora.config')
23 config
= ConfigParser
.ConfigParser(default_options
)
24 loaded_files
= config
.read(CONFIG_FILE
) # config.read returns an empty array if it fails.
25 if len(loaded_files
) == 0:
26 print 'Can\'t find a configuration file at', CONFIG_FILE
29 USER
= config
.get('settings', 'username')
30 DIR
= os
.path
.expanduser(config
.get('settings', 'download_folder'))
31 NOTIFICATIONS
= config
.getboolean('settings', 'notifications')
32 YT_DL
= config
.get('settings', 'youtube-dl')
33 DEFAULT_ICON
= config
.get('settings', 'default_icon')
34 YT_OPT
= default_options
['youtube-dl_options']
36 print 'There is a formatting error in the configuration file at', CONFIG_FILE
39 from search_classes
import pandora_fetch
, search_youtube
, found_video
44 import shlex
, subprocess
52 def fetch_tracks(stations
):
53 """ Takes a list of station tokens and returns a list of Title + Artist strings.
56 for station
in stations
:
57 page
= urllib
.urlopen('http://www.pandora.com/favorites/station_tablerows_thumb_up.vm?token=' + station
+ '&sort_col=thumbsUpDate')
58 page
= BeautifulSoup(page
)
61 for span
in page
.findAll('span', attrs
={'class':'track_title'}):
62 for attr
, value
in span
.attrs
:
63 if attr
== 'tracktitle':
65 for anchor
in page
.findAll('a'):
66 artists
.append(anchor
.string
)
67 if len(titles
) == len(artists
):
70 search_string
= title
+ ' ' + artists
[i
]
71 search_strings
.append(search_string
)
74 # This would mean something strange has happened: there
75 # aren't the same number of titles and artist names on a
80 def check_for_existing(video_list
):
81 """ Checks the download-folder for existing videos with same id and removes from video_list. """
82 filelist
= os
.listdir(DIR
)
84 for video
in copy
.deepcopy(video_list
):
85 for files
in filelist
:
86 if re
.search(video
,files
):
92 def fetch_videos(video_list
):
93 """ Uses subprocess to trigger a download using youtube-dl of the list created earlier, and triggers notifications if enabled. """
95 args
= shlex
.split(YT_DL
+ ' ' + YT_OPT
)
96 if NOTIFICATIONS
: regex
= re
.compile("\[download\] Destination: (.+)")
97 for video
in video_list
:
99 thread
= subprocess
.Popen(args
+ ["http://youtube.com/watch?v=" + video
], stdout
=subprocess
.PIPE
)
100 output
= thread
.stdout
.read()
102 video_file
= regex
.findall(output
)
103 if len(video_file
) == 0:
105 thumbnail
= hashlib
.md5('file://' + DIR
+ video_file
[0]).hexdigest() + '.png'
106 # Two '/'s instead of three because the path is
107 # absolute; I'm not sure how this'd work on windows.
108 title
, sep
, vid_id
= video_file
[0].rpartition('---')
109 title
= string
.replace(title
, '_', ' ')
110 thumbnail
= os
.path
.join(os
.path
.expanduser('~/.thumbnails/normal'), thumbnail
)
111 if not os
.path
.isfile(thumbnail
):
112 opener
= urllib2
.build_opener()
114 page
= opener
.open('http://img.youtube.com/vi/' + video
+ '/1.jpg')
116 # The thumbnail really should be saved to
117 # ~/.thumbnails/normal (Thumbnail Managing
119 # [http://jens.triq.net/thumbnail-spec/]
120 # As others have had problems anyway
121 # (http://mail.gnome.org/archives/gnome-list/2010-October/msg00009.html)
122 # I decided not to bother at the moment.
123 temp
= tempfile
.NamedTemporaryFile(suffix
='.jpg')
126 note
= pynotify
.Notification(title
, 'video downloaded', temp
.name
)
128 note
= pynotify
.Notification(title
, 'video downloaded', DEFAULT_ICON
)
130 # Generally, this will never happen, because the
131 # video is a new file.
132 note
= pynotify
.Notification(title
, 'video downloaded', thumbnail
)
136 stations
= pandora_fetch(USER
)
138 for title
, artist
in stations
.tracks
.iteritems():
139 search
= title
+ " " + artist
140 searches
.append(search
)
141 videos
= search_youtube(searches
);
142 videos
= check_for_existing(videos
.track_ids
)
145 if __name__
== "__main__":