pkkid / python-plexapi

Python bindings for the Plex API.
BSD 3-Clause "New" or "Revised" License
1.13k stars 197 forks source link

RFE: Add API to override Platform #706

Open glensc opened 3 years ago

glensc commented 3 years ago

Describe the issue

There's currently no programmatic way to override Platform and Client name.

Hacks like overwriting X_PLEX_PLATFORM / X_PLEX_DEVICE_NAME do not work without more internal symbols hacking, because those values are copied elsewhere:

Setting environment variables also does not work, as that needs to be done before the import plexapi is called.

Code snippets

from os import getenv, environ
import plexapi

        plex_config = {
            'PLEXAPI_HEADER_PLATFORM': 'PlexTraktSync',
            'PLEXAPI_HEADER_DEVICE_NAME': 'PlexTraktSync',
        }
        plexapi.X_PLEX_DEVICE_NAME = 'PlexTraktSync'
        for k, v in plex_config.items():
            environ[k] = v

Expected behavior

    plex = PlexServer(url, token, device_platform='PlexTraktSync')

Additional context

Trying to make changes identifiable to be able to skip own changes. I.e skip changes identified by named device:

Hellowlol commented 3 years ago

I don’t understand the problem. Your describing different ways to set this that does work. You have to do it in the correct order.

I also fail to see how the issue you linked to is relevant.

You need to fix this in your script.

glensc commented 3 years ago

@Hellowlol those examples are all various hacks. Therefore I request a programmatic way to set the deviceId in the plex instance, not the global static module internal variable. Hence creating this issue for enchancement. Having some trickery done before importing a module trashes up project coding style. Python coding style is that you put import's in the beginning of the file, and then in main() you execute the code.

Besides messing up style, it's very fragile, if in case somebody else loads the module before the header overwrites the code, your initialization will fail.

Hellowlol commented 3 years ago

I can’t speak for others but I’m not gonna do this at all.

There are 3 ways to do this. Patching, environmental variables and using a config file.

Your assuming that PlexServer is the main entry point. That might be true for simple scripts, but what about all the others? Should we add device_platform to all other classes that ppl might, such as the cloud classes? I assume you see my point, as this will be very had to maintain.

With that being said, if you can come up with a simpler method then we are currently using that is easy to maintain I’ll happily merge that. 😄

glensc commented 3 years ago

The problem with patching and environment variables is that these need to be done before 'import' statement. The problem with config, is that it's global and applies to all applications, not my application, so that's out of the way for setting application-specific properties.

The main problem seems to be around BASE_HEADERS being initialized at import plex. if that could be delayed, that would solve the problem (for me).

Perhaps move that BASE_HEADERS to new Config.getBaseHeaders() method (or getDefaultHeaders()), and instead of importing BASE_HEADERS in {client,myplex,server}.py, it is called from their respective constructor.

then applications like mine, can do CONFIG.set('header.platform', 'PlexTraktSync') before creating plex server instance.

Ideally, (i.e in the next iteration), the config could be passed to those {client,myplex,server} constructors.

glensc commented 3 years ago

And yes, PlexServer was an example, and was setting only device_platform an example. the solution should apply to all properties. Unless you want Device and Client identification to become first citizen, in that case, I don't know that should be approached.

glensc commented 3 years ago

Started something:

need some kind of guidance on:

  1. how much compatibility is needed to keep
  2. how to name things
glensc commented 3 years ago

I found this when attempting to refactor:

seems it's somewhat[*] documented how to override a device, just need to do both assignments.

plexapi.X_PLEX_PLATFORM = 'iOS' 
plexapi.BASE_HEADERS['X-Plex-Platform'] = plexapi.X_PLEX_PLATFORM 

[*] somewhat in sense, meaning it's not in docs, but source code, i.e not official.

JonnyWong16 commented 3 years ago

https://python-plexapi.readthedocs.io/en/latest/modules/sync.html#module-plexapi.sync