plexbrowse.py
· 1.9 KiB · Python
Raw
#!/usr/bin/env python3
# python3 plexbrowse.py | while read p; do mpv "$p"; done
# use --host to set the hostname of the server to access
# set PLEX_TOKEN in your environment with your X-Plex-Token
import requests
from os import environ
from os.path import basename
import xml.etree.ElementTree as ET
from sys import stderr
token = environ["PLEX_TOKEN"]
def get(*args, **kwargs):
if "params" not in kwargs:
kwargs["params"] = {}
kwargs["params"]["X-Plex-Token"] = token
return requests.get(*args, **kwargs)
def parse(xml):
return ET.fromstring(xml)
def get_plex(host, path):
return parse(get(f"https://{host}{path}").content)
def pick_item(items, title=lambda i: i.attrib["title"]):
print("\n".join("{} {}".format(n, title(i)) for n, i in enumerate(items)), file=stderr)
print("> ", end="", file=stderr)
selected = int(input())
if len(items) < selected:
return False
return items[selected]
def main():
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("--host", default="plex.wa.alyssasmith.id.au")
args = parser.parse_args()
section = pick_item(get_plex(args.host, "/library/sections").findall("Directory"))
item = pick_item(get_plex(args.host, f"/library/sections/{section.attrib['key']}/all").findall("Directory"))
videos = get_plex(args.host, item.attrib["key"].replace("children", "allLeaves")).findall("Video")
medias = []
for v in videos:
medias += v.findall("Media")
parts = {}
for m in medias:
for p in m.findall("Part"):
parts[basename(p.attrib["file"])] = p.attrib["key"]
filenames = list(parts.keys())
selected = parts[pick_item(filenames, title=lambda i: i)]
print(f"https://{args.host}{selected}?X-Plex-Token={token}")
return 0
if __name__ == "__main__":
from sys import exit
try:
exit(main())
except KeyboardInterrupt:
exit(255)
| 1 | #!/usr/bin/env python3 |
| 2 | # python3 plexbrowse.py | while read p; do mpv "$p"; done |
| 3 | # use --host to set the hostname of the server to access |
| 4 | # set PLEX_TOKEN in your environment with your X-Plex-Token |
| 5 | import requests |
| 6 | from os import environ |
| 7 | from os.path import basename |
| 8 | import xml.etree.ElementTree as ET |
| 9 | from sys import stderr |
| 10 | |
| 11 | token = environ["PLEX_TOKEN"] |
| 12 | |
| 13 | def get(*args, **kwargs): |
| 14 | if "params" not in kwargs: |
| 15 | kwargs["params"] = {} |
| 16 | kwargs["params"]["X-Plex-Token"] = token |
| 17 | return requests.get(*args, **kwargs) |
| 18 | |
| 19 | def parse(xml): |
| 20 | return ET.fromstring(xml) |
| 21 | |
| 22 | def get_plex(host, path): |
| 23 | return parse(get(f"https://{host}{path}").content) |
| 24 | |
| 25 | def pick_item(items, title=lambda i: i.attrib["title"]): |
| 26 | print("\n".join("{} {}".format(n, title(i)) for n, i in enumerate(items)), file=stderr) |
| 27 | print("> ", end="", file=stderr) |
| 28 | selected = int(input()) |
| 29 | if len(items) < selected: |
| 30 | return False |
| 31 | return items[selected] |
| 32 | |
| 33 | def main(): |
| 34 | from argparse import ArgumentParser |
| 35 | parser = ArgumentParser() |
| 36 | parser.add_argument("--host", default="plex.wa.alyssasmith.id.au") |
| 37 | args = parser.parse_args() |
| 38 | section = pick_item(get_plex(args.host, "/library/sections").findall("Directory")) |
| 39 | item = pick_item(get_plex(args.host, f"/library/sections/{section.attrib['key']}/all").findall("Directory")) |
| 40 | videos = get_plex(args.host, item.attrib["key"].replace("children", "allLeaves")).findall("Video") |
| 41 | medias = [] |
| 42 | for v in videos: |
| 43 | medias += v.findall("Media") |
| 44 | parts = {} |
| 45 | for m in medias: |
| 46 | for p in m.findall("Part"): |
| 47 | parts[basename(p.attrib["file"])] = p.attrib["key"] |
| 48 | filenames = list(parts.keys()) |
| 49 | selected = parts[pick_item(filenames, title=lambda i: i)] |
| 50 | print(f"https://{args.host}{selected}?X-Plex-Token={token}") |
| 51 | return 0 |
| 52 | |
| 53 | if __name__ == "__main__": |
| 54 | from sys import exit |
| 55 | try: |
| 56 | exit(main()) |
| 57 | except KeyboardInterrupt: |
| 58 | exit(255) |