Importing python libraries to run script but which libraries?

Do you have questions about writing plugins or scripts in Python? Meet the coders here.
jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Importing python libraries to run script but which libraries?

Post by jachin99 » Wed Apr 04, 2018 4:11 pm

I have found a script that finds movies from my collection, then scours youtube and downloads trailers for all of them supposedly. I have a basic understanding of how to import a library in EG manually (Drop the library into the lib27 packages folder), and I'm trying to work off of the import statement from the script. I have added some of the correct libraries but I'm having trouble finding others. In particular, I'm not finding the system library from python's site, and when I do find libraries whose names match or sound similar, I don't know how to be sure that I am grabbing the correct library referenced in the script. How can I be sure I grabbed the correct libraries? Here is the script:

Code: Select all

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))

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Importing python libraries to run script but which libraries?

Post by jachin99 » Wed Apr 04, 2018 5:54 pm

Alright, Trying to answer my own question here. If a script is trying to import a module that is not a part of the standard python library, then the statement would have to specify where it is trying to import that module from, correct? For example, if I'm importing a module from a libarary that is not part of the standard python 27 library package, the statment would look something like

from pytube import youtube

If that is true then every other module this script is trying to import should be a part of the standard python library? Tieing this into EventGhost, as long as those standard python modules are compatable with EG then those import statements should be valid, and work in EG BUT what about the youtube library? I have added it to my lib27 packages folder but I'm not sure if that is a valid place to put an entire library without actually installing python on the machine. I'm looking at this as more of a learning experience, and there is a good chance I won't even use this to accomplish what I need it to do but if it works out then thats ok too. I thought I would ask here to verify my thoughts.

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Fri Apr 06, 2018 3:52 pm

you want to put it into the site-packages folder

if the directory for the package is named pytube and what you are trying to access is either inside of the __ini__.py file in the pytube directory. or has been imported in that file then you can do this

Code: Select all

import pytube

pytube.youtube
or you can do this as well

Code: Select all

from pytube import youtube
Now. if you do not want to place it into your site-packages folder. and would rather have it located somewhere else. you need to add the parent directory to the list of directories that python searches.

Code: Select all

import sys

sys.path.append(r'c:\library_parent_directory\library')

and here is a spin on it. If it is an egg. (folder ends with .egg) and there is a .pth file in the parent folder then you either need to add a new site or you need to add the path to sys.path and process the .pth file.

Code: Select all


import site

site.addsite(r'c:\library_parent_directory\library')

to add the path and process the pth file

Code: Select all

import sys
import pkg_resources

sys.path.append(r'c:\library_parent_directory\library')
pkg_resources.require('library')
If you like the work I have been doing then feel free to Image

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Fri Apr 06, 2018 3:58 pm

just as a suggestion

Code: Select all


emby = requests.get(url, headers = headers)
films = json.loads(emby.content)


the requests library has a convince method in the Response class..

Code: Select all

emby = requests.get(url, headers = headers)
films = emby.json()
But you still should always have some error handling any time you are dealing with data conversions. you could get something that is all mucked up

Code: Select all

try:
	emby = requests.get(url, headers = headers)
	films = emby.json()
except (requests.HTTPError, ValueError):
	eg.StopMacro()
	eg.Exit()
in the example above. the requests.HTTPError covers all exceptions generated from requests dealing with the HTTP connection. the ValueError covers the json data conversion in the event it fails. This will stop the current macro and exit the script. you can have it print some kind of information if you wanted informing you of the error.
If you like the work I have been doing then feel free to Image

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Importing python libraries to run script but which libraries?

Post by jachin99 » Tue May 08, 2018 1:00 am

kgschlosser wrote:
Fri Apr 06, 2018 3:58 pm
just as a suggestion

Code: Select all


emby = requests.get(url, headers = headers)
films = json.loads(emby.content)

I'm guessing this puts together the request url, and would replace this bit of code?

Code: Select all

