If you have not already, we suggest setting your Plex username to something else rather than email which is displayed on your posts in forum. You can change the username at https://app.plex.tv/desktop#!/account
Welcome to our forums! Please take a few moments to read through our Community Guidelines (also conveniently linked in the header at the top of each page). There, you'll find guidelines on conduct, tips on getting the help you may be searching for, and more!

'General' Channel Development Questions From A New Developer

digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

Hi All!

As per @dane22 's suggestion, I'm taking a few questions I had for him in PM and posting them here, as I'm new to Channel development, but fairly versed in other projects.

Without further ado...

So, the plugin in question(s) are here:

https://github.com/d8ahazard/FlexTV.bundle/commit/8d3ed3c00a85a0dc6aeaeb66118e604b9bae59ed

  1. I'd like it to use the PyChromeCast Library, which has it's own set of dependencies, etc. In my latest commit, I have taken and created the directory /Contents/Libraries/Shared under my project, placed in all the files pulled down by doing a pip install as directed in the PCC readme:

https://github.com/balloob/pychromecast

Yet when I try to access the plugin via URL, I see an error in the log about being unable to find pychromecast.

What am I doing wrong?

  1. Is there a specific trick to forcing Plex to reload my code changes, or is it automagic every time I reload the endpoint?

  2. One of the commands I'll need to do is to the /Devices endpoint. I see I can basically return a MediaContainer from the call, which is cool, because I'm already scraping Plex.tv for device listings.

Question being - is there some documentation on the containers I can return? Is it possible for me to return (more or less) the same structure as I'd find at Plex.tv/devices - so I can just add data from that URL to my existing parser for Plex.tv/devices?

  1. Is there a particular/recommended editor for doing Python work? I don't know the syntax well yet, so having a smarter IDE would probably help a lot, and Pycharm seems to really hate Plex plugin format. Ideally, Pycharm would be my tool of choice, but I don't see anything posted anywhere about how to provide the libraries it needs to understand the native Plex calls.
«1

