diff --git a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs index 9e100ac27..d44ba4276 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs @@ -1,6 +1,6 @@ -using ErsatzTV.Core; +using ErsatzTV.Core; namespace ErsatzTV.Application.Streaming; -public record GetHlsPlaylistByChannelNumber(string Scheme, string Host, string ChannelNumber, string Mode) +public record GetHlsPlaylistByChannelNumber(string Scheme, string Host, string ChannelNumber, string Mode, string AccessToken) : IRequest>; diff --git a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs index 3bc675cb9..060dd8d04 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs @@ -1,4 +1,4 @@ -using ErsatzTV.Core; +using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.FFmpeg.OutputFormat; @@ -71,13 +71,17 @@ public class GetHlsPlaylistByChannelNumberHandler : long index = GetIndexForChannel(parameters.Channel, parameters.PlayoutItem); double timeRemaining = Math.Abs((parameters.PlayoutItem.FinishOffset - now).TotalSeconds); + string tokenQuery = string.IsNullOrWhiteSpace(request.AccessToken) + ? "" + : $"&access_token={request.AccessToken}"; + return $@"#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:{index} #EXT-X-DISCONTINUITY #EXTINF:{timeRemaining:F2}, -{request.Scheme}://{request.Host}/{endpoint}/{request.ChannelNumber}{extension}?index={index}{mode} +{request.Scheme}://{request.Host}/{endpoint}/{request.ChannelNumber}{extension}?index={index}{mode}{tokenQuery} "; } diff --git a/ErsatzTV/Controllers/IptvController.cs b/ErsatzTV/Controllers/IptvController.cs index 21bf3ec93..6c6776e16 100644 --- a/ErsatzTV/Controllers/IptvController.cs +++ b/ErsatzTV/Controllers/IptvController.cs @@ -262,7 +262,7 @@ public class IptvController : StreamingControllerBase Request.Scheme, Request.Host.ToString(), channelNumber, - mode)) + mode, Request.Query["access_token"])) .Map(r => r.Match( playlist => Content(playlist, "application/vnd.apple.mpegurl"), error => BadRequest(error.Value))); diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj index 68c9683da..2ca7e9b40 100644 --- a/ErsatzTV/ErsatzTV.csproj +++ b/ErsatzTV/ErsatzTV.csproj @@ -158,9 +158,7 @@ - - - + diff --git a/ErsatzTV/Properties/launchSettings.json b/ErsatzTV/Properties/launchSettings.json index 30157f5eb..2a6976a52 100644 --- a/ErsatzTV/Properties/launchSettings.json +++ b/ErsatzTV/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "profiles": { "ErsatzTV": { "commandName": "Project", @@ -7,7 +7,8 @@ "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", "ETV_STREAMING_PORT": "8409", - "ETV_UI_PORT": "8410" + "ETV_UI_PORT": "8410", + "JWT__ISSUERSIGNINGKEY": "qwertyuiopasdfghjklzxcvbnm123456" } } } diff --git a/README.md b/README.md index 215b3388b..3b2b4f0e2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ -# ErsatzTV +# ErsatzTV (Community Fork) -ErsatzTV lets you transform your media library into a personalized, live TV experience - complete with EPG, channel scheduling, and seamless streaming to all your devices. Rediscover your content, your way. +ErsatzTV lets you transform your media library into a personalized, live TV experience — complete with EPG, channel scheduling, and seamless streaming to all your devices. + +This repository is a **community-maintained fork** of the original ErsatzTV project, which is currently archived. + +It includes fixes and improvements to keep the project usable in modern setups. [![contact](https://img.shields.io/badge/contact_us-510b80?style=for-the-badge)](https://ersatztv.org/contact) [![features](https://img.shields.io/badge/vote_on_features-darkgreen?style=for-the-badge)](https://features.ersatztv.org/) @@ -8,14 +12,66 @@ ErsatzTV lets you transform your media library into a personalized, live TV expe ![epg-example](https://ersatztv.org/images/home/epg-example.png) -## How It Works +--- + +# Important Notice + +The original ErsatzTV repository has been **archived** and is no longer actively maintained. + +This fork exists to: + +- maintain compatibility with modern environments +- fix bugs affecting real-world deployments +- continue improving the project for the community + +All credit for the original work belongs to the ErsatzTV maintainers and contributors. + +--- + +# Fixes in this Fork + +### JWT + HLS Streaming Fix + +When JWT authentication is enabled (`JWT__ISSUERSIGNINGKEY`), HLS players request the playlist with an `access_token` query parameter. + +However, the original implementation generated segment URLs without propagating this token. + +Example before: +/iptv/hls-direct/1.ts?index=1 + + +This caused segment requests to fail with: + + +401 Unauthorized + + +Example after: + + +/iptv/hls-direct/1.ts?index=1&access_token=TOKEN + + +This change allows authenticated playback with IPTV and HLS players that do not support sending Authorization headers for segment requests. + +Tested successfully with: + +- IPTV Smarters +- HLS players +- JWT-protected IPTV streams + +--- + +# How It Works 1. **Install ErsatzTV**: Download and set up the server on your system. 2. **Add Your Media**: Connect your media libraries and collections. 3. **Create Channels**: Design and schedule your own live channels. 4. **Stream Anywhere**: Watch on any device with IPTV and EPG support. -## Key Features +--- + +# Key Features - **Custom channels**: Create and schedule your own live TV channels. - **IPTV & EPG**: Stream with IPTV and Electronic Program Guide support. @@ -24,11 +80,27 @@ ErsatzTV lets you transform your media library into a personalized, live TV expe - **Music & Subtitles**: Mix music videos and enjoy subtitle support. - **Open Source**: Free, open, and community-driven project. -## Documentation +--- + +# Documentation + +Documentation is available at: + +https://ersatztv.org/docs/ + +--- + +# Credits + +This project is inspired by: + +- https://github.com/DEFENDORe/pseudotv-plex +- https://github.com/vexorian/dizquetv + +--- -Documentation is available at [ersatztv.org](https://ersatztv.org/docs/). +# License -## License +This project is released under the **zlib license**. -This project is inspired by [pseudotv-plex](https://github.com/DEFENDORe/pseudotv) and -the [dizquetv](https://github.com/vexorian/dizquetv) fork and is released under the [zlib license](LICENSE). +See the [LICENSE](LICENSE) file for details. \ No newline at end of file