url = embyapi + "Users/%s/Items?IncludeItemTypes=Movie&Recursive=true&StartIndex=0&format=json&fields=RemoteTrailers,Path" % (embyusr)
kgschlosser wrote:
Fri Apr 06, 2018 3:58 pm
the requests library has a convince method in the Response class..

Code: Select all

emby = requests.get(url, headers = headers)
films = emby.json()
But you still should always have some error handling any time you are dealing with data conversions. you could get something that is all mucked up

Code: Select all

try:
	emby = requests.get(url, headers = headers)
	films = emby.json()
except (requests.HTTPError, ValueError):
	eg.StopMacro()
	eg.Exit()
in the example above. the requests.HTTPError covers all exceptions generated from requests dealing with the HTTP connection. the ValueError covers the json data conversion in the event it fails. This will stop the current macro and exit the script. you can have it print some kind of information if you wanted informing you of the error.
Your example above replaced header declarations below, correct?

Code: Select all

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,
Also, this script depends on an ini file for things like the api url, and key. Would I stick this file in a particular place, or should I attempt to hard code the values in the script itself? Sorry for all of the questions. If I can get this right I would like to make an Emby plugin for EG as a sort of learning experience.

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Tue May 08, 2018 7:11 am

this is your whole script with the bits added that i was talking about

Code: Select all

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,
}

try:
    emby = requests.get(url, headers=headers)
    films = emby.json()
except (requests.HTTPError, ValueError):
    eg.StopMacro()
    eg.Exit()


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))
If you like the work I have been doing then feel free to Image

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Tue May 08, 2018 8:07 am

better yet.

Here is a code shortened version of what you had. well it has more lines but that is because of code formatting so it's easier to read.
if i remove the formatting it is down to 96 lines and that is with a bunch of added exception handling.

Code: Select all

import requests
import ConfigParser
import os
import traceback
from pytube import YouTube

emby_error = []
emby_config = [
    'No Emby URL in Config File.',
    'No Emby API Key in Config File.',
    'No Emby User ID in Config File.',
    None,
    None
]

config_keys = [
    'api',
    'key',
    'usr',
    'dirfrom',
    'dirto'
]

config = ConfigParser.RawConfigParser()
config.read('trailers.ini')

for i, key in enumerate(config_keys):
    if config.has_option('emby', key):
        emby_config[i] = config.get('emby', key)
    elif emby_config[i] is not None:
        emby_error += [emby_config[i]]

if emby_error:
    eg.PrintError('\n'.join(emby_error))
    eg.StopMacro()
    eg.Exit()

(
    emby_url,
    emby_api_key,
    emby_user,
    emby_source_directory,
    emby_destination_directory
) = emby_config

if not emby_url.endswith('/'):
    emby_url += '/'

url = (
    '{emby_url}Users/{emby_user}/Items?'
    'IncludeItemTypes=Movie&'
    'Recursive=true&'
    'StartIndex=0&format=json&'
    'fields=RemoteTrailers,Path'
).format(emby_url=emby_url, emby_user=emby_user)

headers = {
    'content-type':         'application/json',
    'Authorization':        'MediaBrowser',
    'UserId':               emby_user,
    'Client':               'EmbyTrailers',
    'Device':               'Python Script',
    'DeviceId':             'xxx',
    'Version':              '1.0.0.0',
    'X-MediaBrowser-Token': emby_api_key,
}

try:
    response = requests.get(url, headers=headers)
    films = response.json()
except (requests.HTTPError, ValueError):
    traceback.print_exc()
    eg.StopMacro()
    eg.Exit()
