mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-10 06:04:15 +00:00
Add plex-download.py tool; Added new utility to request user/pass from user, config, or env for use when creating cmd line tools
This commit is contained in:
parent
fe68c8f590
commit
63dc1507d2
4 changed files with 155 additions and 50 deletions
|
@ -92,7 +92,7 @@ class PlexObject(object):
|
|||
the first item in the result set is returned.
|
||||
|
||||
Parameters:
|
||||
key (str or int): Path in Plex to fetch items from. If an int is passed
|
||||
ekey (str or int): Path in Plex to fetch items from. If an int is passed
|
||||
in, the key will be translated to /library/metadata/<key>. This allows
|
||||
fetching an item only knowing its key-id.
|
||||
cls (:class:`~plexapi.base.PlexObject`): If you know the class of the
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
import time
|
||||
import zipfile
|
||||
import logging, os, re, requests, time, zipfile
|
||||
from datetime import datetime
|
||||
from getpass import getpass
|
||||
from threading import Thread
|
||||
from plexapi import compat
|
||||
from plexapi.exceptions import NotFound
|
||||
|
@ -284,17 +280,40 @@ def tag_helper(tag, items, locked=True, remove=False):
|
|||
""" Simple tag helper for editing a object. """
|
||||
if not isinstance(items, list):
|
||||
items = [items]
|
||||
|
||||
d = {}
|
||||
data = {}
|
||||
if not remove:
|
||||
for i, item in enumerate(items):
|
||||
tag_name = '%s[%s].tag.tag' % (tag, i)
|
||||
d[tag_name] = item
|
||||
|
||||
tagname = '%s[%s].tag.tag' % (tag, i)
|
||||
data[tagname] = item
|
||||
if remove:
|
||||
tag_name = '%s[].tag.tag-' % tag
|
||||
d[tag_name] = ','.join(items)
|
||||
tagname = '%s[].tag.tag-' % tag
|
||||
data[tagname] = ','.join(items)
|
||||
data['%s.locked' % tag] = 1 if locked else 0
|
||||
return data
|
||||
|
||||
d['%s.locked' % tag] = 1 if locked else 0
|
||||
|
||||
return d
|
||||
def getMyPlexAccount(opts=None):
|
||||
""" Helper function tries to get a MyPlex Account instance by checking
|
||||
the the following locations for a username and password. This is
|
||||
useful to create user-friendly command line tools.
|
||||
1. command-line options (opts).
|
||||
2. environment variables and config.ini
|
||||
3. Prompt on the command line.
|
||||
"""
|
||||
from plexapi import CONFIG
|
||||
from plexapi.myplex import MyPlexAccount
|
||||
# 1. Check command-line options
|
||||
if opts and opts.username and opts.password:
|
||||
print('Authenticating with Plex.tv as %s..' % opts.username)
|
||||
return MyPlexAccount(opts.username, opts.password)
|
||||
# 2. Check Plexconfig (environment variables and config.ini)
|
||||
config_username = CONFIG.get('auth.myplex_username')
|
||||
config_password = CONFIG.get('auth.myplex_password')
|
||||
if config_username and config_password:
|
||||
print('Authenticating with Plex.tv as %s..' % config_username)
|
||||
return MyPlexAccount(config_username, config_password)
|
||||
# 3. Prompt for username and password on the command line
|
||||
username = input('What is your plex.tv username: ')
|
||||
password = getpass('What is your plex.tv password: ')
|
||||
print('Authenticating with Plex.tv as %s..' % username)
|
||||
return MyPlexAccount(username, password)
|
||||
|
|
67
tools/plex-download.py
Executable file
67
tools/plex-download.py
Executable file
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Allows downloading a Plex media item from a local or shared library. You
|
||||
may specify the item by the PlexWeb url (everything after !) or by
|
||||
manually searching the items from the command line wizard.
|
||||
|
||||
Original contribution by lad1337.
|
||||
"""
|
||||
import argparse, re
|
||||
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]
|
||||
|
||||
|
||||
def search_for_item(url=None):
|
||||
if url: return get_item_from_url(opts.url)
|
||||
server = 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))
|
||||
if isinstance(item, Show):
|
||||
item = choose('Choose episode', item.episodes(), lambda x: x._prettyfilename())
|
||||
if not isinstance(item, (Movie, Episode)):
|
||||
raise SystemExit('Unable to download %s' % item.__class__.__name__)
|
||||
return item
|
||||
|
||||
|
||||
def get_item_from_url(url):
|
||||
# Parse the ClientID and Key from the URL
|
||||
clientid = re.findall('[a-f0-9]{40}', url)
|
||||
key = re.findall('key=(.*?)(&.*)?$', url)
|
||||
if not clientid or not key:
|
||||
raise SystemExit('Cannot parse URL: %s' % url)
|
||||
clientid = clientid[0]
|
||||
key = unquote(key[0][0])
|
||||
# Connect to the server and fetch the item
|
||||
servers = [r for r in account.resources() if r.clientIdentifier == clientid]
|
||||
if len(servers) != 1:
|
||||
raise SystemExit('Unknown or ambiguous client id: %s' % clientid)
|
||||
server = servers[0].connect()
|
||||
return server.fetchItem(key)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Command line parser
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--username', help='Your Plex username')
|
||||
parser.add_argument('--password', help='Your Plex password')
|
||||
parser.add_argument('--url', default=None, help='Download from URL (only paste after !)')
|
||||
opts = parser.parse_args()
|
||||
# Search item to download
|
||||
account = utils.getMyPlexAccount(opts)
|
||||
item = search_for_item(opts.url)
|
||||
# Download the item
|
||||
print("Downloading '%s' from %s.." % (item._prettyfilename(), item._server.friendlyName))
|
||||
filepaths = item.download('./')
|
||||
for filepath in filepaths:
|
||||
print(' %s' % filepath)
|
|
@ -8,45 +8,45 @@ and password. Alternatively, if you do not wish to enter your login
|
|||
information below, you can retrieve the same information from plex.tv
|
||||
at the URL: https://plex.tv/api/resources?includeHttps=1
|
||||
"""
|
||||
from getpass import getpass
|
||||
import argparse
|
||||
from plexapi import utils
|
||||
from plexapi.exceptions import BadRequest
|
||||
from plexapi.myplex import MyPlexAccount, _connect
|
||||
from plexapi.myplex import _connect
|
||||
from plexapi.server import PlexServer
|
||||
|
||||
FORMAT = ' %-17s %-25s %-20s %s'
|
||||
FORMAT2 = ' %-17s %-25s %-20s %-30s (%s)'
|
||||
SERVER = 'Plex Media Server'
|
||||
FORMAT = '%-8s %-6s %-17s %-25s %-20s %s (%s)'
|
||||
|
||||
|
||||
def _list_resources(account, servers):
|
||||
print('\nHTTPS Resources:')
|
||||
resources = MyPlexAccount(username, password).resources()
|
||||
for r in resources:
|
||||
if r.accessToken:
|
||||
items = []
|
||||
print('Finding Plex resources..')
|
||||
resources = account.resources()
|
||||
for r in [r for r in resources if r.accessToken]:
|
||||
for connection in r.connections:
|
||||
print(FORMAT % (r.product, r.name, r.accessToken, connection.uri))
|
||||
servers[connection.uri] = r.accessToken
|
||||
print('\nDirect Resources:')
|
||||
for r in resources:
|
||||
if r.accessToken:
|
||||
for connection in r.connections:
|
||||
print(FORMAT % (r.product, r.name, r.accessToken, connection.httpuri))
|
||||
local = 'Local' if connection.local else 'Remote'
|
||||
extras = [r.provides]
|
||||
items.append(FORMAT % ('Resource', local, r.product, r.name, r.accessToken, connection.uri, ','.join(extras)))
|
||||
items.append(FORMAT % ('Resource', local, r.product, r.name, r.accessToken, connection.httpuri, ','.join(extras)))
|
||||
servers[connection.httpuri] = r.accessToken
|
||||
servers[connection.uri] = r.accessToken
|
||||
return items
|
||||
|
||||
|
||||
def _list_devices(account, servers):
|
||||
print('\nDevices:')
|
||||
for d in MyPlexAccount(username, password).devices():
|
||||
if d.token:
|
||||
for conn in d.connections:
|
||||
print(FORMAT % (d.product, d.name, d.token, conn))
|
||||
servers[conn] = d.token
|
||||
items = []
|
||||
print('Finding Plex devices..')
|
||||
for d in [d for d in account.devices() if d.token]:
|
||||
for connection in d.connections:
|
||||
extras = [d.provides]
|
||||
items.append(FORMAT % ('Device', '--', d.product, d.name, d.token, connection, ','.join(extras)))
|
||||
servers[connection] = d.token
|
||||
return items
|
||||
|
||||
|
||||
def _test_servers(servers):
|
||||
seen = set()
|
||||
print('\nServer Clients:')
|
||||
items, seen = [], set()
|
||||
print('Finding Plex clients..')
|
||||
listargs = [[PlexServer, s, t, 5] for s,t in servers.items()]
|
||||
results = utils.threaded(_connect, listargs)
|
||||
for url, token, plex, runtime in results:
|
||||
|
@ -54,19 +54,38 @@ def _test_servers(servers):
|
|||
if plex and clients:
|
||||
for c in plex.clients():
|
||||
if c._baseurl not in seen:
|
||||
print(FORMAT2 % (c.product, c.title, token, c._baseurl, plex.friendlyName))
|
||||
extras = [plex.friendlyName] + c.protocolCapabilities
|
||||
items.append(FORMAT % ('Client', '--', c.product, c.title, token, c._baseurl, ','.join(extras)))
|
||||
seen.add(c._baseurl)
|
||||
return items
|
||||
|
||||
|
||||
def _print_items(items, _filter=None):
|
||||
if _filter:
|
||||
print('Displaying items matching filter: %s' % _filter)
|
||||
print()
|
||||
for item in items:
|
||||
filtered_out = False
|
||||
for f in _filter.split():
|
||||
if f.lower() not in item.lower():
|
||||
filtered_out = True
|
||||
if not filtered_out:
|
||||
print(item)
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
username = input('What is your plex.tv username: ')
|
||||
password = getpass('What is your plex.tv password: ')
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--username', help='Your Plex username')
|
||||
parser.add_argument('--password', help='Your Plex password')
|
||||
parser.add_argument('--filter', default='', help='Only display items containing specified filter')
|
||||
opts = parser.parse_args()
|
||||
try:
|
||||
servers = {}
|
||||
account = MyPlexAccount(username, password)
|
||||
_list_resources(account, servers)
|
||||
_list_devices(account, servers)
|
||||
_test_servers(servers)
|
||||
account = utils.getMyPlexAccount(opts)
|
||||
items = _list_resources(account, servers)
|
||||
items += _list_devices(account, servers)
|
||||
items += _test_servers(servers)
|
||||
_print_items(items, opts.filter)
|
||||
except BadRequest as err:
|
||||
print('Unable to login to plex.tv: %s' % err)
|
||||
|
|
Loading…
Reference in a new issue