URL Services useless for more complex cases?

plugin-dev

#1

I know, it's a bit provocative title.

What I really mean is that URL Services are always executed using a ServicePolicy that will not allow to execute bundled libraries. But I've found myself in need of using one, to run some Javascript on the page. It's being included from the Shared Code, so it works just fine in the channel code, but not from the URL Service, even though it actually calls the same Shared Code and doesn't try to use the external library directly.

So what now, do I dump my URL Service altogether or anybody knows of any workarounds?


#2

@czukowski said:
So what now, do I dump my URL Service altogether or anybody knows of any workarounds?

Here's what I (and others) do: https://github.com/Twoure/KissNetwork.bundle/blob/1fd6bf884109ad0a7679469237a2fb2cbe04e4a7/Contents/Services/Shared%20Code/domain.pys#L15...L16 and then https://github.com/Twoure/KissNetwork.bundle/blob/1fd6bf884109ad0a7679469237a2fb2cbe04e4a7/Contents/Services/Shared%20Code/domain.pys#L27...L28

Do note, if your ever want to submit your channel to be hosted officially by Plex, then you cannot use this method. Otherwise, you're good to go.


Javascript side note: If using PyExecJS, then you can use node modules. Js2Py does not support the require statement.

Example (using method above for file path):
```py

!/usr/bin/env python

This would be a test file located in:

"KissNetwork.bundle/Contents/Services/Shared Code/test.pys"

import os, sys

BUNDLE_PATH = os.path.join(os.getcwd().lstrip('\\?').split('Plug-in Support')[0], 'Plug-ins', 'KissNetwork.bundle')
MODULE_PATH = os.path.join(BUNDLE_PATH, 'Contents', 'Libraries', 'Shared')
NODE_MODULES_PATH = os.path.join(BUNDLE_PATH, 'Contents', 'Libraries', 'node_modules')

if MODULE_PATH not in sys.path:
sys.path.append(MODULE_PATH)

import execjs #PyExecJS imported from Contents/Libraries/Shared

using Base64 as example

https://www.npmjs.com/package/Base64

code = (
"""
var Base64 = require('%s/Base64/base64.js');
var message = Base64.atob('SGkgQGN6dWtvd3NraQ==');
""" %NODE_MODULES_PATH
)

runtime = execjs.get()
context = runtime.compile(code)
print context.exec_('return message')
```

If your Node.js is setup to allow setting the module paths, then you can use this for the code instead:
py
code = (
"""
module.paths.push('%s');
var Base64 = require('Base64');
var message = Base64.atob('SGkgQGN6dWtvd3NraQ==');
""" %NODE_MODULES_PATH
)


#3

@Twoure, thanks for the info! Looks like I'm already using the 1st method to import Shared Libraries that I have added as git submodules (to save me from figuring out how to "install" them into the channels properly and easier updates in the future), but it just didn't occur to me that I could hack my way like this with the Shared Libraries themselves :)

And I'm using Js2Py by the way. Works very well to get the media URLs in cases when the website devs try to deter RegExers with obfuscated JavaScript.

But generally speaking, what was the reason for using Framework.policies.ServicePolicy for all URL Services? As far as I can tell from the Framework source code, there is a separate sandbox for each Service. Why not run them with the same policy as the channel they belong to? What we have now are the URL Services that are able to use Shared Code, that's been introduced just for this reason (again, if my understanding is correct), to share the logic between Channel and URL Service, but as soon as I add Shared Libraries to my channel, the Shared Code effectively cannot be shared anymore, since it wouldn't work in URL Service.


#4

@Twoure, this seems to work for me as well:

BUNDLE_PATH = Core.bundle_path

Are you aware of any disadvantages of using it?


#5

@czukowski said:
@Twoure, this seems to work for me as well:

BUNDLE_PATH = Core.bundle_path

Are you aware of any disadvantages of using it?

IIRC the Core functions are not available within the ServiceCode, because the service code runs within it's own separate sandbox and doesn't know what Core your referring.

To clarify, content from Contents/Code/ accessing the Contents/Services/Shared Code files will have access to the Core functions, but content from Contents/Services/URL/ accessing the Contents/Services/Shared Code files will not.


#6

@Twoure, hm, I was sure I've put that to a Shared Code that was supposed to be called from a URL service, although that wasn't my channel so I may be missing something, gotta check...