Jump to content

Authenticating to API through python script


jachin99

Recommended Posts

jachin99

I would like to learn a little bit of scripting, and I need local trailers for all of my movies.  I have found a script on this site that seems to help me accomplish both of those goals but I'm not sure if the script still works.  To start things off, the script needs values for these fields:

 

embyapi = ""
embykey = ""
embyusr = ""

 

The API key field is fairly straight forward, and when I created the key, the user filed was blank, which I'm not too concerned about for the time being but what would go into the field for embyapi?  Sorry for my ignorance, and thanks for the help.  

Link to comment
Share on other sites

jachin99

Here is a link to the old script https://emby.media/community/index.php?/topic/44282-python-script-to-get-local-trailers/ Comparing what the script does vs what is listed in your wiki, it looks like you have an entirely new method of authentication, is that right?  It looks like I need to have my script authenticate as if it were any other device accessing the emby API, correct?  So to make sure I'm following everything correctly, my python script is going to

 

1. Authenticate to emby as if it were a device (Or Plugin?) via the values referenced in the wiki 

2. Get a list of all of my movies (Exactly what would it request?  Folder names?  Values in a database?)

3. Search youtube for trailers for each of those, and download them if found

4. Somehow use the emby API or authentication chain to write the new trailers to my network file store

 

I know this is the emby developer forum, and not a school for scripting but if I can figure this out, then I might be able to write a few new things here and there for emby. I greatly appreciate any help I can get. 

Link to comment
Share on other sites

jachin99

Alrite. I reread the script. It uses the authentication method in the wiki but I still don't understand how the original 3 values I asked about fit into all of this and what they do for me that the wiki authentications doesn't. Where do I find values for these?

Link to comment
Share on other sites

jachin99

Ok. I think I might be starting to get a handle on this. I'll try to read ALL of your Dev wiki, tinker around some with my script and come back with some well informed questions hopefully.

Edited by jachin99
Link to comment
Share on other sites

jachin99

I'm getting a JSON error for the script and I want to make sure I'm using the right URL.  I am trying to use

Is there some other address that I need to use to get to the API?  I used this based off the address originally posted with the script.  I had to modify it to include a port number to even see a web page when I put the address directly in a browser.  Thanks.

Link to comment
Share on other sites

Well yes but that is only the base url. There should be more to it after that depending on what you are trying to do.

Link to comment
Share on other sites

PenkethBoy

you need something like this

 

 

...192.168.1.81:8096/emby/users/"UserId"/views?api_key=(User.AccessToken or Api_Key from emby server security page)

 

you can get an idea from the NONE working Swagger pages

Edited by PenkethBoy
Link to comment
Share on other sites

jachin99

Ok, i figured i got that right but I wanted to be sure because I haven't been successful at this just yet.  The script constructs the URL based on variables I have at the top.  I'm still getting a JSON error, and after some basic googling, it doesn't look like something really obvious to me.  I'll keep working at it. 

Link to comment
Share on other sites

AmigaZoid

you need something like this

 

 

...192.168.1.81:8096/emby/users/"UserId"/views?api_key=(User.AccessToken or Api_Key from emby server security page)

 

you can get an idea from the NONE working Swagger pages

 

I've been fighting this issue for weeks and was wondering if you can assist?  I am able to authenticate and get my token, get user/{userid}/views but when I try to go further and add items?parentId={the view id}, I get a Access token is required even though I have the token in the headers.  How do I add api_key=(User.AccessToken or Api_Key from emby server security page) to my parentId request?  Thanks

 

I've read hundreds of post that don't answer the issue and the canned read the docs response to all of them is not helpful. 

Link to comment
Share on other sites

I've been fighting this issue for weeks and was wondering if you can assist?  I am able to authenticate and get my token, get user/{userid}/views but when I try to go further and add items?parentId={the view id}, I get a Access token is required even though I have the token in the headers.  How do I add api_key=(User.AccessToken or Api_Key from emby server security page) to my parentId request?  Thanks

 

I've read hundreds of post that don't answer the issue and the canned read the docs response to all of them is not helpful.

 

Hi, have you gone through the same questions and steps mentioned earlier in this topic? Thanks.

Link to comment
Share on other sites

PenkethBoy

I've been fighting this issue for weeks and was wondering if you can assist?  I am able to authenticate and get my token, get user/{userid}/views but when I try to go further and add items?parentId={the view id}, I get a Access token is required even though I have the token in the headers.  How do I add api_key=(User.AccessToken or Api_Key from emby server security page) to my parentId request?  Thanks

 

