Add tqdm requirement; Display download status in plex-download

This commit is contained in:
Michael Shepanski 2017-08-14 23:40:28 -04:00
parent afd6201f29
commit d7276e2e82
5 changed files with 46 additions and 24 deletions

View file

@ -511,7 +511,6 @@ class Playable(object):
"""
filepaths = []
locations = [i for i in self.iterParts() if i]
for location in locations:
filename = location.file
if keep_orginal_name is False:
@ -521,14 +520,10 @@ class Playable(object):
download_url = self.getStreamURL(**kwargs)
else:
download_url = self._server.url('%s?download=1' % location.key)
filepath = utils.download(download_url,
filename=filename,
savepath=savepath,
session=self._server._session)
filepath = utils.download(download_url, filename=filename, savepath=savepath,
session=self._server._session, **kwargs)
if filepath:
filepaths.append(filepath)
return filepaths
def stop(self, reason=''):

View file

@ -8,6 +8,7 @@ import zipfile
from datetime import datetime
from getpass import getpass
from threading import Thread
from tqdm import tqdm
from plexapi import compat
from plexapi.exceptions import NotFound
@ -229,7 +230,7 @@ def downloadSessionImages(server, filename=None, height=150, width=150, opacity=
return info
def download(url, filename=None, savepath=None, session=None, chunksize=4024, unpack=False, mocked=False):
def download(url, filename=None, savepath=None, session=None, chunksize=4024, unpack=False, mocked=False, showstatus=False):
""" Helper to download a thumb, videofile or other media item. Returns the local
path to the downloaded file.
@ -270,9 +271,13 @@ def download(url, filename=None, savepath=None, session=None, chunksize=4024, un
return fullpath
# save the file to disk
log.info('Downloading: %s', fullpath)
if showstatus:
bar = tqdm(unit='B', unit_scale=True)
with open(fullpath, 'wb') as handle:
for chunk in response.iter_content(chunk_size=chunksize):
handle.write(chunk)
if showstatus:
bar.update(len(chunk))
# check we want to unzip the contents
if fullpath.endswith('zip') and unpack:
with zipfile.ZipFile(fullpath, 'r') as handle:
@ -322,3 +327,25 @@ def getMyPlexAccount(opts=None):
password = getpass('What is your plex.tv password: ')
print('Authenticating with Plex.tv as %s..' % username)
return MyPlexAccount(username, password)
def choose(msg, items, attr):
""" Command line helper to display a list of choices, asking the
user to choose one of the options.
"""
# Return the first item if there is only one choice
if len(items) == 1:
return items[0]
# Print all choices to the command line
print()
for index, i in enumerate(items):
name = attr(i) if callable(attr) else getattr(i, attr)
print(' %s: %s' % (index, name))
print()
# Request choice from the user
while True:
try:
number = int(input('%s: ' % msg))
return items[number]
except (ValueError, IndexError):
pass

View file

@ -179,7 +179,7 @@ class Movie(Video, Playable):
url = self.getStreamURL(**kwargs)
else:
self._server.url('%s?download=1' % location.key)
filepath = utils.download(url, filename=name, savepath=savepath, session=self._server._session)
filepath = utils.download(url, filename=name, savepath=savepath, session=self._server._session, **kwargs)
filepaths.append(filepath)
return filepaths
@ -481,13 +481,12 @@ class Episode(Video, Playable):
return '<%s>' % ':'.join([p for p in [
self.__class__.__name__,
self.key.replace('/library/metadata/', '').replace('/children', ''),
'%s-s%se%s' % (self.grandparentTitle.replace(' ', '-')[:20], self.seasonNumber, self.index),
'%s-%s' % (self.grandparentTitle.replace(' ', '-')[:20], self.seasonEpisode),
] if p])
def _prettyfilename(self):
""" Returns a human friendly filename. """
return '%s.S%sE%s' % (self.grandparentTitle.replace(' ', '.'),
str(self.seasonNumber).zfill(2), str(self.index).zfill(2))
return '%s.%s' % (self.grandparentTitle.replace(' ', '.'), self.seasonEpisode)
@property
def locations(self):
@ -503,6 +502,11 @@ class Episode(Video, Playable):
self._seasonNumber = self.parentIndex if self.parentIndex else self.season().seasonNumber
return utils.cast(int, self._seasonNumber)
@property
def seasonEpisode(self):
""" Returns the s00e00 string containing the season and episode. """
return 's%se%s' % (str(self.seasonNumber).zfill(2), str(self.index).zfill(2))
def season(self):
"""" Return this episodes :func:`~plexapi.video.Season`.. """
return self.fetchItem(self.parentKey)

View file

@ -3,4 +3,5 @@
# pip install -r requirments.txt
#---------------------------------------------------------
requests
tqdm
websocket-client

View file

@ -12,23 +12,18 @@ from plexapi import utils
from plexapi.compat import unquote
from plexapi.video import Episode, Movie, Show
def choose(msg, items, attr):
print()
for index, i in enumerate(items):
name = attr(i) if callable(attr) else getattr(i, attr)
print(' %s: %s' % (index, name))
number = int(input('\n%s: ' % msg))
return items[number]
VALID_TYPES = (Movie, Episode, Show)
def search_for_item(url=None):
if url: return get_item_from_url(opts.url)
server = choose('Choose a Server', account.resources(), 'name').connect()
server = utils.choose('Choose a Server', account.resources(), 'name').connect()
query = input('What are you looking for?: ')
item = choose('Choose result', server.search(query), lambda x: repr(x))
items = [i for i in server.search(query) if i.__class__ in VALID_TYPES]
item = utils.choose('Choose result', items, lambda x: '(%s) %s' % (x.type.title(), x.title[0:60]))
if isinstance(item, Show):
item = choose('Choose episode', item.episodes(), lambda x: x._prettyfilename())
display = lambda i: '%s %s %s' % (i.grandparentTitle, i.seasonEpisode, i.title)
item = utils.choose('Choose episode', item.episodes(), display)
if not isinstance(item, (Movie, Episode)):
raise SystemExit('Unable to download %s' % item.__class__.__name__)
return item
@ -62,6 +57,6 @@ if __name__ == '__main__':
item = search_for_item(opts.url)
# Download the item
print("Downloading '%s' from %s.." % (item._prettyfilename(), item._server.friendlyName))
filepaths = item.download('./')
filepaths = item.download('./', showstatus=True)
for filepath in filepaths:
print(' %s' % filepath)