jellyfin/jellyfin-plugin-tvheadend

No channel logos and picons

Shadowghost opened this issue · 34 comments

I have a working tvheadend server which provides picons and channel logos (works fine over it's webUI and on Kodi) but Jellyfin doesn't show any of them on the webUI - episode images are displayed properly (should movie posters be scraped from an external source and be displayed?). I only tested on current nightly since I don't want to mess up my setup right now by downgrading.
Tell me what logs you need and I'll gladly provide them :)

We’re pretty sure this code doesn’t import the images because the original creator didn’t care to do so (I could be wrong).

This would need to be added in as an enhancement.

Actually it seems this is an issue that has been solved in a later version of the original plugin of Emby. As per this thread:

https://emby.media/community/index.php?/topic/55451-tvheadend-no-channel-icons-after-upgrades/

The problem stems from the fact TVheadend server does not return a MIME type when the icons are served locally (to the TVheadend server ) via the local file system, which is quite typical in TVheadend setups. Many other TVheadend clients (Kodi, Android apps, etc.) do not suffer from this issue because they have probably implemented a sort of hack, like the one the Emby programmers have implemented in later versions (that is, "stuffing" a MIME type just by looking at the request paths).

See this thread:

https://emby.media/community/index.php?/topic/20107-tvheadend-plugin-for-emby-beta-1/page-36#entry574403

Sorry, I stand corrected and I have trusted too much old information which, while sharing the same issue, has quite surely nothing to do with the Jellyfin case.

I've spent some time on the plugin code, I've built a version with some more logging and apparently the problem may be in the code from Jellyfin, not the plugin. The missing logo issue occurs when the TVheadend server is accessed using a named user with a password, a case for which there is already provision in the plugin, AND when accessing the TVheadend server without a username/password (i.e. anonymous) is not permitted. As soon as an anonymous access is again permitted on the TVheadend server (user and password set to '*'), the channels' icons are displayed correctly. Of course leaving the anonymous access active is not an ideal setup.

As far as I've understood, the GetChannelsAsync method in the TVheadend plugin correctly compiles the list of channels, including the URLs to their respective logos each having the correct username/password embedded. I have confirmed that using one of those URLs in a browser the TVheadend server returns the proper logo image. So, somewhere in the code of the main Jellyfin this username/password pair seems to get lost, thus anonymizing the URL issued to the TVheadend server, hence the "Unauthorized" answer it returns when the anonymous access to the service is not permitted.

Unfortunately I have no knowledge of the main Jellyfin code, so I am not able right now to fix the code. I apologize for the confusion stemming from my previous comment.

I have the same problem with the missing channel icons (using jellyfin + tvheadend), but even if the anonymous account is enabled in tvheadend. Have you done something specific with the anonymous account? BTW, this issue seems to be related to jellyfin/jellyfin#2063

Nope, I just enabled it to browse and view the channels on the Tvheadend server, nothing really special. Ah, yes, there is one thing that you should check: enabling the (p)icons cache on the Tvheadend server created a total mess with the icons, to the point that even the Kodi PVR extension went mad. Unfortunately it seems that some Tvheadend clients have a local cache by themselves, so if you are in doubt: disable the icon caching on the server side, and remove any (p)icon cached on the client side.

Edit: yes, as I wrote the issue seems to be in the main calling code, not in the extension.

Disabling the icon cache does unfortunately not help. However, the channel icon/picon settings in my configuration are completely untouched, i.e., I have not configured any channel icon or picon locally. Instead, the EPG is providing the channel icon data which is a link to the website of the EPG source. TVHeadend uses these http-Links without any problems, for both channel icons and EPG screenshots. I don't know whether TVHeadend forwards these links to jellyfin or whether it downloads the icons and then sends them to jellyfin. Any idea how it works?

I checked what tvheadend returns when using the json-API, both with cache enabled and disabled. The returned URL correctly shows the channel icon, even with a machine that has no authentication information for tvheadend. Thus, I assume that my configuration has another error. BTW, in the jellyfin log I get the error "Emby.Server.Implementations.HttpServer.HttpListenerHost: Error processing request. URL: "http://IP:PORT/Items/20f785dccdae7a66dfe57537e1b8063c/Images/Primary?maxWidth=720&tag=543b6ca4c9f21c87d81daf7a932499c0&quality=90"
System.UriFormatException: Invalid URI: The hostname could not be parsed."

I just started looking into the code, so maybe its nothing. But I noticed that in the TVHeadend plugin, there are two methods to get the icon Url: getChannelImageUrl(), which adds username+password to the URL when using TVHeadend image cache, and GetChannelImage(), which does not. If GetChannelImage() would use GetChannelImageUrl() instead of building the URL itself, the problem with the required anonymous access to TVHeadend may be gone?

Unfortunately, this does not fix my problem, since I have an anonymous account, but its still not working. I am currently fighting with the debug output. I get (with version 5.0.0) less output than it should (according to the code in master).

Hi, I have the same problem. Both internally and via proxy server settings from externally via a DynDNS address Jellyfin denies access to the channel Picons. Use the TVHeadend plugin with user plus password. On the server itself TVHeadend the picons are local on the server and are displayed correctly. What exactly is the problem? Should an anonymous user without password be created in TVHeadend? Here is the error message and the current settings of the server TVHeadend. With Proxy I have already deactivated the hook, also no success.

Thanks
img_060_jellyfin_error
img_059_jellyfin_error

Answer:
GEThttps://dynadresse.ddnss.com:Port/Items/2c460aa4f732e9da406c51edfc8cf2d0/Images/Primary?maxWidth=480&tag=543b6ca4c9f21c87d81daf7a932499c0&quality=90
[HTTP/1.1 500 Internal Server Error 38ms]

Error processing request

I have the same problem in v10.7.0 RC2. The logfile says this:

[2021-01-03 12:25:32.649 +01:00] [ERR] Error processing request. URL "GET" "/Items/afc050d9852b7308dce063fd3e0c3a16/Images/Primary".
System.NullReferenceException: Object reference not set to an instance of an object.
   at MediaBrowser.Providers.Manager.ProviderManager.SaveImage(BaseItem item, String url, ImageType type, Nullable`1 imageIndex, CancellationToken cancellationToken)
   at Emby.Server.Implementations.Library.LibraryManager.ConvertImageToLocal(BaseItem item, ItemImageInfo image, Int32 imageIndex)
   at Jellyfin.Api.Controllers.ImageController.GetImageResult(BaseItem item, Guid itemId, Nullable`1 index, Nullable`1 height, Nullable`1 maxHeight, Nullable`1 maxWidth, Nullable`1 quality, Nullable`1 width, Nullable`1 addPlayedIndicator, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 blur, String backgroundColor, String foregroundLayer, ItemImageInfo imageInfo, Boolean cropWhitespace, IReadOnlyCollection`1 supportedFormats, Nullable`1 cacheDuration, IDictionary`2 headers, Boolean isHeadRequest)
   at Jellyfin.Api.Controllers.ImageController.GetImageInternal(Guid itemId, ImageType imageType, Nullable`1 imageIndex, String tag, Nullable`1 format, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 width, Nullable`1 height, Nullable`1 quality, Nullable`1 cropWhitespace, Nullable`1 addPlayedIndicator, Nullable`1 blur, String backgroundColor, String foregroundLayer, BaseItem item, Boolean isHeadRequest, ItemImageInfo imageInfo)
   at Jellyfin.Api.Controllers.ImageController.GetItemImage(Guid itemId, ImageType imageType, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 width, Nullable`1 height, Nullable`1 quality, String tag, Nullable`1 cropWhitespace, Nullable`1 format, Nullable`1 addPlayedIndicator, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 blur, String backgroundColor, String foregroundLayer, Nullable`1 imageIndex)
   at lambda_method823(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Jellyfin.Server.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
   at Jellyfin.Server.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
   at Jellyfin.Server.Middleware.IpBasedAccessValidationMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
   at Jellyfin.Server.Middleware.LanFilteringMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.ReDoc.ReDocMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Server.Middleware.RobotsRedirectionMiddleware.Invoke(HttpContext httpContext)
   at Jellyfin.Server.Middleware.LegacyEmbyRouteRewriteMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
   at Jellyfin.Server.Middleware.ResponseTimeMiddleware.Invoke(HttpContext context)
   at Jellyfin.Server.Middleware.ExceptionMiddleware.Invoke(HttpContext context)

I re-installed the picons in TVHeadend, but they still do not show up. Different log file output though:

[2021-01-03 17:05:27.509 +01:00] [WRN] Slow HTTP Response from "http://192.168.0.192:8096/Items/b5e1a12fdd16f5b5559b347c4c8b7b2b/Images/Primary?maxHeight=220&tag=543b6ca4c9f21c87d81daf7a932499c0&quality=90" to "192.168.0.24" in 0:00:01.1598262 with Status Code 500
[2021-01-03 17:05:27.843 +01:00] [ERR] Error processing request. URL "GET" "/Items/874ad3677d9783f4b349c1d0ec1454c5/Images/Primary".
System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at Emby.Server.Implementations.Library.LibraryManager.ConvertImageToLocal(BaseItem item, ItemImageInfo image, Int32 imageIndex)
   at Jellyfin.Api.Controllers.ImageController.GetImageResult(BaseItem item, Guid itemId, Nullable`1 index, Nullable`1 height, Nullable`1 maxHeight, Nullable`1 maxWidth, Nullable`1 quality, Nullable`1 width, Nullable`1 addPlayedIndicator, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 blur, String backgroundColor, String foregroundLayer, ItemImageInfo imageInfo, Boolean cropWhitespace, IReadOnlyCollection`1 supportedFormats, Nullable`1 cacheDuration, IDictionary`2 headers, Boolean isHeadRequest)
   at Jellyfin.Api.Controllers.ImageController.GetImageInternal(Guid itemId, ImageType imageType, Nullable`1 imageIndex, String tag, Nullable`1 format, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 width, Nullable`1 height, Nullable`1 quality, Nullable`1 cropWhitespace, Nullable`1 addPlayedIndicator, Nullable`1 blur, String backgroundColor, String foregroundLayer, BaseItem item, Boolean isHeadRequest, ItemImageInfo imageInfo)
   at Jellyfin.Api.Controllers.ImageController.GetItemImage(Guid itemId, ImageType imageType, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 width, Nullable`1 height, Nullable`1 quality, String tag, Nullable`1 cropWhitespace, Nullable`1 format, Nullable`1 addPlayedIndicator, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 blur, String backgroundColor, String foregroundLayer, Nullable`1 imageIndex)
   at lambda_method933(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Jellyfin.Server.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
   at Jellyfin.Server.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)```

The picons once worked. I've recently reset my database and they are not loaded again. For picons to work I needed make a wildcard user (username="*"), which has access to the web interface. This workaround doesn't seem to work anymore.

Oh, I also remember a bug that tvheadend (sometimes?) doesn't mark the images as actual images, meaning they have no file extension and also no mime type.

I have the same problem. I use the jellyfin and also tvheadend via a docker container. Attached send in some information about the container:

IP range: 192.168.0.0/24
Jellyfin version: 10.7.6
TVHeadEnd version: 4.3-1975

For example, Jellyfin tries to open this URL to open the logo of the channel Eurosport:
http://192.168.0.13:8096/Items/78c5915a076c9957967a6dfe7c6e9cea/Images/Primary?maxWidth=3840&tag=543b6ca4c9f21c87d81daf7a932499c0&quality=90

I have already created a user *, however this did not lead to success.

Under TVHeadEnd I also disabled the icon cache, this also did not lead to success.

In TVHeadEnd the icon is entered as follows:
file:///picons/eurosport1.png

Just got my tvheadend setup with Jellfin and have stumbled on to this issue as well. Icons show in Kodi and in the TVHeadEnd web gui, just not in Jellyfin.

I'm running 10.7.6 (should contain the fix) and the issue is still there for me.

10.7.6 does not contain the fix.

I just changed my Docker container from linuxserver/jellyfin:latest (v10.7.6) to linuxserver/jellyfin:nightly (v10.8.0) and I don't see the channel logos there either. I think in this version the patch should be applied. Or not?

The fix should be there, did you do a full live tv refresh after upgrading?

Yes, I have performed a full Live TV refresh. Attached are a few Screenshots.

Screenshot_2021-09-03-15-08-53-482_org.jellyfin.mobile.jpg
Screenshot_2021-09-03-15-09-15-602_org.jellyfin.mobile.jpg
Screenshot_2021-09-03-15-09-28-796_org.jellyfin.mobile.jpg
Screenshot_2021-09-03-15-11-41-855_org.jellyfin.mobile.jpg

it might be related to jellyfin/jellyfin#2548

I just tested it on master. Browser console throws 500 (Internal Server Error).
It seems like we still have MIME type errors according to the Jellyfin logs:

Sep 03 18:27:08 GhostBox jellyfin[21082]: [18:27:08] [ERR] Error processing request. URL GET /Items/be5d88e573f061aa8a881d2396c69e80/Images/Primary.
Sep 03 18:27:08 GhostBox jellyfin[21082]: System.Net.Http.HttpRequestException: Invalid image received.
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at MediaBrowser.Providers.Manager.ProviderManager.SaveImage(BaseItem item, String url, ImageType type, Nullable`1 imageIndex, CancellationToken cancellationToken)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Emby.Server.Implementations.Library.LibraryManager.ConvertImageToLocal(BaseItem item, ItemImageInfo image, Int32 imageIndex)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Api.Controllers.ImageController.GetImageResult(BaseItem item, Guid itemId, Nullable`1 index, Nullable`1 width, Nullable`1 height, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 fillWidth, Nullable`1 fillHeight, Nullable`1 quality, Nullable`1 addPlayedIndicator, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 blur, String backgroundColor, String foregroundLayer, ItemImageInfo imageInfo, IReadOnlyCollection`1 supportedFormats, Nullable`1 cacheDuration, IDictionary`2 headers, Boolean isHeadRequest)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Api.Controllers.ImageController.GetImageInternal(Guid itemId, ImageType imageType, Nullable`1 imageIndex, String tag, Nullable`1 format, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 width, Nullable`1 height, Nullable`1 quality, Nullable`1 fillWidth, Nullable`1 fillHeight, Nullable`1 addPlayedIndicator, Nullable`1 blur, String backgroundColor, String foregroundLayer, BaseItem item, Boolean isHeadRequest, ItemImageInfo imageInfo)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Api.Controllers.ImageController.GetItemImage(Guid itemId, ImageType imageType, Nullable`1 maxWidth, Nullable`1 maxHeight, Nullable`1 width, Nullable`1 height, Nullable`1 quality, Nullable`1 fillWidth, Nullable`1 fillHeight, String tag, Nullable`1 cropWhitespace, Nullable`1 format, Nullable`1 addPlayedIndicator, Nullable`1 percentPlayed, Nullable`1 unplayedCount, Nullable`1 blur, String backgroundColor, String foregroundLayer, Nullable`1 imageIndex)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at lambda_method693(Closure , Object )
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.IpBasedAccessValidationMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.LanFilteringMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.QueryStringDecodingMiddleware.Invoke(HttpContext httpContext)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Swashbuckle.AspNetCore.ReDoc.ReDocMiddleware.Invoke(HttpContext httpContext)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.RobotsRedirectionMiddleware.Invoke(HttpContext httpContext)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.LegacyEmbyRouteRewriteMiddleware.Invoke(HttpContext httpContext)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.ResponseTimeMiddleware.Invoke(HttpContext context)
Sep 03 18:27:08 GhostBox jellyfin[21082]:    at Jellyfin.Server.Middleware.ExceptionMiddleware.Invoke(HttpContext context)

Like I already wrote a couple of months ago, the issue is that tvheadend doesn't respond with any MIME type. This issue already came up with emby years ago. Back then I implemented a quite hacky workaround, which tried to determine the MIME type based on the file header in cases where no type was given. It worked though. Sadly, this PR never made it in, since emby devs didn't accept any third-party PRs anymore, because of their "policy change" regarding open-source.

Anyways, I think jellyfin is expecting an image here, but is simply receiving a generic data object without MIME type, which causes the "invalid image received" exception. Secondly, the image URLs given by the tvheadend API do not contain any file ending, which also excludes this approach from determining the type.

OK so this should really be solved in TVHeadend. If it would set a MIME type correctly then Jellyfin would show the icons correctly. Right?

Can someone point me to what call exactly is made to TVHeadend to retrieve the icons? I looked in the code briefly but it's far from clear to me. Alternatively, is there a way to show the calls to TVHeadend in the logfiles?

Ulrar commented

Looking at this myself I'm seeing something different : It looks like jellyfin is querying the wrong URLs.
I've created a user with no password (restricted to jellyfin's IP), and confirmed that requests from jellyfin with no authentication can complete. I've also disabled the image cache.
I've also confirmed that what the json API is returning is valid. For example : "icon_public_url":"imagecache/46", and that works fine in browser.

But then for some reason jellyfin requests are not to these IDs, I can see tvheadend returning 404 errors on these :
2021-10-05 17:18:18.763 http: 172.17.0.7: HTTP/1.1 GET (1) /imagecache/26596 -- 404

No idea where that 26596 comes from, that does not appear at all in the tvheadend api's json.
How do you figure out what jellyfin is storing, which of the db files keeps the image URL ?

I wonder if anyone already has a solution or workaround on this problem.
I came from a Plex setup where the connectivity with TvHeadend (using tvhProxy) was a nightmare!
Meanwhile I found that Jellyfin with this plugin works like a charm.
But the lack of channel logos remain for me unsolved what is a pity!
Any help?
Thanks

Ulrar commented

That's subjective, I can't get mine to work without nightly freezes, and the inability to disable hardware transcoding for live tv makes a lot of the SD channel unwatchable on my instance, sadly.

But to answer the question then no, my work around before I gave up on this plugin was to manually download all the icons and add them one by one to the channels in jellyfin, tedious but works.

Thank you @Ulrar for your rapid answer!
But when you say "before I gave up on this plugin" you mean you also gave up of using TvHeadend with Jellyfin or you adopt another solution?
I presume using back Plex is also a dead end, right?

Ulrar commented

I just don't have my TV channels in Jellyfin anymore. There's some kind of issue that makes MP2 streams not transcode properly on Comet Lake CPUs, which isn't jellyfin's fault but I do wish there was a way to disable hardware transcoding for these.
On top of that it would regularly freeze during the nightly guide refresh, getting stuck indefinitely around 80%. The big issue is as long as the refresh is running, the LiveTV row on the frontpage wouldn't load, which would block loading of the following rows making the UI unusable. And cancelling the refresh wouldn't work, I had to restart jellyfin almost every day to clear it.

Anyway I gave up on that plugin and I just installed Kodi on everyone's TV / Tablet / Whatever, using the jellyfin plugin for movies and shows and the tvh PVR plugin for live TV, works perfectly.

That said if it's working for you then great :). You can just take an hour and upload the icons manually and you'll be set.

My current setup use TvHeadend with Kodi clients!
The problem with that (and that I was trying to solve using Plex or Jellyfin) is:

  • I can not easily transcode the streams (specially if I want to do it using hardware)
  • there are no Kodi clients for IOS (unless the device is jailbroken)

But to be honest my tests with Jellyfin are very preliminary.
My initial reaction was positive but I need to put the system working for a longer period to see if the freezes you describe occur.
By the way in my setup I am running Jellyfin in a Docker container running inside a Proxmox VM.
And my TvHeadend is streaming DVB-S2 channels from a TBS6909 card.

Ulrar commented

Ah, I don't have any Apple stuff so I had no idea Kodi wasn't available, that's a shame.
Yeah I use Kodi to avoid the hardware transcoding myself, but fair enough if it's working for you I can see why you'd want it, I do use it for everything else.

My DVB-S channels are fine, I only have issues with my low def DVB-T channels so hopefully you'll be fine ! I'm guessing my guide refresh issues either come from the huge size of it or maybe some conflict in the refresh times, to be honest the other issues already had me put off the plugin a bit so I didn't look into it much, good luck !

I also had this issue, but finally have a workaround:
My setup: Jellyifin in docker with private network, set the ip manually . tvhadend in docker with network_mode: "host" because of the sat-ip server.
tvheadend have a user/password for jellyfin and also have a passwordless anomymous user (*)

My solution:
In tvheadend I enabled the jellyfin private ip for the anonymous user
In jellyfin tvheadend plugin deleted the user/password fields.

After restarting the jellyfin, livetv disappeared from the main screen, but all of the channel logos was synchronized. I wrote back the jellyfin user/password, restarted again and now channel logos are there and livetv works.

Maybe enabling the jellyfin ip for the anonymous user at tvheadend simple do the trick also.

So for me jellyfin kept saying in the logs that it needed a username (tho the gui didn't show a warning when i removed it)

Think your right, creating a anonymous user with its IP set to jellyfin allowed the icons to pull down, i also have icon cache disable on the tvheadend, but not sure it that helped or not

Same problem.
I created the * user and gave it access to the Web Interface (so it can access the picons over HTTP) and it seems to have fixed the problem.
Thanks for the * user clue folks!