Browse Source

fix: mpeg-ts playback with multi-byte characters (#2971)

* fix: mpeg-ts playback with multi-byte characters

* bump windows ffmpeg
main
Jason Dove 8 hours ago committed by GitHub
parent
commit
5ab81525a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/artifacts.yml
  2. 5
      CHANGELOG.md
  3. 22
      ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs
  4. 2
      ErsatzTV/Resources/Scripts/MpegTs/run.bat
  5. 2
      ErsatzTV/Resources/Scripts/MpegTs/run.sh

2
.github/workflows/artifacts.yml

@ -311,7 +311,7 @@ jobs:
uses: suisei-cn/actions-download-file@v1.3.0 uses: suisei-cn/actions-download-file@v1.3.0
id: downloadffmpeg id: downloadffmpeg
with: with:
url: "https://github.com/ErsatzTV/ErsatzTV-ffmpeg/releases/download/8.1.2/ffmpeg-n8.1.2-etv-gd3cc14b8-win64-gpl-8.1.zip" url: "https://github.com/ErsatzTV/ErsatzTV-ffmpeg/releases/download/8.1.2/ffmpeg-n8.1.2-etv-g668ee329-win64-gpl-8.1.zip"
target: ffmpeg/ target: ffmpeg/
- name: Package artifacts - name: Package artifacts

5
CHANGELOG.md

@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Fixed
- Fix regression from `v26.6.0` that broke `MPEG-TS` channels on Windows when the channel name or the ffmpeg path contains non-english characters (like `Télévision`)
- Affected channels would connect but never send any data
- `MPEG-TS (Legacy)` and channel preview were not affected
- Custom MPEG-TS scripts can now use the `ETV_CHANNEL_NAME`, `ETV_HLS_URL` and `ETV_FFMPEG_PATH` environment variables, which are not affected by this issue; the `{{ ChannelName }}`, `{{ HlsUrl }}` and `{{ FFmpegPath }}` template variables continue to work but remain affected
## [26.7.1] - 2026-07-31 ## [26.7.1] - 2026-07-31
### Changed ### Changed

22
ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs

@ -2,6 +2,7 @@ using System.Collections.Concurrent;
using System.IO.Abstractions; using System.IO.Abstractions;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using CliWrap; using CliWrap;
using CliWrap.Builders;
using ErsatzTV.Core; using ErsatzTV.Core;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg; using ErsatzTV.Core.FFmpeg;
@ -50,6 +51,11 @@ public class MpegTsScriptService(
scriptFolder = kvp.Key; scriptFolder = kvp.Key;
} }
// the values below are passed through the environment (which the OS delivers as utf-16)
// rather than templated into the script; cmd.exe decodes batch files using the console
// code page, and at 65001 it aborts entirely on any multi-byte character
string channelName = channel.Name.Replace("\"", string.Empty);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
string scriptInput = Path.Combine(scriptFolder, script.WindowsScript); string scriptInput = Path.Combine(scriptFolder, script.WindowsScript);
@ -64,7 +70,8 @@ public class MpegTsScriptService(
{ {
var fileName = $"{tempFilePool.GetNextTempFile(TempFileCategory.MpegTsScript)}.bat"; var fileName = $"{tempFilePool.GetNextTempFile(TempFileCategory.MpegTsScript)}.bat";
await File.WriteAllTextAsync(fileName, finalScript); await File.WriteAllTextAsync(fileName, finalScript);
return Cli.Wrap(fileName); return Cli.Wrap(fileName)
.WithEnvironmentVariables(WithScriptVariables(hlsUrl, channelName, ffmpegPath));
} }
} }
} }
@ -82,7 +89,9 @@ public class MpegTsScriptService(
{ {
string fileName = tempFilePool.GetNextTempFile(TempFileCategory.MpegTsScript); string fileName = tempFilePool.GetNextTempFile(TempFileCategory.MpegTsScript);
await File.WriteAllTextAsync(fileName, finalScript); await File.WriteAllTextAsync(fileName, finalScript);
return Cli.Wrap("bash").WithArguments([fileName]); return Cli.Wrap("bash")
.WithArguments([fileName])
.WithEnvironmentVariables(WithScriptVariables(hlsUrl, channelName, ffmpegPath));
} }
} }
} }
@ -90,6 +99,15 @@ public class MpegTsScriptService(
return []; return [];
} }
private static Action<EnvironmentVariablesBuilder> WithScriptVariables(
string hlsUrl,
string channelName,
string ffmpegPath) =>
builder => builder
.Set("ETV_HLS_URL", hlsUrl)
.Set("ETV_CHANNEL_NAME", channelName)
.Set("ETV_FFMPEG_PATH", ffmpegPath);
private async Task<Option<string>> GetTemplatedScript( private async Task<Option<string>> GetTemplatedScript(
string fileName, string fileName,
string hlsUrl, string hlsUrl,

2
ErsatzTV/Resources/Scripts/MpegTs/run.bat

@ -1,3 +1,3 @@
@echo off @echo off
"{{ FFmpegPath }}" -nostdin -threads 1 -hide_banner -loglevel error -nostats -fflags +genpts+discardcorrupt+igndts -readrate 1.0 -i "{{ HlsUrl }}" -map 0 -c copy -metadata service_provider="ErsatzTV" -metadata service_name="{{ ChannelName }}" -f mpegts pipe:1 "%ETV_FFMPEG_PATH%" -nostdin -threads 1 -hide_banner -loglevel error -nostats -fflags +genpts+discardcorrupt+igndts -readrate 1.0 -i "%ETV_HLS_URL%" -map 0 -c copy -metadata service_provider="ErsatzTV" -metadata service_name="%ETV_CHANNEL_NAME%" -f mpegts pipe:1

2
ErsatzTV/Resources/Scripts/MpegTs/run.sh

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
"{{ FFmpegPath }}" -nostdin -threads 1 -hide_banner -loglevel error -nostats -fflags +genpts+discardcorrupt+igndts -readrate 1.0 -i "{{ HlsUrl }}" -map 0 -c copy -metadata service_provider="ErsatzTV" -metadata service_name="{{ ChannelName }}" -f mpegts pipe:1 "$ETV_FFMPEG_PATH" -nostdin -threads 1 -hide_banner -loglevel error -nostats -fflags +genpts+discardcorrupt+igndts -readrate 1.0 -i "$ETV_HLS_URL" -map 0 -c copy -metadata service_provider="ErsatzTV" -metadata service_name="$ETV_CHANNEL_NAME" -f mpegts pipe:1

Loading…
Cancel
Save