Answers

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja

    First of all, a Plex Channel lives in a Plex sandbox, and as such, do not like stuff starting with __

    Secondly, a zip with the plugin log do help ;)

    When you change your code, PMS should auto-detect, and reload...
    Check logs will help, or if running on anything else than Windows, start PMS from a terminal, and in the start function of the Channel, do like print "Starting"

    And I personally use Visual Studio Code for my work

    /T

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    First of all, a Plex Channel lives in a Plex sandbox, and as such, do not like stuff starting with __

    Secondly, a zip with the plugin log do help ;)

    https://pastebin.com/XMK2fAgi

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    First of all, a Plex Channel lives in a Plex sandbox, and as such, do not like stuff starting with __

    Forgot to ask what you meant by this. Looking at some of your other projects, I see you importing stuff in a similar fashion. I've double-checked the directory structure, don't see anything obviously wrong with the library itself.

    Am I correct in understanding that's what the error in the log is from? Or is the .dll issue on the windows side?

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja

    You are missing a comma here:
    https://github.com/d8ahazard/FlexTV.bundle/blob/tommy-work/Contents/Code/init.py#L85

    However, after adding that, it failed on a missing google plugin, and sadly haven't got time to dig into this, since already have my plate full of challenges :smile:

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    You are missing a comma here:
    https://github.com/d8ahazard/FlexTV.bundle/blob/tommy-work/Contents/Code/init.py#L85

    However, after adding that, it failed on a missing google plugin, and sadly haven't got time to dig into this, since already have my plate full of challenges :smile:

    Fair enough.

    That typo was fixed on my side, but I'm still seeing the same exact error about not finding pychromecast - not a google plugin.

    Is that log message about google in the FlexTV.bundle log, or another file?

    I know you're busy. Not asking you to do it all for me, just help me get my bearings and an understanding of the basics, then I should be able to figure out the rest...

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja

    Log said:

    2018-01-15 22:42:53,596 (7f986e684700) : CRITICAL (core:615) - Exception starting plug-in (most recent call last): File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/core.py", line 608, in start self.sandbox.execute(self.init_code) File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 256, in execute exec(code) in self.environment File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Library/Plex Media Server/Plug-ins/FlexTV.bundle/Contents/Code/__init__.py", line 14, in <module> import google.protobuf File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 345, in __import__ raise e ImportError: No module named google.protobuf

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    Log said:

    2018-01-15 22:42:53,596 (7f986e684700) : CRITICAL (core:615) - Exception starting plug-in (most recent call last): File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/core.py", line 608, in start self.sandbox.execute(self.init_code) File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 256, in execute exec(code) in self.environment File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Library/Plex Media Server/Plug-ins/FlexTV.bundle/Contents/Code/__init__.py", line 14, in <module> import google.protobuf File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 345, in __import__ raise e ImportError: No module named google.protobuf

    So, I've got google\protobuf in the Libraries\Shared directory.

    I see in several files under the pychromecast project they are importing "from google.protobuf". Is the Plex engine able to understand that this notation means to look in shared libraries for the google\protobuf directory? Or do I need to notate it like ..google.protobuf - or in some other fashion?

    Also, inside google\protobuf - is there any need to change the references to protobuf in there?

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    Log said:

    2018-01-15 22:42:53,596 (7f986e684700) : CRITICAL (core:615) - Exception starting plug-in (most recent call last): File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/core.py", line 608, in start self.sandbox.execute(self.init_code) File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 256, in execute exec(code) in self.environment File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Library/Plex Media Server/Plug-ins/FlexTV.bundle/Contents/Code/__init__.py", line 14, in <module> import google.protobuf File "/share/CACHEDEV1_DATA/.qpkg/PlexMediaServer/Resources/Plug-ins-fc63598ba/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 345, in __import__ raise e ImportError: No module named google.protobuf

    Okay, sorted that out. The google directory needs a blank init.py file in order for pyChromeCast/Plex to recognize it as a module.

    NOW, I'm getting:

    2018-01-16 14:50:04,163 (-8e59900) : DEBUG (core:566) - Finished loading plug-in code 2018-01-16 14:50:05,124 (-c54a4c0) : DEBUG (core:538) - Machine identifier is 511722ffd7807f5b8d4187e12ffbb8adb5641bf2 2018-01-16 14:50:05,124 (-c54a4c0) : DEBUG (core:539) - Server version is 1.10.1.4602-f54242b6b 2018-01-16 14:50:07,946 (-beee4c0) : DEBUG (services:362) - Loaded services 2018-01-16 14:50:08,484 (-c25c4c0) : DEBUG (services:438) - No shared code to load 2018-01-16 14:50:08,491 (-8e59900) : CRITICAL (core:615) - Exception starting plug-in (most recent call last): File "/volume1/@appstore/Plex Media Server/Resources/Plug-ins-f54242b6b/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/core.py", line 608, in start self.sandbox.execute(self.init_code) File "/volume1/@appstore/Plex Media Server/Resources/Plug-ins-f54242b6b/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 256, in execute exec(code) in self.environment File "/volume1/Plex/Library/Application Support/Plex Media Server/Plug-ins/FlexTV.bundle/Contents/Code/__init__.py", line 14, in <module> import pychromecast File "/volume1/@appstore/Plex Media Server/Resources/Plug-ins-f54242b6b/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code/sandbox.py", line 345, in __import__ raise e ImportError: No module named netifaces

    Doing my homework, I see that netifaces is special, because it wants to access the NICS. So, am I screwed?

    It looks like all it's doing with netifaces is listing the IP addresses available to the system into an array, then calling that with normalize_interface_choice...

    So, is there a method from the Plex core that I can use to just spoof this since Plex should know it's own IP Address? I think if I can feed that data into zeroconf.py (@L1585), I can move onto the next stumbling block. XD

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja
    edited January 16

    Network.Address

    Returns the server’s IP address. Unless the server is connected directly to the internet, this will usually be a local IP address. Return type str

    Above would most likely needing to be called from the channels init.py file, since seems to recall, that framework calls doesn't work from /shared dir

    And when said, since this is a channel, you could also simply use 127.0.0.1

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    And now I've got it listing devices!!!!!

    Next random question - how can I populate my ObjectContainer with elements based on the cast items??

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    Network.Address

    Returns the server’s IP address. Unless the server is connected directly to the internet, this will usually be a local IP address. Return type str

    Above would most likely needing to be called from the channels init.py file, since seems to recall, that framework calls doesn't work from /shared dir

    And when said, since this is a channel, you could also simply use 127.0.0.1

    Exactly what I wound up doing - I saw that the zeroconf module had an option to return 0.0.0.0 for binding the socket - this works, I'm now scraping and listing Cast devices.

    Only thing I can't figure out (and it's not a deal-breaker) is if there is some kind of DeviceObject container that's undocumented. I'm returning Cast info using a DirectoryContainer and just sticking the needed info into fields, but I feel like this is hacky.

    Is there any way to define a custom container, where I can call the fields what they actually are?

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja

    @digitalhigh said:
    Only thing I can't figure out (and it's not a deal-breaker) is if there is some kind of DeviceObject container that's undocumented. I'm returning Cast info using a DirectoryContainer and just sticking the needed info into fields, but I feel like this is hacky.

    Is there any way to define a custom container, where I can call the fields what they actually are?

    You are draining me here ;)

    Besides that, I have no idea what you mean?

    Context and coding sample please

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass
    edited January 17

    @dane22 said:

    @digitalhigh said:
    Only thing I can't figure out (and it's not a deal-breaker) is if there is some kind of DeviceObject container that's undocumented. I'm returning Cast info using a DirectoryContainer and just sticking the needed info into fields, but I feel like this is hacky.

    Is there any way to define a custom container, where I can call the fields what they actually are?

    You are draining me here ;)

    Besides that, I have no idea what you mean?

    Context and coding sample please

    Haha - we're almost there though!! :dizzy:

    So, my output currently looks like this for the \Devices enpoint:

    <MediaContainer title1="Cast Devices" noHistory="1" title2="Devices found" noCache="1" size="8" identifier="com.plexapp.plugins.FlexTV" sourceTitle="FlexTV" mediaTagPrefix="/system/bundle/media/flags/"> <Directory thumb="192.168.1.217:8009" duration="1" title="Kitchen Home" summary="audio"/> <Directory thumb="192.168.1.217:42581" duration="1" title="Upstairs" summary="group"/> <Directory thumb="192.168.1.150:8009" duration="1" title="Bathroom" summary="audio"/> <Directory thumb="192.168.1.131:8009" duration="1" title="Basement speaker" summary="audio"/> <Directory thumb="192.168.1.104:8009" duration="1" tagline="E8C28D3C" title="Gavin's Room" summary="cast"/> <Directory thumb="192.168.1.129:8009" duration="1" title="Bedroom TV" summary="cast"/> <Directory thumb="192.168.1.197:8009" duration="1" title="SHIELD" summary="cast"/> <Directory thumb="192.168.1.118:8009" duration="1" title="SHIELD" summary="cast"/> </MediaContainer>

    I want to do that, but make it look like the output of plex.tv\api\resources. My scrapers already know how to parse that output. It's minor to write a new method that scrapes what I'm outputting now, but would be nice to have those fields, just for consistency.

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja

    Hah....Finally nailed you here :smile:

    We are now moving into what the Framework actually was designed to do, and never ever touched that!

    Maybe @shopgirl284 has a clue?

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    Hah....Finally nailed you here :smile:

    We are now moving into what the Framework actually was designed to do, and never ever touched that!

    Maybe @shopgirl284 has a clue?

    I was poking around in the framework, and found a declaration for a "ProxyObject" that appeared to take a multidimensional array and convert it to an object, but I couldn't access it as I have things declared now.

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja

    Coding against the framework is indeed up hill....

    And you did check out this?
    https://forums.plex.tv/discussion/comment/970602/#Comment_970602

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22 said:
    Coding against the framework is indeed up hill....

    And you did check out this?
    https://forums.plex.tv/discussion/comment/970602/#Comment_970602

    I did, that's how I figured out the structure for the DirectoryObject I'm returning. Also where I got the idea to grep around in the PMS directory and found the ProxyObject. I think I found an example declaration I can copy to use it, but I've gotta play around with it.

    From "Plex Media Server\Resources\Plug-ins-fc63598ba\Framework.bundle\Contents\Resources\Versions\2\Python\Framework\api\modelkit.py"
    `
    import Framework
    import os

    from base import BaseKit

    def ProxyObjectGenerator(proxy_name):
    def ProxyFunction(data, sort_order=None, ext=None, index=None, **kwargs):
    return Framework.modelling.attributes.ProxyObject(proxy_name, proxy_name.lower(), data, sort_order, ext, index, **kwargs)
    return ProxyFunction

    class ProxyKit(object):
    def init(self):
    self.Preview = ProxyObjectGenerator('Preview')
    self.Media = ProxyObjectGenerator('Media')
    self.LocalFile = ProxyObjectGenerator('LocalFile')
    self.Remote = ProxyObjectGenerator('Remote')

    ...
    `

  • digitalhighdigitalhigh Posts: 375Members, Plex Pass Plex Pass

    @dane22

    Okay, so, after another day of plugging away, a few more questions...if you're feeling magnanimous:

    1. I see there's a function called UpdateCache() that appears to be useable to do a thing at a given interval. Ideally, I'd like to use this to call a re-scan of cast devices every N minutes, and save them with Data.Set().

    I also see that you've set HTTP.CacheTime to 0.

    So, is there a reason for CacheTime to be at zero, where changing it will break something? If not, is there anything else I need to do to get UpdateCache() to work properly? Does it work properly?

    1. Some of my helper modules call log.debug() versus Log.Debug(). Is there a way to pipe this output to Log.Debug(), or does this get written somewhere else?
  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja
    1. No idea, since never used it myself

    And reason why I set HTTP.CacheTime to zerro was/is, that I don't code regular channels, but more into the tools buisness

    1. I suggest you check out github for the Sub-Zero plugin.....
    2. The dev of that tweaked the framework in ways I simply can't yet grasp, and it works perfectly for him

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

  • dane22dane22 Posts: 10,565Members, Plex Pass, Plex Ninja Plex Ninja
    edited January 22

    @digitalhigh said:
    magnanimous:

    Heh....You already proved, that you are a real dev...

    I simply try here, and not a professional dev, just stubborn if I can't get stuff to work

    I hate bugs - Tommy Lee Jones, MIB
    Join me in developing: epg-dk, str2utf-8, remidx, ExportTools, WebTools
    Support the Samsung Client:Donate
    Guides I use: Media Naming Guide, Local subtitles, Log-Files, QNAP FAQ, The Plex Dance

    NO Support via PM, unless called by me

«1
Sign In or Register to comment.