llygoden 6 Posted January 29, 2017 Posted January 29, 2017 (edited) I wanted to populate my library with a local trailer for each film. I was also interested in learning a bit of Python. So this resulted in the script below, if you want to run it you'll need to install Requests and PyTube (can be done using PIP): import sys import requests import urllib import json import ConfigParser import glob import os from pytube import YouTube config = ConfigParser.RawConfigParser() config.read('trailers.ini') embyapi = "" embykey = "" embyusr = "" h = 0 i = 0 j = 0 k = 0 if config.has_option('emby', 'api'): embyapi = config.get('emby', 'api') else: embyerror = "No Emby URL in Config File.\n" if config.has_option('emby', 'key'): embykey = config.get('emby', 'key') else: embyerror += "No Emby API Key in Config File.\n" if config.has_option('emby', 'usr'): embyusr = config.get('emby', 'usr') else: embyerror += "No Emby User ID in Config File." if config.has_option('emby', 'dirfrom'): embydirf = config.get('emby', 'dirfrom') else: embydirf = "" if config.has_option('emby', 'dirto'): embydirt = config.get('emby', 'dirto') else: embydirt = "" if len(embyapi) == 0 or len(embykey) == 0 or len(embyusr) == 0: print(embyerror) sys.exit() if embyapi[-1] != "/": embyapi += "/" url = embyapi + "Users/%s/Items?IncludeItemTypes=Movie&Recursive=true&StartIndex=0&format=json&fields=RemoteTrailers,Path" % (embyusr) headers = { 'content-type': 'application/json', 'Authorization': 'MediaBrowser', 'UserId': embyusr, 'Client': 'EmbyTrailers', 'Device': 'Python Script', 'DeviceId': 'xxx', 'Version': '1.0.0.0', 'X-MediaBrowser-Token': embykey, } emby = requests.get(url, headers = headers) films = json.loads(emby.content) if not 'Name' in films['Items'][0]: print print("No Films Found") else: for film in films['Items']: if film['LocalTrailerCount'] == 0: h += 1 fulpath = film['Path'].encode("utf-8") if embydirf != "" and embydirt != "": fulpath = fulpath.replace(embydirf, embydirt, 1) fulpath = os.path.normpath(fulpath.replace('\\', os.sep)) basefil = os.path.basename(fulpath) basedir = os.path.dirname(fulpath) trail = os.path.splitext(basefil)[0] if trail[-3:-1] == "CD": trail = trail[:-4] if basedir[-1] != os.sep: basedir += os.sep if len(glob.glob(r"%s%s%s" % (basedir, trail, "-trailer*"))) == 0: download = True i += 1 for trailer in film['RemoteTrailers']: if download: try: yt = YouTube(trailer['Url'].encode("utf-8")) yt.set_filename(trail + "-trailer") video = yt.filter('mp4')[-1] video.download(basedir) except Exception, e: print(trail + " - " + trailer['Url'].encode("utf-8") + " - " + str(e)) if len(glob.glob(r"%s%s%s" % (basedir, trail, "-trailer*"))) > 0: download = False j += 1 if download: k += 1 print("Emby thinks %s Films are Missing Trailers" % (h)) print("%s Films Actually Missing Trailers" % (i)) print("Downloaded %s Trailers" % (j)) print("Unable to Download %s Trailers" % (k)) It reads a trailer.ini file: [emby] api = https://localhost/emby/ key = 00000000000000000000000000000000 usr = 11111111111111111111111111111111 dirfrom = \\Server dirto = /mnt which contains the Emby URL, Emby Username, Emby Api Key and two keys to convert the file paths (Emby reports the file location as \\Server\Movie\Movie.avi, but when I want to run the script on the local machine I want to look at /mnt/Movie/Movie.avi) Two assumptions the script makes is that the trailers are stored as <Movie Name>-trailer.mp4 and that files that have been split over multiple discs will be <Movie Name> CD1.avi, <Movie Name> CD2.avi etc I've run the script locally on my FreeBSD server and remotely from a Windows Machine (In this instance I removed the dirfrom and dirto values) and seems to work on both. Thought this might be useful to others or for someone wanting to work with Emby in Python. Edited January 29, 2017 by llygoden 1
llygoden 6 Posted January 29, 2017 Author Posted January 29, 2017 I also wrote a script to list the films that still don't have trailers after the above script has been run. It uses the same config file for it's information. import sys import requests import urllib import json import ConfigParser import glob import os config = ConfigParser.RawConfigParser() config.read('trailers.ini') embyapi = "" embykey = "" embyusr = "" if config.has_option('emby', 'api'): embyapi = config.get('emby', 'api') else: embyerror = "No Emby URL in Config File.\n" if config.has_option('emby', 'key'): embykey = config.get('emby', 'key') else: embyerror += "No Emby API Key in Config File.\n" if config.has_option('emby', 'usr'): embyusr = config.get('emby', 'usr') else: embyerror += "No Emby User ID in Config File." if config.has_option('emby', 'dirfrom'): embydirf = config.get('emby', 'dirfrom') else: embydirf = "" if config.has_option('emby', 'dirto'): embydirt = config.get('emby', 'dirto') else: embydirt = "" if len(embyapi) == 0 or len(embykey) == 0 or len(embyusr) == 0: print(embyerror) sys.exit() if embyapi[-1] != "/": embyapi += "/" url = embyapi + "Users/%s/Items?IncludeItemTypes=Movie&Recursive=true&StartIndex=0&format=json&fields=RemoteTrailers,Path" % (embyusr) headers = { 'content-type': 'application/json', 'Authorization': 'MediaBrowser', 'UserId': embyusr, 'Client': 'EmbyTrailers', 'Device': 'Python Script', 'DeviceId': 'xxx', 'Version': '1.0.0.0', 'X-MediaBrowser-Token': embykey, } emby = requests.get(url, headers = headers) films = json.loads(emby.content) if not 'Name' in films['Items'][0]: print print("No Films Found") else: i = 0 for film in films['Items']: if film['LocalTrailerCount'] == 0: fulpath = film['Path'].encode("utf-8") if embydirf != "" and embydirt != "": fulpath = fulpath.replace(embydirf, embydirt, 1) fulpath = os.path.normpath(fulpath.replace('\\', os.sep)) basefil = os.path.basename(fulpath) basedir = os.path.dirname(fulpath) trail = os.path.splitext(basefil)[0] if trail[-3:-1] == "CD": trail = trail[:-4] if basedir[-1] != os.sep: basedir += os.sep if len(glob.glob(r"%s%s%s" % (basedir, trail, "-trailer*"))) == 0: i += 1 print('{:>5}'.format(str(i) + '. ') + trail) 1
zigzagtshirt 55 Posted February 22, 2017 Posted February 22, 2017 (edited) Excited to try this out. Looks promising. I am wondering though, if you are pulling trailers off YouTube (presumably the same ones Emby streams for you anyway), what's the rationale for saving them locally and using storage space? Or, as you mentioned, you just wanted to learn some Python and Emby API usage? Can't wait to try it out later Edited February 22, 2017 by zigzagtshirt
JasonG 16 Posted February 25, 2017 Posted February 25, 2017 Having some issues getting these scripts to run - what version of Python are you using? I'm getting strange JSON cannot be decoded messages, so I'm not sure where to start troubleshooting.
llygoden 6 Posted April 27, 2017 Author Posted April 27, 2017 Sorry for the long overdue response @@zigzagtshirt You're correct in that I wanted to learn a bit of Python, but also I have clients with devices that can't play the streamed YouTube trailers as they don't have native apps and so my understanding is that the only way for them to see trailers is with locally held files. @@JasonG I'm using Python 2.7, if you post your error messages I'll attempt to see if I can help.
JasonG 16 Posted May 14, 2017 Posted May 14, 2017 (edited) Sorry for the long overdue response @@zigzagtshirt You're correct in that I wanted to learn a bit of Python, but also I have clients with devices that can't play the streamed YouTube trailers as they don't have native apps and so my understanding is that the only way for them to see trailers is with locally held files. @@JasonG I'm using Python 2.7, if you post your error messages I'll attempt to see if I can help. @llygoden I'm receiving the following: Traceback (most recent call last): File "trailercheck.py", line 58, in <module> films = json.loads(emby.content) File "C:\Python27\lib\json\__init__.py", line 339, in loads return _default_decoder.decode(s) File "C:\Python27\lib\json\decoder.py", line 364, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "C:\Python27\lib\json\decoder.py", line 382, in raw_decode raise ValueError("No JSON object could be decoded") ValueError: No JSON object could be decoded Edited May 14, 2017 by JasonG
JasonG 16 Posted July 13, 2017 Posted July 13, 2017 @llygoden I'm receiving the following: Traceback (most recent call last): File "trailercheck.py", line 58, in <module> films = json.loads(emby.content) File "C:\Python27\lib\json\__init__.py", line 339, in loads return _default_decoder.decode(s) File "C:\Python27\lib\json\decoder.py", line 364, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "C:\Python27\lib\json\decoder.py", line 382, in raw_decode raise ValueError("No JSON object could be decoded") ValueError: No JSON object could be decoded After troubleshooting, I was able to fix the issue. The URL line, for whatever reason, did not like the variable, so hardcoding my user's GUID worked.
kesm 25 Posted February 6, 2018 Posted February 6, 2018 (edited) Hello @@JasonG , Thanks for taking time to make this script! I tried to use it on my nas Synology with python 2.7 installed but all downloads failed.Here is a sample of the errors I got : Memento (2000) Bluray-1080p - https://www.youtube.com/watch?v=FzFQ768J7Bs - 'YouTube' object has no attribute 'set_filename' Passengers (2016) Bluray-1080p - https://www.youtube.com/watch?v=LafZkUT-zkc - 'YouTube' object has no attribute 'set_filename' Does the plugin still work? Maybe Youtube has changed something? Edited February 21, 2018 by kesm 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now