How to load a resource with + symbol in its name?



Title says it all, if I try to execute a command Resource.ExternalPath('icon+test.png') (or R('icon+test.png') for short) this is what I get in my logs and image does not show:

2017-05-19 09:42:39,980 (120) : DEBUG (runtime:717) - Handling request GET /:/plugins/com.plexapp.plugins.test/resources/icon+test.png?t=1495175883
2017-05-19 09:42:39,984 (120) : DEBUG (runtime:814) - Found route matching /:/plugins/com.plexapp.plugins.test/resources/icon test.png
2017-05-19 09:42:39,997 (120) : DEBUG (runtime:88) - Sending packed state data (105 bytes)
2017-05-19 09:42:39,997 (120) : DEBUG (runtime:924) - Response: [404] NoneType, 0 bytes

Any suggestions?

I can't change the name of the image I am using.


@Cigaras try using %2B instead of a plus sign and see if it helps.


R('icon%2Btest.png') returns None without any additional log messages neither in plug-in or in server logs.


Would String.Quote(value, usePlus = False) work?


@shopgirl284 no, it does not work either. Whether usePlus is set to True or False it returns same icon%2Btest.png, and R(String.Quote('icon+test.png', usePlus = False)) gives me same as R('icon%2Btest.png'), nothing :(


is it possible for you to use Core.bundle_path? Then you are not limited by the sandbox-restrictions of the resourcekit and the suggestions @shopgirl284 and @czukowski should work.
PlexPluginCodePolicy in Info.plist must be set (Elevated).

Plugins: ARDMediathek2016, Plex-Plugin-KIKA_und_tivi, Plex-Plugin-3Sat_Mediathek, Plex-Plugin-Flickr, Plex-Plugin-TagesschauXL, Plex-Plugin-Phoenix_Mediathek


pardon - unexpectedly ist doesn't work.
I tried this code (with and without Quoting):
icon='ico+n.png' # Icon-Test

icon=String.Quote('ico+n.png', usePlus = False)

icon_path = 'Contents/Resources/%s' % icon
full_icon_path = os.path.join(Core.bundle_path, icon_path)
oc.add(DirectoryObject(key=Callback(dummy,thumb=full_icon_path), title='Icon-Test',
    summary='', tagline='TV', thumb=full_icon_path))
The Server logs the right path: ``` url => Support/Plex Media Server/Plug-ins/StreamTest.bundle/Contents/Resources/ico+n.png' ```
but logs then an 404-Error:  ``` Completed: [] 404 GET /photo/:/transcode?url=http%3A%2F%2F127.0.0.1%3A32400%2Fvar%2Flib%2Fplexmediaserver%2FLibrary%2FApplication%20Support%2FPlex%20Media%20Server%2FPlug-ins%2FStreamTest.bundle%2FContents%2FResources%2Fico%2Bn.png&width=150&height=150&minSize=1 (8 live) GZIP 1ms 379 bytes (pipelined: 9)```

I will try to find out the reason ...

######Plugins: [ARDMediathek2016](, [Plex-Plugin-KIKA_und_tivi](, [Plex-Plugin-3Sat_Mediathek](, [Plex-Plugin-Flickr](, [Plex-Plugin-TagesschauXL](, [Plex-Plugin-Phoenix_Mediathek](


Is using a full path in URL like that some kind of feature I haven't known about before? If it is, that seems pretty unsafe to me because anything on your computer may be accessible. Although 404 error indicates that it's not working that way.

Anyway, from the OP, it seems like Plex framework code is converting plus sign to space, but I've read somewhere that plus is reserved for space only in URL query part, which filename quite isn't. Therefore it appears like there's a bug with URL decoding in Plex framework. It could still be decoding %2B correctly, but Resource.ExternalPath won't return it.

Have you tried something like R('icon+test.png').replace('+', '%2B')? If Plex does indeed urldecode correctly (other than the plus sign), it might be just what's needed to generate the working URL.


yes, I have seen an example for 'URL query part' here:

My idea to use Core-functions comes from the updater-modules , because many of them uses to put the zip-data into Plugin-directory. My next idea: if this would works, we could store the loaded icon-data with an acceptable filename und use it in the normal way with R(icon).
But my last tests shows, that I'm not able (until yet) to load the binary data of a icon in the Resource-directory. fails and HTTP.Request("%s/:/plugins/%s/%s" % (myhost, myplugin, icon_path), immediate=True).content also fails.

I have not given up yet... :)

Plugins: ARDMediathek2016, Plex-Plugin-KIKA_und_tivi, Plex-Plugin-3Sat_Mediathek, Plex-Plugin-Flickr, Plex-Plugin-TagesschauXL, Plex-Plugin-Phoenix_Mediathek


it's more easier than i thought: :)
I only copy the icon to an icon with a 'normal' name (import shutil is needed for this solution). This happens inside Resources-directory of Plugin:

    icon_bad ='ico+n.png' 

    icon_bad_path = 'Contents/Resources/%s' % icon_bad
    icon_good_path = 'Contents/Resources/%s' % icon_good
    full_icon_bad_path = os.path.join(Core.bundle_path, icon_bad_path)
    full_icon_good_path = os.path.join(Core.bundle_path, icon_good_path)

    shutil.copy(full_icon_bad_path, full_icon_good_path)

    oc.add(DirectoryObject(key=Callback(dummy), title='Icon-Test',
        summary='', tagline='TV', thumb=R(icon_good)))

Yes, I agree czukowski : not an example for security - but similiar safe / unsafe like a Plugin-Update.

Edit: R('icon+test.png').replace('+', '%2B') at my place caused AttributeError: 'NoneType' object has no attribute 'replace'


Plugins: ARDMediathek2016, Plex-Plugin-KIKA_und_tivi, Plex-Plugin-3Sat_Mediathek, Plex-Plugin-Flickr, Plex-Plugin-TagesschauXL, Plex-Plugin-Phoenix_Mediathek