16:2a4c890a667a
Anton Shestakov <engored@ya.ru>, Fri, 26 Sep 2014 14:35:43 +0900
youtube-watch: download option, don't rely on publication time for new_entries.

previous change 15:0a64b0583576

youtube-watch/watch.py

Permissions: -rw-r--r--

Other formats: Feeds:
import subprocess
import sys
from argparse import ArgumentParser, FileType
from calendar import timegm
from contextlib import contextmanager
from operator import itemgetter
from time import localtime, sleep, strftime
import feedparser
def user_entries(user):
url = 'https://gdata.youtube.com/feeds/api/users/%s/uploads?v=2' % user
feed = feedparser.parse(url)
return feed['entries']
def prepare_entries(entries, limit=None):
entries = sorted(entries, key=itemgetter('published_parsed'))
if limit is not None:
entries = entries[-limit:]
return entries
def formatter(template, entries):
for entry in entries:
entry['link'] = entry['link'].replace('&feature=youtube_gdata', '')
entry['published_nice'] = strftime('%Y-%m-%d %H:%M:%S', localtime(timegm(entry['published_parsed'])))
print template.format(**entry)
def get_template(candidate):
if candidate is None:
return templates['default']
elif candidate in templates:
return templates[candidate]
else:
return candidate.decode('utf-8')
templates = {
'default': u'{link:<43} | {published_nice:<19} | {author:<25} | {title}',
'long': u'{title}\nBy {author} ({link})'
}
@contextmanager
def activity_status(msg):
sys.stderr.write(msg)
sys.stderr.flush()
yield
sys.stderr.write('\r' + ' ' * len(msg) + '\r')
sys.stderr.flush()
def fetch_entries(users, delay=0):
entries = []
for user in users:
if delay:
msg = 'Sleeping for %s' % delay
with activity_status(msg):
sleep(delay)
msg = 'Fetching entries for %s' % user
with activity_status(msg):
entries += user_entries(user)
return entries
def download(entries):
if entries:
subprocess.call(['cclive', '--continue', '--timestamp', '--stream', 'best'] + [entry['link'] for entry in entries])
def identify(entry):
return entry['id'].rpartition(':')[2]
def main():
parser = ArgumentParser()
parser.add_argument('-U', '--user', action='append', dest='users', help='author of uploads', metavar='USER [+]')
parser.add_argument('-F', '--input-file', type=FileType('r'), help='file with users')
parser.add_argument('-T', '--template', help='template for python .format()')
parser.add_argument('-l', '--limit', type=int, help='limit number of initial videos')
parser.add_argument('-f', '--follow', action='store_true', help='continuous mode')
parser.add_argument('-d', '--delay', type=int, help='delay for continuous mode', default=60)
parser.add_argument('-D', '--download', action='store_true', help='download each video')
args = parser.parse_args()
template = get_template(args.template)
users = args.users or []
if args.input_file is not None:
users += args.input_file.read().splitlines()
entries = fetch_entries(users)
earlier = {identify(entry) for entry in entries}
entries = prepare_entries(entries, args.limit)
formatter(template, entries)
if args.download:
download(entries)
if not args.follow:
return
try:
while True:
entries = fetch_entries(users, args.delay)
new_entries = [entry for entry in entries if identify(entry) not in earlier]
earlier |= {identify(entry) for entry in new_entries}
new_entries = prepare_entries(new_entries)
formatter(template, new_entries)
if args.download:
download(new_entries)
except KeyboardInterrupt:
print
if __name__ == '__main__':
main()