I've read hundreds of post that don't answer the issue and the canned read the docs response to all of them is not helpful. 

show me the full request as a text string here

Link to comment
Share on other sites

AmigaZoid

http://172.16.1.2:8096/emby/users/8949e65bd88e4d34b3b277204e303195/Views  works and gives an appropriate response using...

 

 

var request = require("request");
var options = { method: 'GET',
  url: 'http://172.16.1.2:8096/emby/users/8949e65bd88e4d34b3b277204e303195/Views'
  headers:
   { Authorization: 'Bearer a45c03b6fa6f4fb18a2439485c69ff6e',
     'X-Emby-Authorization': 'MediaBrowser Client=\\"Windows\\", Device=\\"Test\\", DeviceId=\\"4\\", Version=\\"1.0.0.0\\"',
     'Content-Type': 'application/json' },
  body:
   { Password: 'hidden',
     PasswordMd5: 'hidden',
     Username: 'hidden',
     Pw: 'hidden' },
  json: true };
request(options, function (error, response, body) {
  if (error) throw new Error(error);
  console.log(body);
});

 

but when I try:

 

/emby/users/8949e65bd88e4d34b3b277204e303195/Items?parentId=f137a2dd21bbc1b99aa5c0f6bf02a805

or

/emby/users/8949e65bd88e4d34b3b277204e303195/Items?parentId=f137a2dd21bbc1b99aa5c0f6bf02a805?api_key=a45c03b6fa6f4fb18a2439485c69ff6e

 

​with the same setup, I end up with the "Access token is required"

 

​Thanks for any info you can give to help get me on the right path, I'm at the verge of moving to plex since I have this working already.

Edited by AmigaZoid
Link to comment
Share on other sites

PenkethBoy

Hi

 

Cant have you going to Plex! :)

 

You are almost there - just a couple of tweaks needed

 

1. .../emby/users/8949e65bd88e4d34b3b277204e303195/Views - will only work if you add a user access token or an api_key

2. ....items?parentid=xxx - i would use /emby/user/<userid>/views?api_key=xxxx - it gives you the same basic data but also quite a bit more on the users Emby Libraries - which is what your query returns

3. If you want to continue to use items?parentid it does work BUT where you have ?api_key it should be &api_key - i.e. you only have one ? in the string and where you have two or more parts you need the second and subsequent parts to be & - try it in your browser and change the second ? to a & :)

 

I dont use python so cant comment on the rest of your code as i use Windows Powershell

 

A couple of Tips to end with.

 

look at swagger - yes it does not work - but it gives you an idea whats available as end points

turn on the debug logging in emby - and look through your log in detail you will find lots of interesting http request strings and how they are structured as you migrate through the interface.

 

Have fun

  • Like 1
Link to comment
Share on other sites

AmigaZoid

Geeze!  Just needed another set of eyes, it was the second "?".  

 

Changed it to & and it works, thanks for the assist.  I don't know why it's not working sending the token in the header but at least it's working.

Link to comment
Share on other sites

jachin99

I'm having a lot of help with this script, and a newer version of it I believe requests the emby URL, and formats the API requests accordingly.  We keep running into problems where the script fails to parse the URL given.  I believe the scripts author is attempting an HTTP connection but would we need an HTTPS connection for authentication?  Would that even matter since the script is asking Emby what the URL is? 

Link to comment
Share on other sites

PenkethBoy

@@jachin99

 

can you show us the url as text so we can see its formatted correctly - i.e. your script is constructing the url without errors/omissions as AmigaZoid did?

Link to comment
Share on other sites

jachin99

Ok so we got past the authentication error after a typo fix but the videos being downloaded have no sound. Any ideas?

Link to comment
Share on other sites

jachin99

@@jachin99

 

 

 

can you show us the url as text so we can see its formatted correctly - i.e. your script is constructing the url without errors/omissions as AmigaZoid did?

I'll show you the whole script after a little bit. I'm just not behind a PC right now

Link to comment
Share on other sites

jachin99

Credit for rebooting, and improving this script goes to Kgschlosser on the EventGhost forums.  I'm using this as a way to start to introduce myself to EG, python, and the Emby API so thats how I ended up there.  Here is the script he created for me, which downloads all of the trailer videos but so far, does not produce a trailer with sound (Still working that part out).  For an implementation without EventGhost some of this script will have to be modified but likely not too much.  At least anything with eg. prefix.  The only non-standard library I imported was pytube version 9.2.2-18.  It might have been updated since then so you will have to check the github page.  If this can successfully download material from youtube, then maybe it could be turned into an extras downloader as well.  After this is successful I would like to start toying around with the emby api. 

