Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Image VFS support for JSON-RPC #958

Merged
merged 14 commits into from

2 participants

@jmarshallnz
Owner

This adds support for trivial image:// wrapped URLs suitable for JSON-RPC use.

In CFile::Open() we check whether the texturecache has the image, and cache if not. Then we fall through to the cached version of the image.

This allows us to set image:// URLs in JSON-RPC, so that images are cached only if they're actually fetched by the client, not just if they request items that may have art that is not cached. Currently clients retrieve art via the VFS, so setting an image:// URL allows backward compatibility until such a time as JSON-RPC supports a direct image retrieval handler, whereby that handler can just use the VFS internally.

A couple of things to discuss:

  1. Currently for JSON-RPC we set only art that has been previously discovered (i.e. is in the database). Eden users updating to nightlies will therefore need to view the images in XBMC before they'll be available over JSON-RPC. We could change this by running the backward compatibility code via the thumbloader, however this is very slow for large numbers of items being retrieved.

  2. I've currently not fully implemented CFile::Stat() - in particular Stat() will fail if the image has not yet been cached. IMO this isn't an issue as it's unlikely that we'll be calling this. I could fall through to Stat() on the original image, but this ofcourse will give inaccurate information (size for example).

I consider this a fix rather than a feature (currently no art is available for video items via JSON-RPC).

@jmarshallnz
Owner

Slight issue with this in that microhttpd urldecodes the URLs sent to GET, thus our image:// get decoded and thus things fail.

Need to find a way to get the URl out of microhttpd without it decoding it first, or have a hacky workaround to urlencode it again in the vfs handler.

@Montellese
Owner

Looking good.

Not sure how to handle the first issue either. If we run the thumbloader when retrieving items through JSON-RPC it will slow things down a lot but it should only really slow things down on first retrieval right? I assume this problem only exists for people who upgrade with existing libraries?

Concerning the second issue we don't use Stat() in the webserver or any of its handlers so shouldn't be a problem.

I'll write an image handler for the webserver which will translate received URLs into an image://-based URL and dispatch them to this new image:// VFS handler. This way we can some day drop the webserver's VFS handler and by that close a huge security whole.

@jmarshallnz
Owner

I'll try factoring out the back-compat code from the thumbloader so that it only runs that bit of it (as we have video db items only, it'll only do it once) and see how slow it is.

If we want backcompat for old web clients, we'll need the urldecode issue fixed (or worked around).

@Montellese
Owner

I just looked at the code of the webinterface and it actually never url-encodes the VFS URLs it passes to http://localhost/vfs/ so that's why it doesn't work for now. By adding a simple encodeURI() around the paths retrieved from "fanart" and "thumbnail" it works perfectly fine, i.e. if JSON-RPC returns image://http%3a%2f%2fcf2%2eimgobject%2ecom%2ft%2fp%2foriginal%2ftkvBU9bwUIHv4MOc3BZuTfzKt8t%2ejpg in a "thumbnail" property, the webinterface will take that URL, URL-encode it (again) and will call http://localhost/vfs/image%3A%2F%2Fhttp%253a%252f%252fcf2%252eimgobject%252ecom%252ft%252fp%252foriginal%252ftkvBU9bwUIHv4MOc3BZuTfzKt8t%252ejpg

IMO that would be the correct behaviour because calling http://localhost/vfs/image://... is not right. It sounds and looks a bit odd to url-encode something that is already partly url-encoded but that's how it should be IMO.

