mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-26 05:30:20 +00:00
Merge branch 'master' into better_cli
This commit is contained in:
commit
c9d1e222a6
7 changed files with 49 additions and 11 deletions
|
@ -10,7 +10,7 @@ Python-PlexAPI
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
--------
|
--------
|
||||||
Python bindings for the Plex API. Our goal is to match all capabilities of the official
|
Unofficial Python bindings for the Plex API. Our goal is to match all capabilities of the official
|
||||||
Plex Web Client. A few of the many features we currently support are:
|
Plex Web Client. A few of the many features we currently support are:
|
||||||
|
|
||||||
* Navigate local or remote shared libraries.
|
* Navigate local or remote shared libraries.
|
||||||
|
|
|
@ -550,7 +550,7 @@ class MovieSection(LibrarySection):
|
||||||
Attributes:
|
Attributes:
|
||||||
ALLOWED_FILTERS (list<str>): List of allowed search filters. ('unwatched',
|
ALLOWED_FILTERS (list<str>): List of allowed search filters. ('unwatched',
|
||||||
'duplicate', 'year', 'decade', 'genre', 'contentRating', 'collection',
|
'duplicate', 'year', 'decade', 'genre', 'contentRating', 'collection',
|
||||||
'director', 'actor', 'country', 'studio', 'resolution')
|
'director', 'actor', 'country', 'studio', 'resolution', 'guid')
|
||||||
ALLOWED_SORT (list<str>): List of allowed sorting keys. ('addedAt',
|
ALLOWED_SORT (list<str>): List of allowed sorting keys. ('addedAt',
|
||||||
'originallyAvailableAt', 'lastViewedAt', 'titleSort', 'rating',
|
'originallyAvailableAt', 'lastViewedAt', 'titleSort', 'rating',
|
||||||
'mediaHeight', 'duration')
|
'mediaHeight', 'duration')
|
||||||
|
@ -558,7 +558,8 @@ class MovieSection(LibrarySection):
|
||||||
TYPE (str): 'movie'
|
TYPE (str): 'movie'
|
||||||
"""
|
"""
|
||||||
ALLOWED_FILTERS = ('unwatched', 'duplicate', 'year', 'decade', 'genre', 'contentRating',
|
ALLOWED_FILTERS = ('unwatched', 'duplicate', 'year', 'decade', 'genre', 'contentRating',
|
||||||
'collection', 'director', 'actor', 'country', 'studio', 'resolution')
|
'collection', 'director', 'actor', 'country', 'studio', 'resolution',
|
||||||
|
'guid')
|
||||||
ALLOWED_SORT = ('addedAt', 'originallyAvailableAt', 'lastViewedAt', 'titleSort', 'rating',
|
ALLOWED_SORT = ('addedAt', 'originallyAvailableAt', 'lastViewedAt', 'titleSort', 'rating',
|
||||||
'mediaHeight', 'duration')
|
'mediaHeight', 'duration')
|
||||||
TAG = 'Directory'
|
TAG = 'Directory'
|
||||||
|
@ -570,13 +571,14 @@ class ShowSection(LibrarySection):
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
ALLOWED_FILTERS (list<str>): List of allowed search filters. ('unwatched',
|
ALLOWED_FILTERS (list<str>): List of allowed search filters. ('unwatched',
|
||||||
'year', 'genre', 'contentRating', 'network', 'collection')
|
'year', 'genre', 'contentRating', 'network', 'collection', 'guid')
|
||||||
ALLOWED_SORT (list<str>): List of allowed sorting keys. ('addedAt', 'lastViewedAt',
|
ALLOWED_SORT (list<str>): List of allowed sorting keys. ('addedAt', 'lastViewedAt',
|
||||||
'originallyAvailableAt', 'titleSort', 'rating', 'unwatched')
|
'originallyAvailableAt', 'titleSort', 'rating', 'unwatched')
|
||||||
TAG (str): 'Directory'
|
TAG (str): 'Directory'
|
||||||
TYPE (str): 'show'
|
TYPE (str): 'show'
|
||||||
"""
|
"""
|
||||||
ALLOWED_FILTERS = ('unwatched', 'year', 'genre', 'contentRating', 'network', 'collection')
|
ALLOWED_FILTERS = ('unwatched', 'year', 'genre', 'contentRating', 'network', 'collection',
|
||||||
|
'guid')
|
||||||
ALLOWED_SORT = ('addedAt', 'lastViewedAt', 'originallyAvailableAt', 'titleSort',
|
ALLOWED_SORT = ('addedAt', 'lastViewedAt', 'originallyAvailableAt', 'titleSort',
|
||||||
'rating', 'unwatched')
|
'rating', 'unwatched')
|
||||||
TAG = 'Directory'
|
TAG = 'Directory'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from plexapi import utils
|
from plexapi import log, utils
|
||||||
from plexapi.base import PlexObject
|
from plexapi.base import PlexObject
|
||||||
from plexapi.exceptions import BadRequest
|
from plexapi.exceptions import BadRequest
|
||||||
from plexapi.utils import cast
|
from plexapi.utils import cast
|
||||||
|
@ -52,6 +52,15 @@ class Media(PlexObject):
|
||||||
self.width = cast(int, data.attrib.get('width'))
|
self.width = cast(int, data.attrib.get('width'))
|
||||||
self.parts = self.findItems(data, MediaPart)
|
self.parts = self.findItems(data, MediaPart)
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
part = self._initpath + '/media/%s' % self.id
|
||||||
|
try:
|
||||||
|
return self._server.query(part, method=self._server._session.delete)
|
||||||
|
except BadRequest:
|
||||||
|
log.error("Failed to delete %s. This could be because you havn't allowed "
|
||||||
|
"items to be deleted" % part)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
@utils.registerPlexObject
|
@utils.registerPlexObject
|
||||||
class MediaPart(PlexObject):
|
class MediaPart(PlexObject):
|
||||||
|
|
|
@ -300,7 +300,7 @@ class PlexServer(PlexObject):
|
||||||
""" Install the newest version of Plex Media Server. """
|
""" Install the newest version of Plex Media Server. """
|
||||||
# We can add this but dunno how useful this is since it sometimes
|
# We can add this but dunno how useful this is since it sometimes
|
||||||
# requires user action using a gui.
|
# requires user action using a gui.
|
||||||
part = 'updater/apply'
|
part = '/updater/apply'
|
||||||
release = self.check_for_update(force=True, download=True)
|
release = self.check_for_update(force=True, download=True)
|
||||||
if release and release.version != self.version:
|
if release and release.version != self.version:
|
||||||
# figure out what method this is..
|
# figure out what method this is..
|
||||||
|
|
|
@ -242,7 +242,8 @@ def download(url, filename=None, savepath=None, session=None, chunksize=4024,
|
||||||
chunksize (int): What chunksize read/write at the time.
|
chunksize (int): What chunksize read/write at the time.
|
||||||
mocked (bool): Helper to do evertything except write the file.
|
mocked (bool): Helper to do evertything except write the file.
|
||||||
unpack (bool): Unpack the zip file.
|
unpack (bool): Unpack the zip file.
|
||||||
showstatus (bool): Display progressbar.
|
showstatus(bool): Display a progressbar.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> download(a_episode.getStreamURL(), a_episode.location)
|
>>> download(a_episode.getStreamURL(), a_episode.location)
|
||||||
/path/to/file
|
/path/to/file
|
||||||
|
@ -255,10 +256,12 @@ def download(url, filename=None, savepath=None, session=None, chunksize=4024,
|
||||||
# make sure the savepath directory exists
|
# make sure the savepath directory exists
|
||||||
savepath = savepath or os.getcwd()
|
savepath = savepath or os.getcwd()
|
||||||
compat.makedirs(savepath, exist_ok=True)
|
compat.makedirs(savepath, exist_ok=True)
|
||||||
|
|
||||||
# try getting filename from header if not specified in arguments (used for logs, db)
|
# try getting filename from header if not specified in arguments (used for logs, db)
|
||||||
if not filename and response.headers.get('Content-Disposition'):
|
if not filename and response.headers.get('Content-Disposition'):
|
||||||
filename = re.findall(r'filename=\"(.+)\"', response.headers.get('Content-Disposition'))
|
filename = re.findall(r'filename=\"(.+)\"', response.headers.get('Content-Disposition'))
|
||||||
filename = filename[0] if filename[0] else None
|
filename = filename[0] if filename[0] else None
|
||||||
|
|
||||||
filename = os.path.basename(filename)
|
filename = os.path.basename(filename)
|
||||||
fullpath = os.path.join(savepath, filename)
|
fullpath = os.path.join(savepath, filename)
|
||||||
# append file.ext from content-type if not already there
|
# append file.ext from content-type if not already there
|
||||||
|
@ -267,15 +270,17 @@ def download(url, filename=None, savepath=None, session=None, chunksize=4024,
|
||||||
contenttype = response.headers.get('content-type')
|
contenttype = response.headers.get('content-type')
|
||||||
if contenttype and 'image' in contenttype:
|
if contenttype and 'image' in contenttype:
|
||||||
fullpath += contenttype.split('/')[1]
|
fullpath += contenttype.split('/')[1]
|
||||||
|
|
||||||
# check this is a mocked download (testing)
|
# check this is a mocked download (testing)
|
||||||
if mocked:
|
if mocked:
|
||||||
log.debug('Mocked download %s', fullpath)
|
log.debug('Mocked download %s', fullpath)
|
||||||
return fullpath
|
return fullpath
|
||||||
|
|
||||||
# save the file to disk
|
# save the file to disk
|
||||||
log.info('Downloading: %s', fullpath)
|
log.info('Downloading: %s', fullpath)
|
||||||
if showstatus:
|
if showstatus:
|
||||||
bar = tqdm(desc=filename, unit='B', unit_scale=True,
|
total = int(response.headers.get('content-length', 0))
|
||||||
total=int(response.headers.get('content-length', 0)))
|
bar = tqdm(unit='B', unit_scale=True, total=total, desc=filename)
|
||||||
|
|
||||||
with open(fullpath, 'wb') as handle:
|
with open(fullpath, 'wb') as handle:
|
||||||
for chunk in response.iter_content(chunk_size=chunksize):
|
for chunk in response.iter_content(chunk_size=chunksize):
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Video(PlexPartialObject):
|
||||||
@property
|
@property
|
||||||
def isWatched(self):
|
def isWatched(self):
|
||||||
""" Returns True if this video is watched. """
|
""" Returns True if this video is watched. """
|
||||||
return bool(self.viewCount > 0)
|
return bool(self.viewCount > 0) if self.viewCount else False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def thumbUrl(self):
|
def thumbUrl(self):
|
||||||
|
|
22
tools/plex-alertlistener.py
Executable file
22
tools/plex-alertlistener.py
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Listen to plex alerts and print them to the console.
|
||||||
|
Because we're using print as a function, example only works in Python3.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
from plexapi.server import PlexServer
|
||||||
|
|
||||||
|
|
||||||
|
def _print(msg):
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
plex = PlexServer()
|
||||||
|
listener = plex.startAlertListener(_print)
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
listener.stop()
|
Loading…
Reference in a new issue