# only the API key is needed

emby_api_key = 'Key'
trailer_resolution = '1080p'
# other choices 360p 720p 480p 240p, 144p

import requests
import os
import traceback
import socket
import json
from uuid import uuid4 as GUID
from pytube import YouTube


client_id = str(GUID())

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
sock.settimeout(2.0)
broadcast_address = ('255.255.255.255', 7359)
sock.sendto('who is EmbyServer?', broadcast_address)
sock.settimeout(2.0)

try:
    data = sock.recv(4096)
except socket.timeout:
    eg.PrintError('Could not find an Emby Server')
    eg.StopMacro()
    eg.Exit()

data = json.loads(data.decode('utf-8'))

eg.Print('Found Emby Server')
eg.Print('Name: ' + data['Name'])
eg.Print('Address: ' + data['Address'])
eg.Print('Id: ' + data['Id'])

headers = {
    'Content-Type':         "application/json",
    'Accept':               "application/json",
    'x-emby-authorization': 'MediaBrowser',
    'Client':               'EmbyTrailers',
    'Device':               'Python Script',
    'DeviceId':             client_id,
    'Version':              '1.0.0.0',
}

emby_url = data['Address']
session_url = '{0}/Sessions'.format(emby_url)
params = dict(api_key=emby_api_key)

try:
    session = requests.get(session_url, headers=headers, params=params).json()
except requests.HTTPError:
    traceback.print_exc()
    eg.StopMacro()
    eg.Exit()

params.update(
    dict(
        DeviceId=client_id,
        IncludeItemTypes='Movie',
        Recursive=True,
        StartIndex=0,
        Fields='RemoteTrailers, Path',
        Format='json'
    )
)

items_url = '{emby_url}/Items'.format(emby_url=emby_url)

try:
    response = requests.get(items_url, headers=headers, params=params)
    films = response.json()['Items']
except requests.HTTPError:
    traceback.print_exc()
    eg.StopMacro()
    eg.Exit()
except ValueError:
    print response.status_code
    print response
    eg.StopMacro()
    eg.Exit()
else:
    questionable_trailers = 0
    missing_trailers = 0
    successful_trailer_downloads = 0
    failed_trailer_downloads = 0

    for film in films:
        if not film['LocationType'] == 'FileSystem':
            continue

        if film['LocalTrailerCount'] == 0:
            questionable_trailers += 1

            film_path = film['Path'].encode('utf-8')

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


            def download_trailer(trailer_file_name):
                global missing_trailers
                global successful_trailer_downloads
                global failed_trailer_downloads

                missing_trailers += 1
                for trailer in film['RemoteTrailers']:
                    trailer_url = trailer['Url'].encode('utf-8')

                    try:
                        you_tube = YouTube(trailer_url)
                        streams = you_tube.streams.filter(
                            file_extension='mp4',
                            resolution=trailer_resolution
                        ).all()

                        if streams:
                            stream = streams[0]
                            stream.download(
                                output_path=film_directory_name, 
                                filename=trailer_file_name
                            )
                            successful_trailer_downloads += 1
                            break
                    except:
                        eg.PrintError(
                            '{0} - {1}'.format(film_name, trailer_url)
                        )
                        traceback.print_exc()
                else:
                    failed_trailer_downloads += 1


            film_directory_contents = os.listdir(film_directory_name)

            if (
                'VIDEO_TS' in film_directory_contents or
                'BDMV' in film_directory_contents
            ):
                film_directory_name = os.path.join(
                    film_directory_name,
                    'trailers'
                )
                if not os.path.exists(film_directory_name):
                    os.mkdir(film_directory_name)

                for f in os.listdir(film_directory_name):
                    if f.startswith('trailer'):
                        break
                else:
                    download_trailer('trailer')

            else:
                for f in os.listdir(film_directory_name):
                    if f.startswith(film_name + '-trailer'):
                        break
                else:
                    download_trailer(film_name + '-trailer')

    film_output_template = (
        'Emby Trailer Download Stats\n'
        '    Reported Download Count: {1}\n'
        '    Actual Download Count: {2}\n'
        '    Successful Downloads: {3}\n'
        '    Failed Downloads: {4}\n\n'
    )

    eg.Print(
        film_output_template.format(
            questionable_trailers,
            missing_trailers,
            successful_trailer_downloads,
            failed_trailer_downloads
        )
    )



Link to comment
Share on other sites

jachin99

That looks great but I'm not using Linux and it looks like I'm using g different python libraries. I noticed my .nfo files have links for trailers. What about using those links in the .nfo file as a web address to download trailers from YouTube?

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...