When looking at how to implement the webservers image handler (which forwards to the VFS's CImageFile) I ran into the following problem which I would like to discuss:
JSON-RPC returns URLs of the form "image://" but a call to the image handler would already look like http://localhost/image/ so having the "image://" in there would be kind of duplicate (.../image/image://...). But not expecting "image://" would mean that clients would have to remove the "image://" part from the retrieved URLs which is not really user-friendly either. Any ideas?

@Montellese
Owner

I also noticed something else. When retrieving artwork for music (which is not yet integrated into the texture cache etc) the URLs for fanarts look like "special://....tbn" whereas the URLs for thumbnails look like "image://special%3a%2f%2f...tbn". So either one of those is wrong and if we don't want to break backwards-compatibility (until music artwork is integrated into the texture cache) the thumbnail's one looks wrong to me.

@jmarshallnz
Owner

Ah - that makes sense. Yes, agreed that to use the VFS it makes sense for the client to URL encode - I guess they got away with it till now as the URLs weren't already partially URL eoncdoed.

As for the image handler, I think it makes sense if we have an ID so that http://localhost/image/ is quite natural. Our ID at the moment is image:// stuff, so I think it still makes sense - basically whatever is set in the art fields should be what is passed as the ID. It looks odd at the moment, sure, but once things are in their ID form it will be more straight-forward. Essentially this is an interim step to moving to IDs (as the ID thing wouldn't work for VFS back-compat).

Will check the music - we just wrap directly though there's no real need to for that - a simple fix I think.

@jmarshallnz
Owner

I guess we should check what other clients are doing. I presume that if the default web interface is doing things "incorrectly" that the others probably are as well, which would break backwards compatibility anyway...

@freezy what are you doing for the android remote to receive image URLs from thumbs - are you URL encoding prior to appending to http://ip/vfs/ ?

@Montellese
Owner

For me this is the same as the invalid Content-Type header for JSON-RPC request. Sending a JSON-RPC request with a HTTP Content-Type set to "multipart/formdata" is simply wrong and you have to live with the consequences if the server changes the behaviour to follow the specification more strictly.

I have a fix for the webinterface's missing encodeURI calls and I have the webserver's image handler ready to be able to handle image://- and special://-based URLs. The latter currently doesn't work because the thumbnails are returned with image://special%3a%2f%2f (as mentioned above). Should I wait for your fix or send the pull request "blindly"?

@Montellese
Owner

Stupid brain of mine waits till I'm in bed to remind me that I forgot to adjust the Files.PrepareDownload implementation to point to the new image handler. Will do after some sleep and breakfast ;-)

@jmarshallnz
Owner

Merged Montellese' image:// handler. Now works fine in Global Search addon and over the web interface, and the back-compat is working fine.

One last thing to think about is whether or not we want to move to an ID based system, and if so, how to best do it. We need a URL, or at least a way for scripts that will be displaying art in the UI to transform anything set in the thumbnail or fanart properties to URLs. So question is whether we set the actual URL or the image:// URL or an ID derived from there. eg I could utilise the id key in the textures database for that, though some refactor would be needed to ensure that it would work - basically we'd need to add textures to the db before they're cached, and then have update routines rather than delete/add, which is slightly messier code-wise. Alternatively we could have an in-memory map to do the same thing if we don't care about volatility.

Jonathan Mar... and others added some commits
@Montellese
Owner

Good to go from my side.

@jmarshallnz
Owner

@cptspiff you OK with this one going in? It's quite large for a fix, but better do it properly then hack something in.

@ghost

haven't reviewed by in pricinple it's a refinement/fix so yes.

@jmarshallnz
Owner

Righto

@jmarshallnz jmarshallnz was assigned
@jmarshallnz jmarshallnz merged commit 1e16f6f into xbmc:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 13, 2012
  1. default the type param of GetWrappedImageURL to empty to save specify…

    Jonathan Marshall authored
    …ing it all the time
  2. adds UnwrapImageURL() to unwrap trivially wrapped image://<get_encode…

    Jonathan Marshall authored
    …d_path>/ urls
  3. ensure GetWrappedImageURL() doesn't wrap already wrapped URLs

    Jonathan Marshall authored
  4. make sure all calls into the TextureCache check and unwrap trivially …

    Jonathan Marshall authored
    …wrapped images
  5. adds image:// file protocol as a wrapper for texture cache, to be use…

    Jonathan Marshall authored
    …d for JSON-RPC images
  6. factor out CVideoThumbLoader::FillLibraryArt

    Jonathan Marshall authored
  7. move thumbnail handling in the JSON-RPC FileItemHandler into where fa…

    Jonathan Marshall authored
    …nart handling is done
  8. use wrapped image URLs for the http-api video+picture art

    Jonathan Marshall authored
  9. cleanup: remove unused texturecache functions

    Jonathan Marshall authored
  10. @Montellese

    webserver: add handler for image://

    Montellese authored Jonathan Marshall committed
  11. @Montellese

    jsonrpc: adjust Files.PrepareDownload for HTTP to use the new image h…

    Montellese authored Jonathan Marshall committed
    …andler
  12. @Montellese

    [webinterface.default] make sure to URL-encode any image-paths return…

    Montellese authored Jonathan Marshall committed
    …ed by JSON-RPC when calling http://<ip>:<port>/vfs/
This page is out of date. Refresh to see the latest.
Showing with 530 additions and 238 deletions.
  1. +12 −0 XBMC-ATV2.xcodeproj/project.pbxproj
  2. +12 −0 XBMC-IOS.xcodeproj/project.pbxproj
  3. +12 −0 XBMC.xcodeproj/project.pbxproj
  4. +1 −1  addons/webinterface.default/js/MediaLibrary.js
  5. +2 −2 addons/webinterface.default/js/NowPlayingManager.js
  6. +5 −1 project/VS2010Express/XBMC.vcxproj
  7. +13 −1 project/VS2010Express/XBMC.vcxproj.filters
  8. +5 −0 xbmc/Application.cpp
  9. +2 −0  xbmc/Application.h
  10. +1 −1  xbmc/GUIInfoManager.cpp
  11. +1 −1  xbmc/GUILargeTextureManager.cpp
  12. +28 −79 xbmc/TextureCache.cpp
  13. +16 −36 xbmc/TextureCache.h
  14. +81 −72 xbmc/ThumbLoader.cpp
  15. +6 −0 xbmc/ThumbLoader.h
  16. +2 −0  xbmc/filesystem/FileFactory.cpp
  17. +114 −0 xbmc/filesystem/ImageFile.cpp
  18. +45 −0 xbmc/filesystem/ImageFile.h
  19. +1 −0  xbmc/filesystem/Makefile.in
  20. +4 −4 xbmc/interfaces/http-api/XBMChttp.cpp
  21. +53 −34 xbmc/interfaces/json-rpc/FileItemHandler.cpp
  22. +6 −1 xbmc/network/WebServer.cpp
  23. +61 −0 xbmc/network/httprequesthandler/HTTPImageHandler.cpp
  24. +42 −0 xbmc/network/httprequesthandler/HTTPImageHandler.h
  25. +2 −1  xbmc/network/httprequesthandler/Makefile
  26. +1 −2  xbmc/pictures/PictureThumbLoader.cpp
  27. +2 −2 xbmc/video/VideoInfoTag.cpp
View
12 XBMC-ATV2.xcodeproj/project.pbxproj
@@ -26,6 +26,8 @@
7C0B990A154B80200065A238 /* AEDeviceInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0B9908154B80200065A238 /* AEDeviceInfo.cpp */; };
7C1A89BB152671FB00C63311 /* TextureCacheJob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C1A89B9152671FB00C63311 /* TextureCacheJob.cpp */; };
7C1F6F8C13ED17CC001726AB /* LibraryDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C1F6F8A13ED17CC001726AB /* LibraryDirectory.cpp */; };
+ 7C6EB586155E3EC80080368A /* ImageFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB584155E3EC80080368A /* ImageFile.cpp */; };
+ 7C6EB708155F3B160080368A /* HTTPImageHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB706155F3B160080368A /* HTTPImageHandler.cpp */; };
7C89627013B702F3003631FE /* GUIWindowScreensaverDim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C89626E13B702F3003631FE /* GUIWindowScreensaverDim.cpp */; };
7C99B7AA134072CD00FC2B16 /* GUIDialogPlayEject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C99B7A8134072CD00FC2B16 /* GUIDialogPlayEject.cpp */; };
7CCFD9AA1514952700211D82 /* PCMCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CCFD9A81514952700211D82 /* PCMCodec.cpp */; };
@@ -1016,6 +1018,10 @@
7C1A89BA152671FB00C63311 /* TextureCacheJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextureCacheJob.h; sourceTree = "<group>"; };
7C1F6F8A13ED17CC001726AB /* LibraryDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LibraryDirectory.cpp; sourceTree = "<group>"; };
7C1F6F8B13ED17CC001726AB /* LibraryDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibraryDirectory.h; sourceTree = "<group>"; };
+ 7C6EB584155E3EC80080368A /* ImageFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFile.cpp; sourceTree = "<group>"; };
+ 7C6EB585155E3EC80080368A /* ImageFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFile.h; sourceTree = "<group>"; };
+ 7C6EB706155F3B160080368A /* HTTPImageHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPImageHandler.cpp; sourceTree = "<group>"; };
+ 7C6EB707155F3B160080368A /* HTTPImageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPImageHandler.h; sourceTree = "<group>"; };
7C89626E13B702F3003631FE /* GUIWindowScreensaverDim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowScreensaverDim.cpp; sourceTree = "<group>"; };
7C89626F13B702F3003631FE /* GUIWindowScreensaverDim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIWindowScreensaverDim.h; sourceTree = "<group>"; };
7C99B7A8134072CD00FC2B16 /* GUIDialogPlayEject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogPlayEject.cpp; sourceTree = "<group>"; };
@@ -3235,6 +3241,8 @@
children = (
DFCA6AFE15224684000BFAAE /* HTTPApiHandler.cpp */,
DFCA6AFF15224684000BFAAE /* HTTPApiHandler.h */,
+ 7C6EB706155F3B160080368A /* HTTPImageHandler.cpp */,
+ 7C6EB707155F3B160080368A /* HTTPImageHandler.h */,
DFCA6B0015224684000BFAAE /* HTTPJsonRpcHandler.cpp */,
DFCA6B0115224684000BFAAE /* HTTPJsonRpcHandler.h */,
DFCA6B0215224684000BFAAE /* HTTPVfsHandler.cpp */,
@@ -4291,6 +4299,8 @@
F56C73FA131EC151000AD0F6 /* IFile.cpp */,
F56C73FB131EC151000AD0F6 /* IFile.h */,
F56C73FC131EC151000AD0F6 /* IFileDirectory.h */,
+ 7C6EB584155E3EC80080368A /* ImageFile.cpp */,
+ 7C6EB585155E3EC80080368A /* ImageFile.h */,
F56C73FD131EC151000AD0F6 /* iso9660.cpp */,
F56C73FE131EC151000AD0F6 /* iso9660.h */,
F56C73FF131EC151000AD0F6 /* ISO9660Directory.cpp */,
@@ -7182,6 +7192,8 @@
DFB662FC15376810006B8FF1 /* AEWAVLoader.cpp in Sources */,
DFB6631115376991006B8FF1 /* DVDAudioCodecPassthrough.cpp in Sources */,
7C0B990A154B80200065A238 /* AEDeviceInfo.cpp in Sources */,
+ 7C6EB586155E3EC80080368A /* ImageFile.cpp in Sources */,
+ 7C6EB708155F3B160080368A /* HTTPImageHandler.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
12 XBMC-IOS.xcodeproj/project.pbxproj
@@ -27,6 +27,8 @@
7C0B98F9154B7FF30065A238 /* AEDeviceInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0B98F7154B7FF30065A238 /* AEDeviceInfo.cpp */; };
7C1A89CE1526722200C63311 /* TextureCacheJob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C1A89CC1526722200C63311 /* TextureCacheJob.cpp */; };
7C1F6F7A13ED178F001726AB /* LibraryDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C1F6F7813ED178F001726AB /* LibraryDirectory.cpp */; };
+ 7C6EB570155E3E680080368A /* ImageFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB56E155E3E680080368A /* ImageFile.cpp */; };
+ 7C6EB71A155F3B330080368A /* HTTPImageHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB718155F3B330080368A /* HTTPImageHandler.cpp */; };
7C89628013B7031E003631FE /* GUIWindowScreensaverDim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C89627E13B7031E003631FE /* GUIWindowScreensaverDim.cpp */; };
7C99B7BE1340730000FC2B16 /* GUIDialogPlayEject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C99B7BC1340730000FC2B16 /* GUIDialogPlayEject.cpp */; };
7CCFD9991514950700211D82 /* PCMCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CCFD9971514950700211D82 /* PCMCodec.cpp */; };
@@ -1016,6 +1018,10 @@
7C1A89CD1526722200C63311 /* TextureCacheJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextureCacheJob.h; sourceTree = "<group>"; };
7C1F6F7813ED178F001726AB /* LibraryDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LibraryDirectory.cpp; sourceTree = "<group>"; };
7C1F6F7913ED178F001726AB /* LibraryDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibraryDirectory.h; sourceTree = "<group>"; };
+ 7C6EB56E155E3E680080368A /* ImageFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFile.cpp; sourceTree = "<group>"; };
+ 7C6EB56F155E3E680080368A /* ImageFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFile.h; sourceTree = "<group>"; };
+ 7C6EB718155F3B330080368A /* HTTPImageHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPImageHandler.cpp; sourceTree = "<group>"; };
+ 7C6EB719155F3B330080368A /* HTTPImageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPImageHandler.h; sourceTree = "<group>"; };
7C89627E13B7031E003631FE /* GUIWindowScreensaverDim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowScreensaverDim.cpp; sourceTree = "<group>"; };
7C89627F13B7031E003631FE /* GUIWindowScreensaverDim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIWindowScreensaverDim.h; sourceTree = "<group>"; };
7C99B7BC1340730000FC2B16 /* GUIDialogPlayEject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogPlayEject.cpp; sourceTree = "<group>"; };
@@ -3232,6 +3238,8 @@
children = (
DFCA6ADE15224671000BFAAE /* HTTPApiHandler.cpp */,
DFCA6ADF15224671000BFAAE /* HTTPApiHandler.h */,
+ 7C6EB718155F3B330080368A /* HTTPImageHandler.cpp */,
+ 7C6EB719155F3B330080368A /* HTTPImageHandler.h */,
DFCA6AE015224671000BFAAE /* HTTPJsonRpcHandler.cpp */,
DFCA6AE115224671000BFAAE /* HTTPJsonRpcHandler.h */,
DFCA6AE215224671000BFAAE /* HTTPVfsHandler.cpp */,
@@ -4647,6 +4655,8 @@
F56C83DD131F42E8000AD0F6 /* IFile.cpp */,
F56C83DE131F42E8000AD0F6 /* IFile.h */,
F56C83DF131F42E8000AD0F6 /* IFileDirectory.h */,
+ 7C6EB56E155E3E680080368A /* ImageFile.cpp */,
+ 7C6EB56F155E3E680080368A /* ImageFile.h */,
F56C83E0131F42E8000AD0F6 /* iso9660.cpp */,
F56C83E1131F42E8000AD0F6 /* iso9660.h */,
F56C83E2131F42E8000AD0F6 /* ISO9660Directory.cpp */,
@@ -7193,6 +7203,8 @@
DFB6627615376791006B8FF1 /* AEWAVLoader.cpp in Sources */,
DFB6630C1537697E006B8FF1 /* DVDAudioCodecPassthrough.cpp in Sources */,
7C0B98F9154B7FF30065A238 /* AEDeviceInfo.cpp in Sources */,
+ 7C6EB570155E3E680080368A /* ImageFile.cpp in Sources */,
+ 7C6EB71A155F3B330080368A /* HTTPImageHandler.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
12 XBMC.xcodeproj/project.pbxproj
@@ -260,6 +260,8 @@
7C5608C70F1754930056433A /* ExternalPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C5608C40F1754930056433A /* ExternalPlayer.cpp */; };
7C62F24210505BC7002AD2C1 /* Bookmark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C62F24010505BC7002AD2C1 /* Bookmark.cpp */; };
7C62F45E1057A62D002AD2C1 /* DirectoryNodeSingles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C62F45C1057A62D002AD2C1 /* DirectoryNodeSingles.cpp */; };
+ 7C6EB330155BD1D40080368A /* ImageFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB32E155BD1D40080368A /* ImageFile.cpp */; };
+ 7C6EB6FA155F32C30080368A /* HTTPImageHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB6F8155F32C30080368A /* HTTPImageHandler.cpp */; };
7C779E3A104A57E500F444C4 /* RenderSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C779E1F104A57E500F444C4 /* RenderSystem.cpp */; };
7C779E3B104A57E500F444C4 /* RenderSystemGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C779E21104A57E500F444C4 /* RenderSystemGL.cpp */; };
7C779E3C104A57E500F444C4 /* WinEventsSDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C779E27104A57E500F444C4 /* WinEventsSDL.cpp */; };
@@ -1530,6 +1532,10 @@
7C62F24110505BC7002AD2C1 /* Bookmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bookmark.h; sourceTree = "<group>"; };
7C62F45C1057A62D002AD2C1 /* DirectoryNodeSingles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectoryNodeSingles.cpp; sourceTree = "<group>"; };
7C62F45D1057A62D002AD2C1 /* DirectoryNodeSingles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryNodeSingles.h; sourceTree = "<group>"; };
+ 7C6EB32E155BD1D40080368A /* ImageFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFile.cpp; sourceTree = "<group>"; };
+ 7C6EB32F155BD1D40080368A /* ImageFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFile.h; sourceTree = "<group>"; };
+ 7C6EB6F8155F32C30080368A /* HTTPImageHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPImageHandler.cpp; sourceTree = "<group>"; };
+ 7C6EB6F9155F32C30080368A /* HTTPImageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPImageHandler.h; sourceTree = "<group>"; };
7C779E1F104A57E500F444C4 /* RenderSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSystem.cpp; sourceTree = "<group>"; };
7C779E20104A57E500F444C4 /* RenderSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSystem.h; sourceTree = "<group>"; };
7C779E21104A57E500F444C4 /* RenderSystemGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSystemGL.cpp; sourceTree = "<group>"; };
@@ -4244,6 +4250,8 @@
children = (
DFCA6AB9152245CD000BFAAE /* HTTPApiHandler.cpp */,
DFCA6ABA152245CD000BFAAE /* HTTPApiHandler.h */,
+ 7C6EB6F8155F32C30080368A /* HTTPImageHandler.cpp */,
+ 7C6EB6F9155F32C30080368A /* HTTPImageHandler.h */,
DFCA6ABB152245CD000BFAAE /* HTTPJsonRpcHandler.cpp */,
DFCA6ABC152245CD000BFAAE /* HTTPJsonRpcHandler.h */,
DFCA6ABD152245CD000BFAAE /* HTTPVfsHandler.cpp */,
@@ -4917,6 +4925,8 @@
E38E16EE0D25F9FA00618676 /* IFile.cpp */,
E38E16EF0D25F9FA00618676 /* IFile.h */,
E38E16F00D25F9FA00618676 /* IFileDirectory.h */,
+ 7C6EB32E155BD1D40080368A /* ImageFile.cpp */,
+ 7C6EB32F155BD1D40080368A /* ImageFile.h */,
E38E16F10D25F9FA00618676 /* iso9660.cpp */,
E38E16F20D25F9FA00618676 /* iso9660.h */,
E38E16F30D25F9FA00618676 /* ISO9660Directory.cpp */,
@@ -7260,6 +7270,8 @@
F5ED9496155D7B9900842059 /* CoreAudioMixMap.cpp in Sources */,
F5ED94AB155D7F8000842059 /* CoreAudioUnit.cpp in Sources */,
F5ED9509155D855200842059 /* CoreAudioGraph.cpp in Sources */,
+ 7C6EB330155BD1D40080368A /* ImageFile.cpp in Sources */,
+ 7C6EB6FA155F32C30080368A /* HTTPImageHandler.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
2  addons/webinterface.default/js/MediaLibrary.js
@@ -454,7 +454,7 @@ MediaLibrary.prototype = {
}
},
getThumbnailPath: function(thumbnail) {
- return thumbnail ? ('/vfs/' + thumbnail) : DEFAULT_ALBUM_COVER;
+ return thumbnail ? ('/image/' + encodeURI(thumbnail)) : DEFAULT_ALBUM_COVER;
},
generateThumb: function(type, thumbnail, title, artist) {
var floatableAlbum = $('<div>');
View
4 addons/webinterface.default/js/NowPlayingManager.js
@@ -382,7 +382,7 @@ NowPlayingManager.prototype = {
this.lastPlaylistItem = this.activePlaylistItem;
var imgPath = DEFAULT_ALBUM_COVER;
if (this.activePlaylistItem.thumbnail) {
- imgPath = (this.activePlaylistItem.thumbnail.startsWith('special://') ? '/vfs/' : 'images/') + this.activePlaylistItem.thumbnail;
+ imgPath = this.activePlaylistItem.thumbnail.startsWith('special://') ? ('/image/' + encodeURI(this.activePlaylistItem.thumbnail)) : ('images/' + this.activePlaylistItem.thumbnail);
}
$('#audioCoverArt').html('<img src="' + imgPath + '" alt="' + this.activePlaylistItem.album + ' cover art">');
$('#audioTrackTitle').html('<span title="' + this.activePlaylistItem.title + '">' + this.activePlaylistItem.title + '</span>');
@@ -430,7 +430,7 @@ NowPlayingManager.prototype = {
this.lastPlaylistItem = this.activePlaylistItem;
var imgPath = DEFAULT_VIDEO_COVER;
if (this.activePlaylistItem.thumbnail) {
- imgPath = (this.activePlaylistItem.thumbnail.startsWith('special://') ? '/vfs/' : 'images/') + this.activePlaylistItem.thumbnail;
+ imgPath = this.activePlaylistItem.thumbnail.startsWith('special://') ? ('/image/' + encodeURI(this.activePlaylistItem.thumbnail)) : ('images/' + this.activePlaylistItem.thumbnail);
}
$('#videoCoverArt').html('<img src="' + imgPath + '" alt="' + this.activePlaylistItem.title + ' cover art">');
$('#videoShowTitle').html(this.activePlaylistItem.showtitle||'&nbsp;');
View
6 project/VS2010Express/XBMC.vcxproj
@@ -393,6 +393,7 @@
<ClCompile Include="..\..\xbmc\filesystem\HTTPDirectory.cpp" />
<ClCompile Include="..\..\xbmc\filesystem\IDirectory.cpp" />
<ClCompile Include="..\..\xbmc\filesystem\IFile.cpp" />
+ <ClCompile Include="..\..\xbmc\filesystem\ImageFile.cpp" />
<ClCompile Include="..\..\xbmc\filesystem\iso9660.cpp" />
<ClCompile Include="..\..\xbmc\filesystem\ISO9660Directory.cpp" />
<ClCompile Include="..\..\xbmc\filesystem\ISOFile.cpp" />
@@ -790,6 +791,7 @@
<ClCompile Include="..\..\xbmc\network\GUIDialogAccessPoints.cpp" />
<ClCompile Include="..\..\xbmc\network\GUIDialogNetworkSetup.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPApiHandler.cpp" />
+ <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPJsonRpcHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPWebinterfaceAddonsHandler.cpp" />
@@ -923,9 +925,11 @@
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Utils\AEWAVLoader.h" />
<ClInclude Include="..\..\xbmc\cores\dvdplayer\DVDCodecs\Audio\DVDAudioCodecPassthrough.h" />
<ClInclude Include="..\..\xbmc\cores\paplayer\PCMCodec.h" />
+ <ClInclude Include="..\..\xbmc\filesystem\ImageFile.h" />
<ClInclude Include="..\..\xbmc\filesystem\windows\WINFileSMB.h" />
<ClInclude Include="..\..\xbmc\filesystem\windows\WINSMBDirectory.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\xbmcmodule\pythreadstate.h" />
+ <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.h" />
<ClInclude Include="..\..\xbmc\network\websocket\WebSocket.h" />
<ClInclude Include="..\..\xbmc\network\websocket\WebSocketManager.h" />
<ClInclude Include="..\..\xbmc\network\websocket\WebSocketV13.h" />
@@ -2278,4 +2282,4 @@
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project>
+</Project>
View
14 project/VS2010Express/XBMC.vcxproj.filters
@@ -2578,6 +2578,12 @@
<ClCompile Include="..\..\xbmc\utils\RecentlyAddedJob.cpp">
<Filter>utils</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\filesystem\ImageFile.cpp">
+ <Filter>filesystem</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.cpp">
+ <Filter>network\httprequesthandler</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\xbmc\win32\pch.h">
@@ -5193,6 +5199,12 @@
<ClInclude Include="..\..\xbmc\utils\RecentlyAddedJob.h">
<Filter>utils</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\filesystem\ImageFile.h">
+ <Filter>filesystem</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.h">
+ <Filter>network\httprequesthandler</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
@@ -5204,4 +5216,4 @@
<Filter>win32</Filter>
</CustomBuild>
</ItemGroup>
-</Project>
+</Project>
View
5 xbmc/Application.cpp
@@ -38,6 +38,7 @@
#include "video/Bookmark.h"
#ifdef HAS_WEB_SERVER
#include "network/WebServer.h"
+#include "network/httprequesthandler/HTTPImageHandler.h"
#include "network/httprequesthandler/HTTPVfsHandler.h"
#ifdef HAS_HTTPAPI
#include "network/httprequesthandler/HTTPApiHandler.h"
@@ -345,6 +346,7 @@ CApplication::CApplication(void)
: m_pPlayer(NULL)
#ifdef HAS_WEB_SERVER
, m_WebServer(*new CWebServer)
+ , m_httpImageHandler(*new CHTTPImageHandler)
, m_httpVfsHandler(*new CHTTPVfsHandler)
#ifdef HAS_JSONRPC
, m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler)
@@ -408,6 +410,7 @@ CApplication::~CApplication(void)
{
#ifdef HAS_WEB_SERVER
delete &m_WebServer;
+ delete &m_httpImageHandler;
delete &m_httpVfsHandler;
#ifdef HAS_HTTPAPI
delete &m_httpApiHandler;
@@ -1119,6 +1122,7 @@ bool CApplication::Initialize()
g_curlInterface.Unload();
#ifdef HAS_WEB_SERVER
+ CWebServer::RegisterRequestHandler(&m_httpImageHandler);
CWebServer::RegisterRequestHandler(&m_httpVfsHandler);
#ifdef HAS_JSONRPC
CWebServer::RegisterRequestHandler(&m_httpJsonRpcHandler);
@@ -3366,6 +3370,7 @@ void CApplication::Stop(int exitCode)
//Sleep(5000);
#ifdef HAS_WEB_SERVER
+ CWebServer::UnregisterRequestHandler(&m_httpImageHandler);
CWebServer::UnregisterRequestHandler(&m_httpVfsHandler);
#ifdef HAS_JSONRPC
CWebServer::UnregisterRequestHandler(&m_httpJsonRpcHandler);
View
2  xbmc/Application.h
@@ -71,6 +71,7 @@ class CBookmark;
class CWebServer;
#ifdef HAS_WEB_SERVER
class CWebServer;
+class CHTTPImageHandler;
class CHTTPVfsHandler;
#ifdef HAS_JSONRPC
class CHTTPJsonRpcHandler;
@@ -259,6 +260,7 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
#ifdef HAS_WEB_SERVER
CWebServer& m_WebServer;
+ CHTTPImageHandler& m_httpImageHandler;
CHTTPVfsHandler& m_httpVfsHandler;
#ifdef HAS_JSONRPC
CHTTPJsonRpcHandler& m_httpJsonRpcHandler;
View
2  xbmc/GUIInfoManager.cpp
@@ -3584,7 +3584,7 @@ void CGUIInfoManager::SetCurrentMovie(CFileItem &item)
if (!CVideoThumbLoader::FillThumb(item))
{
CStdString thumb = CVideoThumbLoader::GetEmbeddedThumbURL(item);
- if (!CTextureCache::Get().GetCachedImage(thumb).IsEmpty())
+ if (CTextureCache::Get().HasCachedImage(thumb))
item.SetThumbnailImage(thumb);
}
}
View
2  xbmc/GUILargeTextureManager.cpp
@@ -57,7 +57,7 @@ bool CImageLoader::DoWork()
if (loadPath.IsEmpty())
{
// not in our texture cache, so try and load directly and then cache the result
- loadPath = CTextureCache::Get().CacheTexture(texturePath, &m_texture);
+ loadPath = CTextureCache::Get().CacheImage(texturePath, &m_texture);
if (m_texture)
return true; // we're done
}
View
107 xbmc/TextureCache.cpp
@@ -69,22 +69,17 @@ bool CTextureCache::IsCachedImage(const CStdString &url) const
return false;
}
-CStdString CTextureCache::GetCachedImage(const CStdString &url)
+bool CTextureCache::HasCachedImage(const CStdString &url)
{
CStdString cachedHash;
- return GetCachedImage(url, cachedHash);
+ return !GetCachedImage(url, cachedHash).IsEmpty();
}
-CStdString CTextureCache::GetCachedImage(const CStdString &url, CStdString &cachedHash)
+CStdString CTextureCache::GetCachedImage(const CStdString &image, CStdString &cachedHash)
{
cachedHash.clear();
- if (url.compare(0, 8, "image://") == 0)
- {
- CStdString image = CURL(url).GetHostName();
- CURL::Decode(image);
- if (IsCachedImage(image))
- return image; // no point generating thumbs of already cached images
- }
+ CStdString url = UnwrapImageURL(image);
+
if (IsCachedImage(url))
return url;
@@ -100,6 +95,9 @@ CStdString CTextureCache::GetCachedImage(const CStdString &url, CStdString &cach
CStdString CTextureCache::GetWrappedImageURL(const CStdString &image, const CStdString &type, const CStdString &options)
{
+ if (image.compare(0, 8, "image://") == 0)
+ return image; // already wrapped
+
CStdString encoded(image);
CURL::Encode(encoded);
CStdString url = "image://";
@@ -116,6 +114,21 @@ CStdString CTextureCache::GetWrappedThumbURL(const CStdString &image)
return GetWrappedImageURL(image, "", "size=thumb");
}
+CStdString CTextureCache::UnwrapImageURL(const CStdString &image)
+{
+ if (image.compare(0, 8, "image://") == 0)
+ {
+ CURL url(image);
+ if (url.GetUserName().IsEmpty() && url.GetOptions().IsEmpty())
+ {
+ CStdString file(url.GetHostName());
+ CURL::Decode(file);
+ return file;
+ }
+ }
+ return image;
+}
+
CStdString CTextureCache::CheckCachedImage(const CStdString &url, bool returnDDS, bool &needsRecaching)
{
CStdString cachedHash;
@@ -136,17 +149,6 @@ CStdString CTextureCache::CheckCachedImage(const CStdString &url, bool returnDDS
return "";
}
-CStdString CTextureCache::CheckAndCacheImage(const CStdString &url, bool returnDDS)
-{
- bool needsRecaching = false;
- CStdString path(CheckCachedImage(url, returnDDS, needsRecaching));
- if (!path.IsEmpty())
- {
- return path;
- }
- return CacheImageFile(url);
-}
-
void CTextureCache::BackgroundCacheImage(const CStdString &url)
{
CStdString cacheHash;
@@ -155,11 +157,12 @@ void CTextureCache::BackgroundCacheImage(const CStdString &url)
return; // image is already cached and doesn't need to be checked further
// needs (re)caching
- AddJob(new CTextureCacheJob(url, cacheHash));
+ AddJob(new CTextureCacheJob(UnwrapImageURL(url), cacheHash));
}
-CStdString CTextureCache::CacheTexture(const CStdString &url, CBaseTexture **texture)
+CStdString CTextureCache::CacheImage(const CStdString &image, CBaseTexture **texture)
{
+ CStdString url = UnwrapImageURL(image);
CSingleLock lock(m_processingSection);
if (m_processing.find(url) == m_processing.end())
{
@@ -187,50 +190,6 @@ CStdString CTextureCache::CacheTexture(const CStdString &url, CBaseTexture **tex
return GetCachedImage(url, cachedHash);
}
-CStdString CTextureCache::CacheImageFile(const CStdString &url)
-{
- return CacheTexture(url);
-
- // TODO: In the future we need a cache job to callback when the image is loaded
- // thus automatically updating the images. We'd also need fallback code inside
- // the CGUITexture class to display something from this point on.
-
- // Have this caching stuff be a lifo stack, and bump things up the stack when we should (check whether
- // CJobQueue does this...) That way we can have a bunch of "cache thumb kthxpls" run from a background
- // thread, and all we do here is cache from the size we've already been given. If we haven't been
- // given a size, we must assume that the user wants fullsize. We could, in fact, add the sizing of it
- // into the URL scheme using options... i.e. http://my.thumb/file|width=blah|height=foo
- // that gives us sizing goodness, plus pre-caching goodness where we know shit should be cached
- // all with the fandangled jobmanager....
-
- // We almost need a better interface on the loading side of things - i.e. we need the textures to
- // request a particular image and to get some (immediate?) recognition as to whether it's cached
- // so that a fallback image can be specified. Perhaps the texture updating routines (i.e.
- // UpdateInfo and/or SetFileName) might handle this? The procedure would be to hit the db
- // to see if this image is available or not. If it isn't, then we simply load the fallback or
- // "loading..." image, but keep testing to see if the image has been cached or not. Hmm,
- // that's inefficient as well - at the very least a string compare or 12 per frame as it tests
- // a list of caching jobs, or (more inefficiently) a db query every frame.
-
- // The "best" method is the callback technique - this can be done quite easily though if the texture
- // is the one that makes the request I think? At least when one texture is involved - we pass in our
- // pointer to the callback list. In fact, we could generalize this somewhat with the texture
- // manager handling those pointers - after all, it already handles reference counting, so why not
- // count using the callback pointers instead? We then wouldn't have to call AllocResources() all
- // the time. When the texture is loaded it's moved from the queued to the allocated list, and at
- // that point we could have an interim list (loaded) that we then run the callbacks on once a frame.
- // There'd be a "LOADING" enum for allocation of the image and the texture could then show a fallback?
- // Main problem with this is CGUITexture doesn't have any concept of a fallback: CGUIImage does instead.
- // The main fallback mechanism we use is LISTITEM_ICON vs LISTITEM_THUMB - with the former we actually
- // use the thumb if it's available, and drop back to the icon if it's not. In either case, having
- // a "loading" fallback would be useful even if it wasn't the icon. I guess this could be a property
- // of CGUITexture similar to how background="true" is? The loading texture would be displayed if
- // and only if there is an image being loaded. Need to talk to Jezz_X about this - eg if you have
- // a current image and a new one is loading we currently hold on to the current one and render
- // the current one faded out - we'd need to change this so that the fading only happened once it
- // was ready to render.
-}
-
void CTextureCache::ClearCachedImage(const CStdString &url, bool deleteSource /*= false */)
{
// TODO: This can be removed when the texture cache covers everything.
@@ -340,20 +299,10 @@ void CTextureCache::OnJobProgress(unsigned int jobID, unsigned int progress, uns
CJobQueue::OnJobProgress(jobID, progress, total, job);
}
-CStdString CTextureCache::GetUniqueImage(const CStdString &url, const CStdString &extension)
-{
- Crc32 crc;
- crc.ComputeFromLowerCase(url);
- CStdString hex;
- hex.Format("%08x", (unsigned int)crc);
- CStdString hash;
- hash.Format("generated/%c/%s%s", hex[0], hex.c_str(), extension.c_str());
- return GetCachedPath(hash);
-}
-
bool CTextureCache::Export(const CStdString &image, const CStdString &destination)
{
- CStdString cachedImage(GetCachedImage(image));
+ CStdString cachedHash;
+ CStdString cachedImage(GetCachedImage(image, cachedHash));
if (!cachedImage.IsEmpty())
{
if (CFile::Cache(cachedImage, destination))
View
52 xbmc/TextureCache.h
@@ -70,24 +70,14 @@ class CTextureCache : public CJobQueue
*/
CStdString CheckCachedImage(const CStdString &image, bool returnDDS, bool &needsRecaching);
- /*! \brief This function is a wrapper around CheckCacheImage and CacheImageFile.
-
- Checks firstly whether an image is already cached, and return URL if so [see CheckCacheImage]
- If the image is not yet in the database it is cached and added to the database [see CacheImageFile]
-
- \param image url of the image to check and cache
- \param returnDDS if we're allowed to return a DDS version, defaults to true
- \return cached url of this image
- \sa CheckCacheImage
- */
- CStdString CheckAndCacheImage(const CStdString &image, bool returnDDS = true);
-
/*! \brief Cache image (if required) using a background job
- Essentially a threaded version of CheckAndCacheImage.
+ Checks firstly whether an image is already cached, and return URL if so [see CheckCacheImage]
+ If the image is not yet in the database, a background job is started to
+ cache the image and add to the database [see CTextureCacheJob]
\param image url of the image to cache
- \sa CheckAndCacheImage
+ \sa CacheImage
*/
void BackgroundCacheImage(const CStdString &image);
@@ -100,24 +90,14 @@ class CTextureCache : public CJobQueue
\return cached url of this image
\sa CTextureCacheJob::CacheTexture
*/
- CStdString CacheTexture(const CStdString &url, CBaseTexture **texture = NULL);
-
- /*! \brief Take image URL and add it to image cache
+ CStdString CacheImage(const CStdString &url, CBaseTexture **texture = NULL);
- Takes the URL to an image. Caches and adds to the database.
-
- \param image url of the image to cache
- \return cached url of this image
- \sa CTextureCacheJob::DoWork
- */
- CStdString CacheImageFile(const CStdString &url);
-
- /*! \brief retrieve the cached version of the given image (if it exists)
+ /*! \brief Check whether an image is cached
\param image url of the image
- \return cached url of this image, empty if none exists
+ \return true if the image is cached, false otherwise
\sa ClearCachedImage
*/
- CStdString GetCachedImage(const CStdString &image);
+ bool HasCachedImage(const CStdString &image);
/*! \brief clear the cached version of the given image
\param image url of the image
@@ -144,16 +124,9 @@ class CTextureCache : public CJobQueue
\param options which options we need (eg size=thumb)
\return full wrapped URL of the image file
*/
- static CStdString GetWrappedImageURL(const CStdString &image, const CStdString &type, const CStdString &options = "");
+ static CStdString GetWrappedImageURL(const CStdString &image, const CStdString &type = "", const CStdString &options = "");
static CStdString GetWrappedThumbURL(const CStdString &image);
- /*! \brief get a unique image path to associate with the given URL, useful for caching images
- \param url path to retrieve a unique image for
- \param extension type of file we want
- \return a "unique" path to an image with the appropriate extension
- */
- static CStdString GetUniqueImage(const CStdString &url, const CStdString &extension);
-
/*! \brief Add this image to the database
Thread-safe wrapper of CTextureDatabase::AddCachedTexture
\param image url of the original image
@@ -175,6 +148,13 @@ class CTextureCache : public CJobQueue
CTextureCache const& operator=(CTextureCache const&);
virtual ~CTextureCache();
+ /*! \brief Unwrap an image://<url_encoded_path> style URL
+ Such urls are used for art over the webserver or other users of the VFS
+ \param image url of the image
+ \return the unwrapped URL, or the original URL if unwrapping is inappropriate.
+ */
+ static CStdString UnwrapImageURL(const CStdString &image);
+
/*! \brief Check if the given image is a cached image
\param image url of the image
\return true if this is a cached image, false otherwise.
View
153 xbmc/ThumbLoader.cpp
@@ -199,8 +199,86 @@ bool CVideoThumbLoader::LoadItem(CFileItem* pItem)
}
// video db items normally have info in the database
- if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iDbId > -1 &&
- !pItem->GetVideoInfoTag()->m_type.IsEmpty() && pItem->GetArt().empty())
+ if (pItem->HasVideoInfoTag() && pItem->GetArt().empty())
+ {
+ FillLibraryArt(pItem);
+
+ if (pItem->GetVideoInfoTag()->m_type != "movie" &&
+ pItem->GetVideoInfoTag()->m_type != "episode" &&
+ pItem->GetVideoInfoTag()->m_type != "tvshow" &&
+ pItem->GetVideoInfoTag()->m_type != "musicvideo")
+ return true; // nothing else to be done
+ }
+
+ // fanart
+ if (!pItem->HasProperty("fanart_image"))
+ {
+ CStdString fanart = GetCachedImage(*pItem, "fanart");
+ if (fanart.IsEmpty())
+ {
+ fanart = pItem->GetLocalFanart();
+ if (!fanart.IsEmpty()) // cache it
+ SetCachedImage(*pItem, "fanart", fanart);
+ }
+ if (!fanart.IsEmpty())
+ {
+ CTextureCache::Get().BackgroundCacheImage(fanart);
+ pItem->SetProperty("fanart_image", fanart);
+ }
+ }
+
+ // thumbnails
+ if (!pItem->HasThumbnail())
+ {
+ FillThumb(*pItem);
+ if (!pItem->HasThumbnail() && !pItem->m_bIsFolder && pItem->IsVideo())
+ {
+ // create unique thumb for auto generated thumbs
+ CStdString thumbURL = GetEmbeddedThumbURL(*pItem);
+ if (CTextureCache::Get().HasCachedImage(thumbURL))
+ {
+ CTextureCache::Get().BackgroundCacheImage(thumbURL);
+ pItem->SetProperty("HasAutoThumb", true);
+ pItem->SetProperty("AutoThumbImage", thumbURL);
+ pItem->SetThumbnailImage(thumbURL);
+ }
+ else if (g_guiSettings.GetBool("myvideos.extractthumb") &&
+ g_guiSettings.GetBool("myvideos.extractflags"))
+ {
+ CFileItem item(*pItem);
+ CStdString path(item.GetPath());
+ if (URIUtils::IsInRAR(item.GetPath()))
+ SetupRarOptions(item,path);
+
+ CThumbExtractor* extract = new CThumbExtractor(item, path, true, thumbURL);
+ AddJob(extract);
+ return true;
+ }
+ }
+ }
+
+ // flag extraction
+ if (!pItem->m_bIsFolder &&
+ pItem->HasVideoInfoTag() &&
+ g_guiSettings.GetBool("myvideos.extractflags") &&
+ (!pItem->GetVideoInfoTag()->HasStreamDetails() ||
+ pItem->GetVideoInfoTag()->m_streamDetails.GetVideoDuration() <= 0))
+ {
+ CFileItem item(*pItem);
+ CStdString path(item.GetPath());
+ if (URIUtils::IsInRAR(item.GetPath()))
+ SetupRarOptions(item,path);
+ CThumbExtractor* extract = new CThumbExtractor(item,path,false);
+ AddJob(extract);
+ }
+
+ return true;
+}
+
+bool CVideoThumbLoader::FillLibraryArt(CFileItem *pItem)
+{
+ if (pItem->GetVideoInfoTag()->m_iDbId > -1 &&
+ !pItem->GetVideoInfoTag()->m_type.IsEmpty())
{
CVideoDatabase db;
db.Open();
@@ -281,77 +359,8 @@ bool CVideoThumbLoader::LoadItem(CFileItem* pItem)
pItem->SetProperty("fanart_image", fanart);
}
db.Close();
-
- if (pItem->GetVideoInfoTag()->m_type != "movie" &&
- pItem->GetVideoInfoTag()->m_type != "episode" &&
- pItem->GetVideoInfoTag()->m_type != "tvshow" &&
- pItem->GetVideoInfoTag()->m_type != "musicvideo")
- return true; // nothing else to be done
- }
-
- // fanart
- if (!pItem->HasProperty("fanart_image"))
- {
- CStdString fanart = GetCachedImage(*pItem, "fanart");
- if (fanart.IsEmpty())
- {
- fanart = pItem->GetLocalFanart();
- if (!fanart.IsEmpty()) // cache it
- SetCachedImage(*pItem, "fanart", fanart);
- }
- if (!fanart.IsEmpty())
- {
- CTextureCache::Get().BackgroundCacheImage(fanart);
- pItem->SetProperty("fanart_image", fanart);
- }
}
-
- // thumbnails
- if (!pItem->HasThumbnail())
- {
- FillThumb(*pItem);
- if (!pItem->HasThumbnail() && !pItem->m_bIsFolder && pItem->IsVideo())
- {
- // create unique thumb for auto generated thumbs
- CStdString thumbURL = GetEmbeddedThumbURL(*pItem);
- if (!CTextureCache::Get().GetCachedImage(thumbURL).IsEmpty())
- {
- CTextureCache::Get().BackgroundCacheImage(thumbURL);
- pItem->SetProperty("HasAutoThumb", true);
- pItem->SetProperty("AutoThumbImage", thumbURL);
- pItem->SetThumbnailImage(thumbURL);
- }
- else if (g_guiSettings.GetBool("myvideos.extractthumb") &&
- g_guiSettings.GetBool("myvideos.extractflags"))
- {
- CFileItem item(*pItem);
- CStdString path(item.GetPath());
- if (URIUtils::IsInRAR(item.GetPath()))
- SetupRarOptions(item,path);
-
- CThumbExtractor* extract = new CThumbExtractor(item, path, true, thumbURL);
- AddJob(extract);
- return true;
- }
- }
- }
-
- // flag extraction
- if (!pItem->m_bIsFolder &&
- pItem->HasVideoInfoTag() &&
- g_guiSettings.GetBool("myvideos.extractflags") &&
- (!pItem->GetVideoInfoTag()->HasStreamDetails() ||
- pItem->GetVideoInfoTag()->m_streamDetails.GetVideoDuration() <= 0))
- {
- CFileItem item(*pItem);
- CStdString path(item.GetPath());
- if (URIUtils::IsInRAR(item.GetPath()))
- SetupRarOptions(item,path);
- CThumbExtractor* extract = new CThumbExtractor(item,path,false);
- AddJob(extract);
- }
-
- return true;
+ return !pItem->GetArt().empty();
}
bool CVideoThumbLoader::FillThumb(CFileItem &item)
View
6 xbmc/ThumbLoader.h
@@ -104,6 +104,12 @@ class CVideoThumbLoader : public CThumbLoader, public CJobQueue
*/
static CStdString GetEmbeddedThumbURL(const CFileItem &item);
+ /*! \brief helper function to fill the art for a video library item
+ \param item a video CFileItem
+ \return true if we fill art, false otherwise
+ */
+ bool FillLibraryArt(CFileItem *item);
+
/*!
\brief Callback from CThumbExtractor on completion of a generated image
View
2  xbmc/filesystem/FileFactory.cpp
@@ -79,6 +79,7 @@
#include "MythFile.h"
#include "HDHomeRunFile.h"
#include "SlingboxFile.h"
+#include "ImageFile.h"
#include "Application.h"
#include "URL.h"
#include "utils/log.h"
@@ -117,6 +118,7 @@ IFile* CFileFactory::CreateLoader(const CURL& url)
else if (strProtocol == "videodb") return NULL;
else if (strProtocol == "special") return new CSpecialProtocolFile();
else if (strProtocol == "multipath") return new CMultiPathFile();
+ else if (strProtocol == "image") return new CImageFile();
else if (strProtocol == "file" || strProtocol.IsEmpty()) return new CHDFile();
else if (strProtocol == "filereader") return new CFileReaderFile();
#if defined(HAS_FILESYSTEM_CDDA) && defined(HAS_DVD_DRIVE)
View
114 xbmc/filesystem/ImageFile.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "ImageFile.h"
+#include "utils/URIUtils.h"
+#include "URL.h"
+#include "TextureCache.h"
+
+using namespace XFILE;
+using namespace std;
+
+CImageFile::CImageFile(void)
+{
+}
+
+CImageFile::~CImageFile(void)
+{
+ Close();
+}
+
+bool CImageFile::Open(const CURL& url)
+{
+ CStdString file = url.Get();
+ bool needsRecaching = false;
+ CStdString cachedFile = CTextureCache::Get().CheckCachedImage(file, false, needsRecaching);
+ if (cachedFile.IsEmpty())
+ { // not in the cache, so cache it
+ cachedFile = CTextureCache::Get().CacheImage(file);
+ }
+ if (!cachedFile.IsEmpty())
+ { // in the cache, return what we have
+ if (m_file.Open(cachedFile))
+ return true;
+ }
+ return false;
+}
+
+bool CImageFile::Exists(const CURL& url)
+{
+ bool needsRecaching = false;
+ CStdString cachedFile = CTextureCache::Get().CheckCachedImage(url.Get(), false, needsRecaching);
+ if (!cachedFile.IsEmpty())
+ return CFile::Exists(cachedFile);
+
+ // need to check if the original can be cached on demand and that the file exists
+ if (!url.GetUserName().IsEmpty())
+ return false; // not in the cache, and can't be cached on demand
+
+ CStdString image = url.GetHostName();
+ CURL::Decode(image);
+ return CFile::Exists(image);
+}
+
+int CImageFile::Stat(const CURL& url, struct __stat64* buffer)
+{
+ bool needsRecaching = false;
+ CStdString cachedFile = CTextureCache::Get().CheckCachedImage(url.Get(), false, needsRecaching);
+ if (!cachedFile.IsEmpty())
+ return CFile::Stat(cachedFile, buffer);
+
+ /*
+ Doesn't exist in the cache yet. We have 3 options here:
+ 1. Cache the file and do the Stat() on the cached file.
+ 2. Do the Stat() on the original file.
+ 3. Return -1;
+ Only 1 will return valid results, at the cost of being time consuming. ATM we do 3 under
+ the theory that the only user of this is the webinterface currently, where Stat() is not
+ required.
+ */
+ return -1;
+}
+
+unsigned int CImageFile::Read(void* lpBuf, int64_t uiBufSize)
+{
+ return m_file.Read(lpBuf, uiBufSize);
+}
+
+int64_t CImageFile::Seek(int64_t iFilePosition, int iWhence /*=SEEK_SET*/)
+{
+ return m_file.Seek(iFilePosition, iWhence);
+}
+
+void CImageFile::Close()
+{
+ m_file.Close();
+}
+
+int64_t CImageFile::GetPosition()
+{
+ return m_file.GetPosition();
+}
+
+int64_t CImageFile::GetLength()
+{
+ return m_file.GetLength();
+}
View
45 xbmc/filesystem/ImageFile.h
@@ -0,0 +1,45 @@
+#pragma once
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "File.h"
+
+namespace XFILE
+{
+ class CImageFile: public IFile
+ {
+ public:
+ CImageFile();
+ virtual ~CImageFile();
+ virtual bool Open(const CURL& url);
+ virtual bool Exists(const CURL& url);
+ virtual int Stat(const CURL& url, struct __stat64* buffer);
+
+ virtual unsigned int Read(void* lpBuf, int64_t uiBufSize);
+ virtual int64_t Seek(int64_t iFilePosition, int iWhence = SEEK_SET);
+ virtual void Close();
+ virtual int64_t GetPosition();
+ virtual int64_t GetLength();
+
+ protected:
+ CFile m_file;
+ };
+}
View
1  xbmc/filesystem/Makefile.in
@@ -33,6 +33,7 @@ SRCS=AddonsDirectory.cpp \
HTTPDirectory.cpp \
IDirectory.cpp \
IFile.cpp \
+ ImageFile.cpp \
iso9660.cpp \
ISO9660Directory.cpp \
ISOFile.cpp \
View
8 xbmc/interfaces/http-api/XBMChttp.cpp
@@ -1259,7 +1259,7 @@ int CXbmcHttp::xbmcGetMovieDetails(int numParas, CStdString paras[])
if (!CVideoThumbLoader::FillThumb(*item))
thumb = "[None]";
else
- thumb = CTextureCache::Get().CheckAndCacheImage(item->GetThumbnailImage());
+ thumb = CTextureCache::GetWrappedImageURL(item->GetThumbnailImage());
output += closeTag+openTag+"Thumb:" + thumb;
m_database.Close();
delete item;
@@ -1322,9 +1322,9 @@ int CXbmcHttp::xbmcGetCurrentlyPlaying(int numParas, CStdString paras[])
resolution = slide->GetPictureInfoTag()->GetInfo(SLIDE_RESOLUTION);
slideOutput+=closeTag+openTag+prefix+"Resolution:" + resolution;
CFileItem item(*slide);
- thumb = CTextureCache::Get().GetCachedImage(CTextureCache::GetWrappedThumbURL(item.GetPath()));
- if (autoGetPictureThumbs && thumb.IsEmpty())
- thumb = CTextureCache::Get().CheckAndCacheImage(CTextureCache::GetWrappedThumbURL(item.GetPath()), false);
+ CStdString thumbURL = CTextureCache::GetWrappedThumbURL(item.GetPath());
+ if (autoGetPictureThumbs || CTextureCache::Get().HasCachedImage(thumbURL))
+ thumb = thumbURL;
if (thumb.IsEmpty())
{
thumb = "[None]";
View
87 xbmc/interfaces/json-rpc/FileItemHandler.cpp
@@ -49,6 +49,8 @@ void CFileItemHandler::FillDetails(ISerializable* info, CFileItemPtr item, const
CVariant serialization;
info->Serialize(serialization);
+ bool fetchedArt = false;
+
for (unsigned int i = 0; i < fields.size(); i++)
{
CStdString field = fields[i].asString();
@@ -89,16 +91,59 @@ void CFileItemHandler::FillDetails(ISerializable* info, CFileItemPtr item, const
continue;
}
- if (field == "fanart" && !item->HasPictureInfoTag())
+ if (field == "thumbnail")
{
- CStdString fanart;
- if (item->HasProperty("fanart_image"))
- fanart = CTextureCache::Get().CheckAndCacheImage(item->GetProperty("fanart_image").asString());
- if (fanart.empty())
- fanart = item->GetCachedFanart();
- if (!fanart.empty())
- result["fanart"] = fanart.c_str();
+ if (item->HasVideoInfoTag())
+ {
+ if (!item->HasThumbnail() && !fetchedArt && item->GetVideoInfoTag()->m_iDbId > -1)
+ {
+ CVideoThumbLoader loader;
+ loader.FillLibraryArt(item.get());
+ fetchedArt = true;
+ }
+ if (item->HasThumbnail())
+ result["thumbnail"] = CTextureCache::GetWrappedImageURL(item->GetThumbnailImage());
+ }
+ else if (item->HasPictureInfoTag())
+ {
+ if (!item->HasThumbnail())
+ item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(item->GetPath()));
+ if (item->HasThumbnail())
+ result["thumbnail"] = CTextureCache::GetWrappedImageURL(item->GetThumbnailImage());
+ }
+ else
+ { // TODO: music art is not currently wrapped
+ if (item->HasThumbnail())
+ result["thumbnail"] = item->GetThumbnailImage();
+ }
+ if (!result.isMember("thumbnail"))
+ result["thumbnail"] = "";
+ continue;
+ }
+ if (field == "fanart")
+ {
+ if (item->HasVideoInfoTag())
+ {
+ if (!item->HasProperty("fanart_image") && !fetchedArt && item->GetVideoInfoTag()->m_iDbId > -1)
+ {
+ CVideoThumbLoader loader;
+ loader.FillLibraryArt(item.get());
+ fetchedArt = true;
+ }
+ if (item->HasProperty("fanart_image"))
+ result["fanart"] = CTextureCache::GetWrappedImageURL(item->GetProperty("fanart_image").asString());
+ }
+ else if (item->HasMusicInfoTag())
+ { // TODO: music art is not currently wrapped
+ CStdString fanart;
+ if (item->HasProperty("fanart_image"))
+ fanart = item->GetProperty("fanart_image").asString();
+ if (fanart.empty())
+ fanart = item->GetCachedFanart();
+ if (!fanart.empty())
+ result["fanart"] = fanart.c_str();
+ }
continue;
}
@@ -154,7 +199,6 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
{
CVariant object;
bool hasFileField = false;
- bool hasThumbnailField = false;
if (item.get())
{
@@ -164,8 +208,6 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
if (field == "file")
hasFileField = true;
- if (field == "thumbnail")
- hasThumbnailField = true;
}
if (allowFile && hasFileField)
@@ -227,29 +269,6 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
}
}
- if (hasThumbnailField)
- {
- if (item->HasThumbnail())
- object["thumbnail"] = CTextureCache::Get().CheckAndCacheImage(item->GetThumbnailImage());
- else if (item->HasVideoInfoTag())
- { // TODO: Should the JSON-API return actual image URLs, virtual thumb URLs, or local URLs to the cached image?
- // ATM we return the latter
- CStdString thumbURL = CVideoThumbLoader::GetEmbeddedThumbURL(*item);
- CStdString cachedThumb = CTextureCache::Get().GetCachedImage(thumbURL);
- if (!cachedThumb.IsEmpty())
- object["thumbnail"] = cachedThumb;
- }
- else if (item->HasPictureInfoTag())
- {
- CStdString thumb = CTextureCache::Get().CheckAndCacheImage(CTextureCache::GetWrappedThumbURL(item->GetPath()));
- if (!thumb.empty())
- object["thumbnail"] = thumb;
- }
-
- if (!object.isMember("thumbnail"))
- object["thumbnail"] = "";
- }
-
FillDetails(item.get(), item, validFields, object);
if (item->HasVideoInfoTag())
View
7 xbmc/network/WebServer.cpp
@@ -560,8 +560,13 @@ bool CWebServer::PrepareDownload(const char *path, CVariant &details, std::strin
if (exists)
{
protocol = "http";
- string url = "vfs/";
+ string url;
CStdString strPath = path;
+ if (strPath.Left(8) == "image://" ||
+ (strPath.Left(10) == "special://" && strPath.Right(4) == ".tbn"))
+ url = "image/";
+ else
+ url = "vfs/";
CURL::Encode(strPath);
url += strPath;
details["path"] = url;
View
61 xbmc/network/httprequesthandler/HTTPImageHandler.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "HTTPImageHandler.h"
+#include "network/WebServer.h"
+#include "URL.h"
+#include "filesystem/ImageFile.h"
+
+using namespace std;
+
+bool CHTTPImageHandler::CheckHTTPRequest(const HTTPRequest &request)
+{
+ return (request.url.find("/image/") == 0);
+}
+
+int CHTTPImageHandler::HandleHTTPRequest(const HTTPRequest &request)
+{
+ if (request.url.size() > 7)
+ {
+ m_path = request.url.substr(7);
+
+ XFILE::CImageFile imageFile;
+ if (imageFile.Exists(m_path) ||
+ // temporary workaround for music images until they are integrated into CTextureCache and therefore CImageFile
+ (m_path.Left(10) == "special://" && m_path.Right(4) == ".tbn" && XFILE::CFile::Exists(m_path)))
+ {
+ m_responseCode = MHD_HTTP_OK;
+ m_responseType = HTTPFileDownload;
+ }
+ else
+ {
+ m_responseCode = MHD_HTTP_NOT_FOUND;
+ m_responseType = HTTPError;
+ }
+ }
+ else
+ {
+ m_responseCode = MHD_HTTP_BAD_REQUEST;
+ m_responseType = HTTPError;
+ }
+
+ return MHD_YES;
+}
View
42 xbmc/network/httprequesthandler/HTTPImageHandler.h
@@ -0,0 +1,42 @@
+#pragma once
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IHTTPRequestHandler.h"
+
+#include "utils/StdString.h"
+
+class CHTTPImageHandler : public IHTTPRequestHandler
+{
+public:
+ CHTTPImageHandler() { };
+
+ virtual IHTTPRequestHandler* GetInstance() { return new CHTTPImageHandler(); }
+ virtual bool CheckHTTPRequest(const HTTPRequest &request);
+ virtual int HandleHTTPRequest(const HTTPRequest &request);
+
+ virtual std::string GetHTTPResponseFile() const { return m_path; }
+
+ virtual int GetPriority() const { return 2; }
+
+private:
+ CStdString m_path;
+};
View
3  xbmc/network/httprequesthandler/Makefile
@@ -1,4 +1,5 @@
SRCS=HTTPApiHandler.cpp \
+ HTTPImageHandler.cpp \
HTTPJsonRpcHandler.cpp \
HTTPVfsHandler.cpp \
HTTPWebinterfaceAddonsHandler.cpp \
@@ -8,4 +9,4 @@ SRCS=HTTPApiHandler.cpp \
LIB=httprequesthandlers.a
include ../../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
View
3  xbmc/pictures/PictureThumbLoader.cpp
@@ -71,8 +71,7 @@ bool CPictureThumbLoader::LoadItem(CFileItem* pItem)
if (!CVideoThumbLoader::FillThumb(*pItem))
{
CStdString thumbURL = CVideoThumbLoader::GetEmbeddedThumbURL(*pItem);
- CStdString cachedThumb = CTextureCache::Get().GetCachedImage(thumbURL);
- if (!cachedThumb.IsEmpty())
+ if (CTextureCache::Get().HasCachedImage(thumbURL))
{
thumb = thumbURL;
}
View
4 xbmc/video/VideoInfoTag.cpp
@@ -432,8 +432,8 @@ void CVideoInfoTag::Serialize(CVariant& value)
CVariant actor;
actor["name"] = m_cast[i].strName;
actor["role"] = m_cast[i].strRole;
- if (!m_cast[i].thumb.IsEmpty()) // TODO: json-rpc should use real URLs just like everywhere else
- actor["thumbnail"] = CTextureCache::Get().CheckAndCacheImage(m_cast[i].thumb);
+ if (!m_cast[i].thumb.IsEmpty())
+ actor["thumbnail"] = CTextureCache::GetWrappedImageURL(m_cast[i].thumb);
value["cast"].push_back(actor);
}
value["set"] = m_set;
Something went wrong with that request. Please try again.