else:
    if 'Name' not in films['Items'][0]:
        eg.PrintNotice("No Films Found")
        eg.StopMacro()
        eg.Exit()

    questionable_trailers = 0
    missing_trailers = 0
    successful_trailer_downloads = 0
    failed_trailer_downloads = 0
    for film in films['Items']:
        if film['LocalTrailerCount'] == 0:
            questionable_trailers += 1
            
            film_path = film['Path'].encode('utf-8')
            if None not in (emby_source_directory, emby_destination_directory):
                film_path = film_path.replace(
                    emby_source_directory,
                    emby_destination_directory,
                    1
                )
                film_path = os.path.normpath(film_path.replace('\\', os.sep))

            film_base_path = os.path.basename(film_path)
            film_directory_name = os.path.dirname(film_path)
            film_name = os.path.splitext(film_base_path)[0]
            if film_name[-3:-1] == 'CD':
                film_name = film_name[:-4]

            for f in os.listdir(film_directory_name):
                if f.startswith(film_name + '-trailer'):
                    break
            else:
                missing_trailers += 1
                for trailer in film['RemoteTrailers']:
                    trailer_url = trailer['Url'].encode('utf-8')
                    
                    try:
                        you_tube = YouTube(trailer_url)
                        you_tube.set_filename(film_name + '-trailer')
                        video = you_tube.filter('mp4')[-1]
                        video.download(film_directory_name)
                        successful_trailer_downloads += 1
                        break
                    except:
                        eg.PrintError(
                            '{0} - {1}'.format(film_name, trailer_url)
                        )
                        traceback.print_exc()
                else:
                    failed_trailer_downloads += 1

    eg.Print(
        'Emby thinks %d Films are Missing Trailers' % questionable_trailers
    )
    eg.Print('%d Films Actually Missing Trailers' % missing_trailers)
    eg.Print('Downloaded %d Trailers' % successful_trailer_downloads)
    eg.Print('Unable to Download %d Trailers' % failed_trailer_downloads)
If you like the work I have been doing then feel free to Image

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Importing python libraries to run script but which libraries?

Post by jachin99 » Tue May 08, 2018 2:21 pm

What should I do with trailers.ini? Do I put this in the pytube library folder? Thanks for all of the help

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Tue May 08, 2018 3:00 pm

idk I am just rewriting the script you gave me. i didn't change what it was doing or where it was grabbing data from. I simply changed how it was going about doing it.

I would assume that you put the ini file in the cwd (current working directory) which should be %appdata%/EvenGhost
I thought you were using the version of the script you posted earlier. this is a simplified version of that same script. I am assuming that you are running this from inside of EventGhost. I would imagine that you put this into a python script action and run it.
If you like the work I have been doing then feel free to Image

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Tue May 08, 2018 3:07 pm

ok ok i see what is happening here...

LOL

I have never used Emby before. and i was misunderstanding hat you are trying to do.


Do you have an Emby account?
Have you installed the Python Youtube library into EventGhost?
Do you have an ini file written for Emby?
If you like the work I have been doing then feel free to Image

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Importing python libraries to run script but which libraries?

Post by jachin99 » Tue May 08, 2018 3:49 pm

No Worries. I didn't create this script, it was something someone else did as a project, and appears to be abandoned. I have an emby account, and I have a local instance of emby server running on one of my machines. This emby server instance reads all of my media from a file server. i would assume that when I authenticate to the emby api, the script would work off of emby's authentication to my file server. I have already put in the web address, api key, and user information in my .ini file.

For pytube, I downloaded what i assume to be the correct version, and placed the pytube folder in my site-packages eg folder. There is no requirement for my personal use to even have an ini file but if this script runs off of one then I'm not sure where to put it. Thanks again.

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Tue May 08, 2018 6:16 pm

I would poke about the Emby server for some means to output that ini file. The reason why i say this is that sometimes an API key may not be an actual API key. but instead it is an Auth Token. and Auth Tokens expire and need to be updated. That being stated the ini file contents specifically the key names seem like they are from someone that is new to programming. just like the script was as well. So it could be user created. I do not know...


We can forgo the ini file if you like. I don't see a use for it personally. it's simply one more thing to have to pay attention to and remember to backup.


here is the code with the ini file BS removed. directions are at the top.

Code: Select all


# you need to change these variable below to they proper values.
# the last 2 copy andpaste the directory right from file explorer 
# and paste it between the single quotes. 
# you have to leave the "r" in front. 
 emby_url = 'API URL'
 emby_api_key = 'API KEY'
 emby_user = 'SOME USER NAME'
 emby_source_directory = r'SOURCE DIRECTORY'
 emby_destination_directory = r'DESTINATION DIRECTORY'


import requests
import os
import traceback
from pytube import YouTube


url = (
    '{emby_url}/Users/{emby_user}/Items?'
    'IncludeItemTypes=Movie&'
    'Recursive=true&'
    'StartIndex=0&format=json&'
    'fields=RemoteTrailers,Path'
).format(emby_url=emby_url, emby_user=emby_user)

headers = {
    'content-type':         'application/json',
    'Authorization':        'MediaBrowser',
    'UserId':               emby_user,
    'Client':               'EmbyTrailers',
    'Device':               'Python Script',
    'DeviceId':             'xxx',
    'Version':              '1.0.0.0',
    'X-MediaBrowser-Token': emby_api_key,
}

try:
    response = requests.get(url, headers=headers)
    films = response.json()
except (requests.HTTPError, ValueError):
    traceback.print_exc()
    eg.StopMacro()
    eg.Exit()
else:
    if 'Name' not in films['Items'][0]:
        eg.PrintNotice("No Films Found")
        eg.StopMacro()
        eg.Exit()

    questionable_trailers = 0
    missing_trailers = 0
    successful_trailer_downloads = 0
    failed_trailer_downloads = 0
    for film in films['Items']:
        if film['LocalTrailerCount'] == 0:
            questionable_trailers += 1
            
            film_path = film['Path'].encode('utf-8')
            if None not in (emby_source_directory, emby_destination_directory):
                film_path = film_path.replace(
                    emby_source_directory,
                    emby_destination_directory,
                    1
                )
                film_path = os.path.normpath(film_path.replace('\\', os.sep))

            film_base_path = os.path.basename(film_path)
            film_directory_name = os.path.dirname(film_path)
            film_name = os.path.splitext(film_base_path)[0]
            if film_name[-3:-1] == 'CD':
                film_name = film_name[:-4]

            for f in os.listdir(film_directory_name):
                if f.startswith(film_name + '-trailer'):
                    break
            else:
                missing_trailers += 1
                for trailer in film['RemoteTrailers']:
                    trailer_url = trailer['Url'].encode('utf-8')
                    
                    try:
                        you_tube = YouTube(trailer_url)
                        you_tube.set_filename(film_name + '-trailer')
                        video = you_tube.filter('mp4')[-1]
                        video.download(film_directory_name)
                        successful_trailer_downloads += 1
                        break
                    except:
                        eg.PrintError(
                            '{0} - {1}'.format(film_name, trailer_url)
                        )
                        traceback.print_exc()
                else:
                    failed_trailer_downloads += 1

    eg.Print(
        'Emby thinks %d Films are Missing Trailers' % questionable_trailers
    )
    eg.Print('%d Films Actually Missing Trailers' % missing_trailers)
    eg.Print('Downloaded %d Trailers' % successful_trailer_downloads)
    eg.Print('Unable to Download %d Trailers' % failed_trailer_downloads)
    
If you like the work I have been doing then feel free to Image

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Importing python libraries to run script but which libraries?

Post by jachin99 » Tue May 08, 2018 7:06 pm

I'll take a look at that, thanks. The API key is user generated, and I think its a lot like the pushbullet api keys. I don't know a lot about the specifics of how they work to be honest. I know you can share libraries with them.

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Importing python libraries to run script but which libraries?

Post by kgschlosser » Tue May 08, 2018 7:16 pm

ok so the API key will be static and will not change at all. so that can be directly entered into the script. as can the username. the only things would be the url which would be static as well. The directories all depend on what you want. So there is no real need for the ini file.
If you like the work I have been doing then feel free to Image

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Importing python libraries to run script but which libraries?

Post by jachin99 » Tue May 08, 2018 8:26 pm

The author mentioned the director from and dir to values weren't relevant on windows but I'll see I guess. Emby knows where all of my files are and it detects trailers in a specific naming format and directory. If it doesn't work out I'll start chasing errors.

Post Reply