diff --git a/.github/workflows/repo-stale.yaml b/.github/workflows/repo-stale.yaml
index 897b7014ac..7f6fcffed5 100644
--- a/.github/workflows/repo-stale.yaml
+++ b/.github/workflows/repo-stale.yaml
@@ -19,6 +19,7 @@ jobs:
days-before-pr-stale: -1
days-before-close: 21
days-before-pr-close: -1
+ operations-per-run: 75
exempt-issue-labels: regression,security,roadmap,future,feature,enhancement,confirmed
stale-issue-label: stale
stale-issue-message: |-
diff --git a/DvdLib/BigEndianBinaryReader.cs b/DvdLib/BigEndianBinaryReader.cs
deleted file mode 100644
index b3aad85cec..0000000000
--- a/DvdLib/BigEndianBinaryReader.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma warning disable CS1591
-
-using System.Buffers.Binary;
-using System.IO;
-
-namespace DvdLib
-{
- public class BigEndianBinaryReader : BinaryReader
- {
- public BigEndianBinaryReader(Stream input)
- : base(input)
- {
- }
-
- public override ushort ReadUInt16()
- {
- return BinaryPrimitives.ReadUInt16BigEndian(base.ReadBytes(2));
- }
-
- public override uint ReadUInt32()
- {
- return BinaryPrimitives.ReadUInt32BigEndian(base.ReadBytes(4));
- }
- }
-}
diff --git a/DvdLib/DvdLib.csproj b/DvdLib/DvdLib.csproj
deleted file mode 100644
index 1053c0089f..0000000000
--- a/DvdLib/DvdLib.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- {713F42B5-878E-499D-A878-E4C652B1D5E8}
-
-
-
-
-
-
-
- net7.0
- false
- true
- AllDisabledByDefault
- disable
-
-
-
diff --git a/DvdLib/Ifo/Cell.cs b/DvdLib/Ifo/Cell.cs
deleted file mode 100644
index ea0b50e430..0000000000
--- a/DvdLib/Ifo/Cell.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma warning disable CS1591
-
-using System.IO;
-
-namespace DvdLib.Ifo
-{
- public class Cell
- {
- public CellPlaybackInfo PlaybackInfo { get; private set; }
-
- public CellPositionInfo PositionInfo { get; private set; }
-
- internal void ParsePlayback(BinaryReader br)
- {
- PlaybackInfo = new CellPlaybackInfo(br);
- }
-
- internal void ParsePosition(BinaryReader br)
- {
- PositionInfo = new CellPositionInfo(br);
- }
- }
-}
diff --git a/DvdLib/Ifo/CellPlaybackInfo.cs b/DvdLib/Ifo/CellPlaybackInfo.cs
deleted file mode 100644
index 6e33a0ec5a..0000000000
--- a/DvdLib/Ifo/CellPlaybackInfo.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma warning disable CS1591
-
-using System.IO;
-
-namespace DvdLib.Ifo
-{
- public enum BlockMode
- {
- NotInBlock = 0,
- FirstCell = 1,
- InBlock = 2,
- LastCell = 3,
- }
-
- public enum BlockType
- {
- Normal = 0,
- Angle = 1,
- }
-
- public enum PlaybackMode
- {
- Normal = 0,
- StillAfterEachVOBU = 1,
- }
-
- public class CellPlaybackInfo
- {
- public readonly BlockMode Mode;
- public readonly BlockType Type;
- public readonly bool SeamlessPlay;
- public readonly bool Interleaved;
- public readonly bool STCDiscontinuity;
- public readonly bool SeamlessAngle;
- public readonly PlaybackMode PlaybackMode;
- public readonly bool Restricted;
- public readonly byte StillTime;
- public readonly byte CommandNumber;
- public readonly DvdTime PlaybackTime;
- public readonly uint FirstSector;
- public readonly uint FirstILVUEndSector;
- public readonly uint LastVOBUStartSector;
- public readonly uint LastSector;
-
- internal CellPlaybackInfo(BinaryReader br)
- {
- br.BaseStream.Seek(0x4, SeekOrigin.Current);
- PlaybackTime = new DvdTime(br.ReadBytes(4));
- br.BaseStream.Seek(0x10, SeekOrigin.Current);
- }
- }
-}
diff --git a/DvdLib/Ifo/CellPositionInfo.cs b/DvdLib/Ifo/CellPositionInfo.cs
deleted file mode 100644
index 216aa0f77a..0000000000
--- a/DvdLib/Ifo/CellPositionInfo.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma warning disable CS1591
-
-using System.IO;
-
-namespace DvdLib.Ifo
-{
- public class CellPositionInfo
- {
- public readonly ushort VOBId;
- public readonly byte CellId;
-
- internal CellPositionInfo(BinaryReader br)
- {
- VOBId = br.ReadUInt16();
- br.ReadByte();
- CellId = br.ReadByte();
- }
- }
-}
diff --git a/DvdLib/Ifo/Chapter.cs b/DvdLib/Ifo/Chapter.cs
deleted file mode 100644
index e786cb5536..0000000000
--- a/DvdLib/Ifo/Chapter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma warning disable CS1591
-
-namespace DvdLib.Ifo
-{
- public class Chapter
- {
- public ushort ProgramChainNumber { get; private set; }
-
- public ushort ProgramNumber { get; private set; }
-
- public uint ChapterNumber { get; private set; }
-
- public Chapter(ushort pgcNum, ushort programNum, uint chapterNum)
- {
- ProgramChainNumber = pgcNum;
- ProgramNumber = programNum;
- ChapterNumber = chapterNum;
- }
- }
-}
diff --git a/DvdLib/Ifo/Dvd.cs b/DvdLib/Ifo/Dvd.cs
deleted file mode 100644
index 7f8ece47dc..0000000000
--- a/DvdLib/Ifo/Dvd.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-
-namespace DvdLib.Ifo
-{
- public class Dvd
- {
- private readonly ushort _titleSetCount;
- public readonly List
Titles;
-
- private ushort _titleCount;
- public readonly Dictionary VTSPaths = new Dictionary();
- public Dvd(string path)
- {
- Titles = new List();
- var allFiles = new DirectoryInfo(path).GetFiles(path, SearchOption.AllDirectories);
-
- var vmgPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.IFO", StringComparison.OrdinalIgnoreCase)) ??
- allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.BUP", StringComparison.OrdinalIgnoreCase));
-
- if (vmgPath == null)
- {
- foreach (var ifo in allFiles)
- {
- if (!string.Equals(ifo.Extension, ".ifo", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- var nums = ifo.Name.Split('_', StringSplitOptions.RemoveEmptyEntries);
- if (nums.Length >= 2 && ushort.TryParse(nums[1], out var ifoNumber))
- {
- ReadVTS(ifoNumber, ifo.FullName);
- }
- }
- }
- else
- {
- using (var vmgFs = new FileStream(vmgPath.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- using (var vmgRead = new BigEndianBinaryReader(vmgFs))
- {
- vmgFs.Seek(0x3E, SeekOrigin.Begin);
- _titleSetCount = vmgRead.ReadUInt16();
-
- // read address of TT_SRPT
- vmgFs.Seek(0xC4, SeekOrigin.Begin);
- uint ttSectorPtr = vmgRead.ReadUInt32();
- vmgFs.Seek(ttSectorPtr * 2048, SeekOrigin.Begin);
- ReadTT_SRPT(vmgRead);
- }
- }
-
- for (ushort titleSetNum = 1; titleSetNum <= _titleSetCount; titleSetNum++)
- {
- ReadVTS(titleSetNum, allFiles);
- }
- }
- }
-
- private void ReadTT_SRPT(BinaryReader read)
- {
- _titleCount = read.ReadUInt16();
- read.BaseStream.Seek(6, SeekOrigin.Current);
- for (uint titleNum = 1; titleNum <= _titleCount; titleNum++)
- {
- var t = new Title(titleNum);
- t.ParseTT_SRPT(read);
- Titles.Add(t);
- }
- }
-
- private void ReadVTS(ushort vtsNum, IReadOnlyList allFiles)
- {
- var filename = string.Format(CultureInfo.InvariantCulture, "VTS_{0:00}_0.IFO", vtsNum);
-
- var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ??
- allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase));
-
- if (vtsPath == null)
- {
- throw new FileNotFoundException("Unable to find VTS IFO file");
- }
-
- ReadVTS(vtsNum, vtsPath.FullName);
- }
-
- private void ReadVTS(ushort vtsNum, string vtsPath)
- {
- VTSPaths[vtsNum] = vtsPath;
-
- using (var vtsFs = new FileStream(vtsPath, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- using (var vtsRead = new BigEndianBinaryReader(vtsFs))
- {
- // Read VTS_PTT_SRPT
- vtsFs.Seek(0xC8, SeekOrigin.Begin);
- uint vtsPttSrptSecPtr = vtsRead.ReadUInt32();
- uint baseAddr = (vtsPttSrptSecPtr * 2048);
- vtsFs.Seek(baseAddr, SeekOrigin.Begin);
-
- ushort numTitles = vtsRead.ReadUInt16();
- vtsRead.ReadUInt16();
- uint endaddr = vtsRead.ReadUInt32();
- uint[] offsets = new uint[numTitles];
- for (ushort titleNum = 0; titleNum < numTitles; titleNum++)
- {
- offsets[titleNum] = vtsRead.ReadUInt32();
- }
-
- for (uint titleNum = 0; titleNum < numTitles; titleNum++)
- {
- uint chapNum = 1;
- vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);
- var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));
- if (t == null)
- {
- continue;
- }
-
- do
- {
- t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum));
- if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1]))
- {
- break;
- }
-
- chapNum++;
- }
- while (vtsFs.Position < (baseAddr + endaddr));
- }
-
- // Read VTS_PGCI
- vtsFs.Seek(0xCC, SeekOrigin.Begin);
- uint vtsPgciSecPtr = vtsRead.ReadUInt32();
- vtsFs.Seek(vtsPgciSecPtr * 2048, SeekOrigin.Begin);
-
- long startByte = vtsFs.Position;
-
- ushort numPgcs = vtsRead.ReadUInt16();
- vtsFs.Seek(6, SeekOrigin.Current);
- for (ushort pgcNum = 1; pgcNum <= numPgcs; pgcNum++)
- {
- byte pgcCat = vtsRead.ReadByte();
- bool entryPgc = (pgcCat & 0x80) != 0;
- uint titleNum = (uint)(pgcCat & 0x7F);
-
- vtsFs.Seek(3, SeekOrigin.Current);
- uint vtsPgcOffset = vtsRead.ReadUInt32();
-
- var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));
- if (t != null)
- {
- t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);
- }
- }
- }
- }
- }
- }
-}
diff --git a/DvdLib/Ifo/DvdTime.cs b/DvdLib/Ifo/DvdTime.cs
deleted file mode 100644
index d231406106..0000000000
--- a/DvdLib/Ifo/DvdTime.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-
-namespace DvdLib.Ifo
-{
- public class DvdTime
- {
- public readonly byte Hour, Minute, Second, Frames, FrameRate;
-
- public DvdTime(byte[] data)
- {
- Hour = GetBCDValue(data[0]);
- Minute = GetBCDValue(data[1]);
- Second = GetBCDValue(data[2]);
- Frames = GetBCDValue((byte)(data[3] & 0x3F));
-
- if ((data[3] & 0x80) != 0)
- {
- FrameRate = 30;
- }
- else if ((data[3] & 0x40) != 0)
- {
- FrameRate = 25;
- }
- }
-
- private static byte GetBCDValue(byte data)
- {
- return (byte)((((data & 0xF0) >> 4) * 10) + (data & 0x0F));
- }
-
- public static explicit operator TimeSpan(DvdTime time)
- {
- int ms = (int)(((1.0 / (double)time.FrameRate) * time.Frames) * 1000.0);
- return new TimeSpan(0, time.Hour, time.Minute, time.Second, ms);
- }
- }
-}
diff --git a/DvdLib/Ifo/Program.cs b/DvdLib/Ifo/Program.cs
deleted file mode 100644
index 3d94fa7dc1..0000000000
--- a/DvdLib/Ifo/Program.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma warning disable CS1591
-
-using System.Collections.Generic;
-
-namespace DvdLib.Ifo
-{
- public class Program
- {
- public IReadOnlyList Cells { get; }
-
- public Program(List cells)
- {
- Cells = cells;
- }
- }
-}
diff --git a/DvdLib/Ifo/ProgramChain.cs b/DvdLib/Ifo/ProgramChain.cs
deleted file mode 100644
index 83c0051b90..0000000000
--- a/DvdLib/Ifo/ProgramChain.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-#pragma warning disable CS1591
-
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace DvdLib.Ifo
-{
- public enum ProgramPlaybackMode
- {
- Sequential,
- Random,
- Shuffle
- }
-
- public class ProgramChain
- {
- private byte _programCount;
- public readonly List Programs;
-
- private byte _cellCount;
- public readonly List Cells;
-
- public DvdTime PlaybackTime { get; private set; }
-
- public UserOperation ProhibitedUserOperations { get; private set; }
-
- public byte[] AudioStreamControl { get; private set; } // 8*2 entries
- public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries
-
- private ushort _nextProgramNumber;
-
- private ushort _prevProgramNumber;
-
- private ushort _goupProgramNumber;
-
- public ProgramPlaybackMode PlaybackMode { get; private set; }
-
- public uint ProgramCount { get; private set; }
-
- public byte StillTime { get; private set; }
-
- public byte[] Palette { get; private set; } // 16*4 entries
-
- private ushort _commandTableOffset;
-
- private ushort _programMapOffset;
- private ushort _cellPlaybackOffset;
- private ushort _cellPositionOffset;
-
- public readonly uint VideoTitleSetIndex;
-
- internal ProgramChain(uint vtsPgcNum)
- {
- VideoTitleSetIndex = vtsPgcNum;
- Cells = new List();
- Programs = new List();
- }
-
- internal void ParseHeader(BinaryReader br)
- {
- long startPos = br.BaseStream.Position;
-
- br.ReadUInt16();
- _programCount = br.ReadByte();
- _cellCount = br.ReadByte();
- PlaybackTime = new DvdTime(br.ReadBytes(4));
- ProhibitedUserOperations = (UserOperation)br.ReadUInt32();
- AudioStreamControl = br.ReadBytes(16);
- SubpictureStreamControl = br.ReadBytes(128);
-
- _nextProgramNumber = br.ReadUInt16();
- _prevProgramNumber = br.ReadUInt16();
- _goupProgramNumber = br.ReadUInt16();
-
- StillTime = br.ReadByte();
- byte pbMode = br.ReadByte();
- if (pbMode == 0)
- {
- PlaybackMode = ProgramPlaybackMode.Sequential;
- }
- else
- {
- PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle;
- }
-
- ProgramCount = (uint)(pbMode & 0x7F);
-
- Palette = br.ReadBytes(64);
- _commandTableOffset = br.ReadUInt16();
- _programMapOffset = br.ReadUInt16();
- _cellPlaybackOffset = br.ReadUInt16();
- _cellPositionOffset = br.ReadUInt16();
-
- // read position info
- br.BaseStream.Seek(startPos + _cellPositionOffset, SeekOrigin.Begin);
- for (int cellNum = 0; cellNum < _cellCount; cellNum++)
- {
- var c = new Cell();
- c.ParsePosition(br);
- Cells.Add(c);
- }
-
- br.BaseStream.Seek(startPos + _cellPlaybackOffset, SeekOrigin.Begin);
- for (int cellNum = 0; cellNum < _cellCount; cellNum++)
- {
- Cells[cellNum].ParsePlayback(br);
- }
-
- br.BaseStream.Seek(startPos + _programMapOffset, SeekOrigin.Begin);
- var cellNumbers = new List();
- for (int progNum = 0; progNum < _programCount; progNum++) cellNumbers.Add(br.ReadByte() - 1);
-
- for (int i = 0; i < cellNumbers.Count; i++)
- {
- int max = (i + 1 == cellNumbers.Count) ? _cellCount : cellNumbers[i + 1];
- Programs.Add(new Program(Cells.Where((c, idx) => idx >= cellNumbers[i] && idx < max).ToList()));
- }
- }
- }
-}
diff --git a/DvdLib/Ifo/Title.cs b/DvdLib/Ifo/Title.cs
deleted file mode 100644
index 29a0b95c72..0000000000
--- a/DvdLib/Ifo/Title.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-#pragma warning disable CS1591
-
-using System.Collections.Generic;
-using System.IO;
-
-namespace DvdLib.Ifo
-{
- public class Title
- {
- public uint TitleNumber { get; private set; }
-
- public uint AngleCount { get; private set; }
-
- public ushort ChapterCount { get; private set; }
-
- public byte VideoTitleSetNumber { get; private set; }
-
- private ushort _parentalManagementMask;
- private byte _titleNumberInVTS;
- private uint _vtsStartSector; // relative to start of entire disk
-
- public ProgramChain EntryProgramChain { get; private set; }
-
- public readonly List ProgramChains;
-
- public readonly List Chapters;
-
- public Title(uint titleNum)
- {
- ProgramChains = new List();
- Chapters = new List();
- Chapters = new List();
- TitleNumber = titleNum;
- }
-
- public bool IsVTSTitle(uint vtsNum, uint vtsTitleNum)
- {
- return (vtsNum == VideoTitleSetNumber && vtsTitleNum == _titleNumberInVTS);
- }
-
- internal void ParseTT_SRPT(BinaryReader br)
- {
- byte titleType = br.ReadByte();
- // TODO parse Title Type
-
- AngleCount = br.ReadByte();
- ChapterCount = br.ReadUInt16();
- _parentalManagementMask = br.ReadUInt16();
- VideoTitleSetNumber = br.ReadByte();
- _titleNumberInVTS = br.ReadByte();
- _vtsStartSector = br.ReadUInt32();
- }
-
- internal void AddPgc(BinaryReader br, long startByte, bool entryPgc, uint pgcNum)
- {
- long curPos = br.BaseStream.Position;
- br.BaseStream.Seek(startByte, SeekOrigin.Begin);
-
- var pgc = new ProgramChain(pgcNum);
- pgc.ParseHeader(br);
- ProgramChains.Add(pgc);
- if (entryPgc)
- {
- EntryProgramChain = pgc;
- }
-
- br.BaseStream.Seek(curPos, SeekOrigin.Begin);
- }
- }
-}
diff --git a/DvdLib/Ifo/UserOperation.cs b/DvdLib/Ifo/UserOperation.cs
deleted file mode 100644
index 5d111ebc06..0000000000
--- a/DvdLib/Ifo/UserOperation.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-
-namespace DvdLib.Ifo
-{
- [Flags]
- public enum UserOperation
- {
- None = 0,
- TitleOrTimePlay = 1,
- ChapterSearchOrPlay = 2,
- TitlePlay = 4,
- Stop = 8,
- GoUp = 16,
- TimeOrChapterSearch = 32,
- PrevOrTopProgramSearch = 64,
- NextProgramSearch = 128,
- ForwardScan = 256,
- BackwardScan = 512,
- TitleMenuCall = 1024,
- RootMenuCall = 2048,
- SubpictureMenuCall = 4096,
- AudioMenuCall = 8192,
- AngleMenuCall = 16384,
- ChapterMenuCall = 32768,
- Resume = 65536,
- ButtonSelectOrActive = 131072,
- StillOff = 262144,
- PauseOn = 524288,
- AudioStreamChange = 1048576,
- SubpictureStreamChange = 2097152,
- AngleChange = 4194304,
- KaraokeAudioPresentationModeChange = 8388608,
- VideoPresentationModeChange = 16777216,
- }
-}
diff --git a/DvdLib/Properties/AssemblyInfo.cs b/DvdLib/Properties/AssemblyInfo.cs
deleted file mode 100644
index 6acd571d68..0000000000
--- a/DvdLib/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Reflection;
-using System.Resources;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("DvdLib")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Jellyfin Project")]
-[assembly: AssemblyProduct("Jellyfin Server")]
-[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: NeutralResourcesLanguage("en")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index e1e83621b1..fc7d0242d7 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -83,13 +83,11 @@ using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.SyncPlay;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
-using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.MediaEncoding.Subtitles;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
@@ -562,8 +560,6 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton();
- serviceCollection.AddSingleton();
-
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json
index 64cb36fd82..13b99cc997 100644
--- a/Emby.Server.Implementations/Localization/Core/bg-BG.json
+++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json
@@ -123,5 +123,6 @@
"TaskOptimizeDatabase": "Оптимизирай базата данни",
"TaskKeyframeExtractorDescription": "Извличат се ключови кадри от видеофайловете ,за да се създаде по точен ХЛС списък . Задачата може да отнеме много време.",
"TaskKeyframeExtractor": "Извличане на ключови кадри",
- "External": "Външен"
+ "External": "Външен",
+ "HearingImpaired": "Увреден слух"
}
diff --git a/Jellyfin.sln b/Jellyfin.sln
index c0d2ec0687..f3fb7efa98 100644
--- a/Jellyfin.sln
+++ b/Jellyfin.sln
@@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Drawing", "src\Jel
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Photos", "Emby.Photos\Emby.Photos.csproj", "{89AB4548-770D-41FD-A891-8DAFF44F452C}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DvdLib", "DvdLib\DvdLib.csproj", "{713F42B5-878E-499D-A878-E4C652B1D5E8}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Server.Implementations", "Emby.Server.Implementations\Emby.Server.Implementations.csproj", "{E383961B-9356-4D5D-8233-9A1079D03055}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RSSDP", "RSSDP\RSSDP.csproj", "{21002819-C39A-4D3E-BE83-2A276A77FB1F}"
@@ -139,10 +137,6 @@ Global
{89AB4548-770D-41FD-A891-8DAFF44F452C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.Build.0 = Release|Any CPU
- {713F42B5-878E-499D-A878-E4C652B1D5E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {713F42B5-878E-499D-A878-E4C652B1D5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {713F42B5-878E-499D-A878-E4C652B1D5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {713F42B5-878E-499D-A878-E4C652B1D5E8}.Release|Any CPU.Build.0 = Release|Any CPU
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index fe8e9063ee..bc6207ac51 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -187,13 +187,5 @@ namespace MediaBrowser.Controller.MediaEncoding
/// The path.
/// The type of path.
void UpdateEncoderPath(string path, string pathType);
-
- ///
- /// Gets the primary playlist of .vob files.
- ///
- /// The to the .vob files.
- /// The title number to start with.
- /// A playlist.
- IEnumerable GetPrimaryPlaylistVobFiles(string path, uint? titleNumber);
}
}
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
deleted file mode 100644
index 7e026b42e3..0000000000
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Linq;
-using BDInfo.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.MediaEncoding.BdInfo
-{
- public class BdInfoDirectoryInfo : IDirectoryInfo
- {
- private readonly IFileSystem _fileSystem;
-
- private readonly FileSystemMetadata _impl;
-
- public BdInfoDirectoryInfo(IFileSystem fileSystem, string path)
- {
- _fileSystem = fileSystem;
- _impl = _fileSystem.GetDirectoryInfo(path);
- }
-
- private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl)
- {
- _fileSystem = fileSystem;
- _impl = impl;
- }
-
- public string Name => _impl.Name;
-
- public string FullName => _impl.FullName;
-
- public IDirectoryInfo? Parent
- {
- get
- {
- var parentFolder = System.IO.Path.GetDirectoryName(_impl.FullName);
- if (parentFolder is not null)
- {
- return new BdInfoDirectoryInfo(_fileSystem, parentFolder);
- }
-
- return null;
- }
- }
-
- public IDirectoryInfo[] GetDirectories()
- {
- return Array.ConvertAll(
- _fileSystem.GetDirectories(_impl.FullName).ToArray(),
- x => new BdInfoDirectoryInfo(_fileSystem, x));
- }
-
- public IFileInfo[] GetFiles()
- {
- return Array.ConvertAll(
- _fileSystem.GetFiles(_impl.FullName).ToArray(),
- x => new BdInfoFileInfo(x));
- }
-
- public IFileInfo[] GetFiles(string searchPattern)
- {
- return Array.ConvertAll(
- _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(),
- x => new BdInfoFileInfo(x));
- }
-
- public IFileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption)
- {
- return Array.ConvertAll(
- _fileSystem.GetFiles(
- _impl.FullName,
- new[] { searchPattern },
- false,
- (searchOption & System.IO.SearchOption.AllDirectories) == System.IO.SearchOption.AllDirectories).ToArray(),
- x => new BdInfoFileInfo(x));
- }
-
- public static IDirectoryInfo FromFileSystemPath(IFileSystem fs, string path)
- {
- return new BdInfoDirectoryInfo(fs, path);
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
deleted file mode 100644
index 3e53cbf29f..0000000000
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
+++ /dev/null
@@ -1,194 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using BDInfo;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.BdInfo
-{
- ///
- /// Class BdInfoExaminer.
- ///
- public class BdInfoExaminer : IBlurayExaminer
- {
- private readonly IFileSystem _fileSystem;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The filesystem.
- public BdInfoExaminer(IFileSystem fileSystem)
- {
- _fileSystem = fileSystem;
- }
-
- ///
- /// Gets the disc info.
- ///
- /// The path.
- /// BlurayDiscInfo.
- public BlurayDiscInfo GetDiscInfo(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException(nameof(path));
- }
-
- var bdrom = new BDROM(BdInfoDirectoryInfo.FromFileSystemPath(_fileSystem, path));
-
- bdrom.Scan();
-
- // Get the longest playlist
- var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid);
-
- var outputStream = new BlurayDiscInfo
- {
- MediaStreams = Array.Empty()
- };
-
- if (playlist is null)
- {
- return outputStream;
- }
-
- outputStream.Chapters = playlist.Chapters.ToArray();
-
- outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks;
-
- var mediaStreams = new List();
-
- foreach (var stream in playlist.SortedStreams)
- {
- if (stream is TSVideoStream videoStream)
- {
- AddVideoStream(mediaStreams, videoStream);
- continue;
- }
-
- if (stream is TSAudioStream audioStream)
- {
- AddAudioStream(mediaStreams, audioStream);
- continue;
- }
-
- if (stream is TSTextStream textStream)
- {
- AddSubtitleStream(mediaStreams, textStream);
- continue;
- }
-
- if (stream is TSGraphicsStream graphicsStream)
- {
- AddSubtitleStream(mediaStreams, graphicsStream);
- }
- }
-
- outputStream.MediaStreams = mediaStreams.ToArray();
-
- outputStream.PlaylistName = playlist.Name;
-
- if (playlist.StreamClips is not null && playlist.StreamClips.Any())
- {
- // Get the files in the playlist
- outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToArray();
- }
-
- return outputStream;
- }
-
- ///
- /// Adds the video stream.
- ///
- /// The streams.
- /// The video stream.
- private void AddVideoStream(List streams, TSVideoStream videoStream)
- {
- var mediaStream = new MediaStream
- {
- BitRate = Convert.ToInt32(videoStream.BitRate),
- Width = videoStream.Width,
- Height = videoStream.Height,
- Codec = videoStream.CodecShortName,
- IsInterlaced = videoStream.IsInterlaced,
- Type = MediaStreamType.Video,
- Index = streams.Count
- };
-
- if (videoStream.FrameRateDenominator > 0)
- {
- float frameRateEnumerator = videoStream.FrameRateEnumerator;
- float frameRateDenominator = videoStream.FrameRateDenominator;
-
- mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator;
- }
-
- streams.Add(mediaStream);
- }
-
- ///
- /// Adds the audio stream.
- ///
- /// The streams.
- /// The audio stream.
- private void AddAudioStream(List streams, TSAudioStream audioStream)
- {
- var stream = new MediaStream
- {
- Codec = audioStream.CodecShortName,
- Language = audioStream.LanguageCode,
- Channels = audioStream.ChannelCount,
- SampleRate = audioStream.SampleRate,
- Type = MediaStreamType.Audio,
- Index = streams.Count
- };
-
- var bitrate = Convert.ToInt32(audioStream.BitRate);
-
- if (bitrate > 0)
- {
- stream.BitRate = bitrate;
- }
-
- if (audioStream.LFE > 0)
- {
- stream.Channels = audioStream.ChannelCount + 1;
- }
-
- streams.Add(stream);
- }
-
- ///
- /// Adds the subtitle stream.
- ///
- /// The streams.
- /// The text stream.
- private void AddSubtitleStream(List streams, TSTextStream textStream)
- {
- streams.Add(new MediaStream
- {
- Language = textStream.LanguageCode,
- Codec = textStream.CodecShortName,
- Type = MediaStreamType.Subtitle,
- Index = streams.Count
- });
- }
-
- ///
- /// Adds the subtitle stream.
- ///
- /// The streams.
- /// The text stream.
- private void AddSubtitleStream(List streams, TSGraphicsStream textStream)
- {
- streams.Add(new MediaStream
- {
- Language = textStream.LanguageCode,
- Codec = textStream.CodecShortName,
- Type = MediaStreamType.Subtitle,
- Index = streams.Count
- });
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs
deleted file mode 100644
index d55688e3df..0000000000
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma warning disable CS1591
-
-using System.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.MediaEncoding.BdInfo
-{
- public class BdInfoFileInfo : BDInfo.IO.IFileInfo
- {
- private FileSystemMetadata _impl;
-
- public BdInfoFileInfo(FileSystemMetadata impl)
- {
- _impl = impl;
- }
-
- public string Name => _impl.Name;
-
- public string FullName => _impl.FullName;
-
- public string Extension => _impl.Extension;
-
- public long Length => _impl.Length;
-
- public bool IsDir => _impl.IsDirectory;
-
- public Stream OpenRead()
- {
- return new FileStream(
- FullName,
- FileMode.Open,
- FileAccess.Read,
- FileShare.Read);
- }
-
- public StreamReader OpenText()
- {
- return new StreamReader(OpenRead());
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index d95f894c52..d2240b5aff 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -862,85 +862,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
throw new NotImplementedException();
}
- ///
- public IEnumerable GetPrimaryPlaylistVobFiles(string path, uint? titleNumber)
- {
- // min size 300 mb
- const long MinPlayableSize = 314572800;
-
- // Try to eliminate menus and intros by skipping all files at the front of the list that are less than the minimum size
- // Once we reach a file that is at least the minimum, return all subsequent ones
- var allVobs = _fileSystem.GetFiles(path, true)
- .Where(file => string.Equals(file.Extension, ".vob", StringComparison.OrdinalIgnoreCase))
- .OrderBy(i => i.FullName)
- .ToList();
-
- // If we didn't find any satisfying the min length, just take them all
- if (allVobs.Count == 0)
- {
- _logger.LogWarning("No vobs found in dvd structure.");
- return Enumerable.Empty();
- }
-
- if (titleNumber.HasValue)
- {
- var prefix = string.Format(
- CultureInfo.InvariantCulture,
- titleNumber.Value >= 10 ? "VTS_{0}_" : "VTS_0{0}_",
- titleNumber.Value);
- var vobs = allVobs.Where(i => i.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)).ToList();
-
- if (vobs.Count > 0)
- {
- var minSizeVobs = vobs
- .SkipWhile(f => f.Length < MinPlayableSize)
- .ToList();
-
- return minSizeVobs.Count == 0 ? vobs.Select(i => i.FullName) : minSizeVobs.Select(i => i.FullName);
- }
-
- _logger.LogWarning("Could not determine vob file list for {Path} using DvdLib. Will scan using file sizes.", path);
- }
-
- var files = allVobs
- .SkipWhile(f => f.Length < MinPlayableSize)
- .ToList();
-
- // If we didn't find any satisfying the min length, just take them all
- if (files.Count == 0)
- {
- _logger.LogWarning("Vob size filter resulted in zero matches. Taking all vobs.");
- files = allVobs;
- }
-
- // Assuming they're named "vts_05_01", take all files whose second part matches that of the first file
- if (files.Count > 0)
- {
- var parts = _fileSystem.GetFileNameWithoutExtension(files[0]).Split('_');
-
- if (parts.Length == 3)
- {
- var title = parts[1];
-
- files = files.TakeWhile(f =>
- {
- var fileParts = _fileSystem.GetFileNameWithoutExtension(f).Split('_');
-
- return fileParts.Length == 3 && string.Equals(title, fileParts[1], StringComparison.OrdinalIgnoreCase);
- }).ToList();
-
- // If this resulted in not getting any vobs, just take them all
- if (files.Count == 0)
- {
- _logger.LogWarning("Vob filename filter resulted in zero matches. Taking all vobs.");
- files = allVobs;
- }
- }
- }
-
- return files.Select(i => i.FullName);
- }
-
public bool CanExtractSubtitles(string codec)
{
// TODO is there ever a case when a subtitle can't be extracted??
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 1233fb1108..93177298f9 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -22,7 +22,6 @@
-
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 18e248a1bd..04bdbdf59e 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -625,17 +625,6 @@ namespace MediaBrowser.MediaEncoding.Probing
return attachment;
}
- ///
- /// Determines whether a stream code time base is double the frame rate.
- ///
- /// average frame rate.
- /// codec time base string.
- /// true if the codec time base is double the frame rate.
- internal static bool IsCodecTimeBaseDoubleTheFrameRate(float? averageFrameRate, string codecTimeBase)
- {
- return MathF.Abs(((averageFrameRate ?? 0) * (GetFrameRate(codecTimeBase) ?? 0)) - 0.5f) <= float.Epsilon;
- }
-
///
/// Converts ffprobe stream info to our MediaStream class.
///
@@ -748,22 +737,9 @@ namespace MediaBrowser.MediaEncoding.Probing
stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
- bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
+ stream.IsInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
&& !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase);
- // Some interlaced H.264 files in mp4 containers using MBAFF coding aren't flagged as being interlaced by FFprobe,
- // so for H.264 files we also calculate the frame rate from the codec time base and check if it is double the reported
- // frame rate to determine if the file is interlaced
-
- bool h264MbaffCoded = string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)
- && string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
- && IsCodecTimeBaseDoubleTheFrameRate(stream.AverageFrameRate, stream.CodecTimeBase);
-
- if (videoInterlaced || h264MbaffCoded)
- {
- stream.IsInterlaced = true;
- }
-
if (isAudio
|| string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)
|| string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase)
diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
deleted file mode 100644
index 83f982a5c8..0000000000
--- a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-#nullable disable
-#pragma warning disable CS1591
-
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Model.MediaInfo
-{
- ///
- /// Represents the result of BDInfo output.
- ///
- public class BlurayDiscInfo
- {
- ///
- /// Gets or sets the media streams.
- ///
- /// The media streams.
- public MediaStream[] MediaStreams { get; set; }
-
- ///
- /// Gets or sets the run time ticks.
- ///
- /// The run time ticks.
- public long? RunTimeTicks { get; set; }
-
- ///
- /// Gets or sets the files.
- ///
- /// The files.
- public string[] Files { get; set; }
-
- public string PlaylistName { get; set; }
-
- ///
- /// Gets or sets the chapters.
- ///
- /// The chapters.
- public double[] Chapters { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs b/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs
deleted file mode 100644
index 5b7d1d03c3..0000000000
--- a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace MediaBrowser.Model.MediaInfo
-{
- ///
- /// Interface IBlurayExaminer.
- ///
- public interface IBlurayExaminer
- {
- ///
- /// Gets the disc info.
- ///
- /// The path.
- /// BlurayDiscInfo.
- BlurayDiscInfo GetDiscInfo(string path);
- }
-}
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 13de86a929..9e238e9f3a 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -8,7 +8,6 @@
-
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 81434b8620..0f35c6a5ea 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -9,7 +9,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using DvdLib.Ifo;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Configuration;
@@ -37,7 +36,6 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly ILogger _logger;
private readonly IMediaEncoder _mediaEncoder;
private readonly IItemRepository _itemRepo;
- private readonly IBlurayExaminer _blurayExaminer;
private readonly ILocalizationManager _localization;
private readonly IEncodingManager _encodingManager;
private readonly IServerConfigurationManager _config;
@@ -53,7 +51,6 @@ namespace MediaBrowser.Providers.MediaInfo
IMediaSourceManager mediaSourceManager,
IMediaEncoder mediaEncoder,
IItemRepository itemRepo,
- IBlurayExaminer blurayExaminer,
ILocalizationManager localization,
IEncodingManager encodingManager,
IServerConfigurationManager config,
@@ -67,7 +64,6 @@ namespace MediaBrowser.Providers.MediaInfo
_mediaSourceManager = mediaSourceManager;
_mediaEncoder = mediaEncoder;
_itemRepo = itemRepo;
- _blurayExaminer = blurayExaminer;
_localization = localization;
_encodingManager = encodingManager;
_config = config;
@@ -84,47 +80,16 @@ namespace MediaBrowser.Providers.MediaInfo
CancellationToken cancellationToken)
where T : Video
{
- BlurayDiscInfo blurayDiscInfo = null;
-
Model.MediaInfo.MediaInfo mediaInfoResult = null;
if (!item.IsShortcut || options.EnableRemoteContentProbe)
{
- string[] streamFileNames = null;
-
- if (item.VideoType == VideoType.Dvd)
- {
- streamFileNames = FetchFromDvdLib(item);
-
- if (streamFileNames.Length == 0)
- {
- _logger.LogError("No playable vobs found in dvd structure, skipping ffprobe.");
- return ItemUpdateType.MetadataImport;
- }
- }
- else if (item.VideoType == VideoType.BluRay)
- {
- var inputPath = item.Path;
-
- blurayDiscInfo = GetBDInfo(inputPath);
-
- streamFileNames = blurayDiscInfo.Files;
-
- if (streamFileNames.Length == 0)
- {
- _logger.LogError("No playable vobs found in bluray structure, skipping ffprobe.");
- return ItemUpdateType.MetadataImport;
- }
- }
-
- streamFileNames ??= Array.Empty();
-
mediaInfoResult = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
}
- await Fetch(item, cancellationToken, mediaInfoResult, blurayDiscInfo, options).ConfigureAwait(false);
+ await Fetch(item, cancellationToken, mediaInfoResult, options).ConfigureAwait(false);
return ItemUpdateType.MetadataImport;
}
@@ -164,7 +129,6 @@ namespace MediaBrowser.Providers.MediaInfo
Video video,
CancellationToken cancellationToken,
Model.MediaInfo.MediaInfo mediaInfo,
- BlurayDiscInfo blurayInfo,
MetadataRefreshOptions options)
{
List mediaStreams;
@@ -218,10 +182,6 @@ namespace MediaBrowser.Providers.MediaInfo
video.Container = mediaInfo.Container;
chapters = mediaInfo.Chapters ?? Array.Empty();
- if (blurayInfo is not null)
- {
- FetchBdInfo(video, ref chapters, mediaStreams, blurayInfo);
- }
}
else
{
@@ -317,91 +277,6 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- private void FetchBdInfo(BaseItem item, ref ChapterInfo[] chapters, List mediaStreams, BlurayDiscInfo blurayInfo)
- {
- var video = (Video)item;
-
- // video.PlayableStreamFileNames = blurayInfo.Files.ToList();
-
- // Use BD Info if it has multiple m2ts. Otherwise, treat it like a video file and rely more on ffprobe output
- if (blurayInfo.Files.Length > 1)
- {
- int? currentHeight = null;
- int? currentWidth = null;
- int? currentBitRate = null;
-
- var videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
-
- // Grab the values that ffprobe recorded
- if (videoStream is not null)
- {
- currentBitRate = videoStream.BitRate;
- currentWidth = videoStream.Width;
- currentHeight = videoStream.Height;
- }
-
- // Fill video properties from the BDInfo result
- mediaStreams.Clear();
- mediaStreams.AddRange(blurayInfo.MediaStreams);
-
- if (blurayInfo.RunTimeTicks.HasValue && blurayInfo.RunTimeTicks.Value > 0)
- {
- video.RunTimeTicks = blurayInfo.RunTimeTicks;
- }
-
- if (blurayInfo.Chapters is not null)
- {
- double[] brChapter = blurayInfo.Chapters;
- chapters = new ChapterInfo[brChapter.Length];
- for (int i = 0; i < brChapter.Length; i++)
- {
- chapters[i] = new ChapterInfo
- {
- StartPositionTicks = TimeSpan.FromSeconds(brChapter[i]).Ticks
- };
- }
- }
-
- videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
-
- // Use the ffprobe values if these are empty
- if (videoStream is not null)
- {
- videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate;
- videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width;
- videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height;
- }
- }
- }
-
- private bool IsEmpty(int? num)
- {
- return !num.HasValue || num.Value == 0;
- }
-
- ///
- /// Gets information about the longest playlist on a bdrom.
- ///
- /// The path.
- /// VideoStream.
- private BlurayDiscInfo GetBDInfo(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException(nameof(path));
- }
-
- try
- {
- return _blurayExaminer.GetDiscInfo(path);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting BDInfo");
- return null;
- }
- }
-
private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions refreshOptions, LibraryOptions libraryOptions)
{
var replaceData = refreshOptions.ReplaceAllMetadata;
@@ -683,33 +558,5 @@ namespace MediaBrowser.Providers.MediaInfo
return chapters;
}
-
- private string[] FetchFromDvdLib(Video item)
- {
- var path = item.Path;
- var dvd = new Dvd(path);
-
- var primaryTitle = dvd.Titles.OrderByDescending(GetRuntime).FirstOrDefault();
-
- byte? titleNumber = null;
-
- if (primaryTitle is not null)
- {
- titleNumber = primaryTitle.VideoTitleSetNumber;
- item.RunTimeTicks = GetRuntime(primaryTitle);
- }
-
- return _mediaEncoder.GetPrimaryPlaylistVobFiles(item.Path, titleNumber)
- .Select(Path.GetFileName)
- .ToArray();
- }
-
- private long GetRuntime(Title title)
- {
- return title.ProgramChains
- .Select(i => (TimeSpan)i.PlaybackTime)
- .Select(i => i.Ticks)
- .Sum();
- }
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
index 2800219552..31fa3da1ce 100644
--- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
@@ -53,7 +53,6 @@ namespace MediaBrowser.Providers.MediaInfo
/// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
- /// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
@@ -67,7 +66,6 @@ namespace MediaBrowser.Providers.MediaInfo
IMediaSourceManager mediaSourceManager,
IMediaEncoder mediaEncoder,
IItemRepository itemRepo,
- IBlurayExaminer blurayExaminer,
ILocalizationManager localization,
IEncodingManager encodingManager,
IServerConfigurationManager config,
@@ -87,7 +85,6 @@ namespace MediaBrowser.Providers.MediaInfo
mediaSourceManager,
mediaEncoder,
itemRepo,
- blurayExaminer,
localization,
encodingManager,
config,
diff --git a/debian/bin/restart.sh b/debian/bin/restart.sh
deleted file mode 100755
index 4847b918be..0000000000
--- a/debian/bin/restart.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/bash
-
-# restart.sh - Jellyfin server restart script
-# Part of the Jellyfin project (https://github.com/jellyfin)
-#
-# This script restarts the Jellyfin daemon on Linux when using
-# the Restart button on the admin dashboard. It supports the
-# systemctl, service, and traditional /etc/init.d (sysv) restart
-# methods, chosen automatically by which one is found first (in
-# that order).
-#
-# This script is used by the Debian/Ubuntu/Fedora/CentOS packages.
-
-# This is the Right Way(tm) to check if we are booted with
-# systemd, according to sd_booted(3)
-if [ -d /run/systemd/system ]; then
- cmd=systemctl
-else
- # Everything else is really hard to figure out, so we just use
- # service(8) if it's available - that works with most init
- # systems/distributions I know of, including FreeBSD
- if type service >/dev/null 2>&1; then
- cmd=service
- else
- # If even service(8) isn't available, we just try /etc/init.d
- # and hope for the best
- if [ -d /etc/init.d ]; then
- cmd=sysv
- else
- echo "Unable to detect a way to restart Jellyfin; bailing out" 1>&2
- echo "Please report this bug to https://github.com/jellyfin/jellyfin/issues" 1>&2
- exit 1
- fi
- fi
-fi
-
-if type sudo >/dev/null 2>&1; then
- sudo_command=sudo
-else
- sudo_command=
-fi
-
-echo "Detected service control platform '$cmd'; using it to restart Jellyfin..."
-case $cmd in
- 'systemctl')
- # Without systemd-run here, `jellyfin.service`'s shutdown terminates this process too
- $sudo_command systemd-run systemctl restart jellyfin
- ;;
- 'service')
- echo "sleep 0.5; $sudo_command service jellyfin start" | at now
- ;;
- 'sysv')
- echo "sleep 0.5; /usr/bin/sudo /etc/init.d/jellyfin start" | at now
- ;;
-esac
-exit 0
diff --git a/debian/conf/jellyfin b/debian/conf/jellyfin
index 2f0630a9ce..9129967559 100644
--- a/debian/conf/jellyfin
+++ b/debian/conf/jellyfin
@@ -21,9 +21,6 @@ JELLYFIN_CACHE_DIR="/var/cache/jellyfin"
# web client path, installed by the jellyfin-web package
JELLYFIN_WEB_OPT="--webdir=/usr/share/jellyfin/web"
-# Restart script for in-app server control
-JELLYFIN_RESTART_OPT="--restartpath=/usr/lib/jellyfin/restart.sh"
-
# ffmpeg binary paths, overriding the system values
JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg"
@@ -50,4 +47,4 @@ JELLYFIN_ADDITIONAL_OPTS=""
# Application username
JELLYFIN_USER="jellyfin"
# Full application command
-JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLFIN_ADDITIONAL_OPTS"
+JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLFIN_ADDITIONAL_OPTS"
diff --git a/debian/install b/debian/install
index 994322d141..593b13a7b3 100644
--- a/debian/install
+++ b/debian/install
@@ -3,4 +3,3 @@ debian/conf/jellyfin etc/default/
debian/conf/logging.json etc/jellyfin/
debian/conf/jellyfin.service.conf etc/systemd/system/jellyfin.service.d/
debian/conf/jellyfin-sudoers etc/sudoers.d/
-debian/bin/restart.sh usr/lib/jellyfin/
diff --git a/debian/jellyfin.service b/debian/jellyfin.service
index 1150924a08..2cc49f7c4a 100644
--- a/debian/jellyfin.service
+++ b/debian/jellyfin.service
@@ -8,7 +8,7 @@ EnvironmentFile = /etc/default/jellyfin
User = jellyfin
Group = jellyfin
WorkingDirectory = /var/lib/jellyfin
-ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS
+ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS
Restart = on-failure
TimeoutSec = 15
SuccessExitStatus=0 143
diff --git a/debian/postinst b/debian/postinst
index a15442c76e..947959aa7a 100644
--- a/debian/postinst
+++ b/debian/postinst
@@ -59,8 +59,6 @@ case "$1" in
chgrp adm $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA
chmod 0750 $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA
- chmod +x /usr/lib/jellyfin/restart.sh > /dev/null 2>&1 || true
-
# Install jellyfin symlink into /usr/bin
ln -sf /usr/lib/jellyfin/bin/jellyfin /usr/bin/jellyfin
diff --git a/fedora/jellyfin.env b/fedora/jellyfin.env
index 1ccd8196fd..1f79fac4f6 100644
--- a/fedora/jellyfin.env
+++ b/fedora/jellyfin.env
@@ -23,9 +23,6 @@ JELLYFIN_CACHE_DIR="/var/cache/jellyfin"
# web client path, installed by the jellyfin-web package
# JELLYFIN_WEB_OPT="--webdir=/usr/share/jellyfin-web"
-# In-App service control
-JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh"
-
# [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values
#JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg"
diff --git a/fedora/jellyfin.service b/fedora/jellyfin.service
index 2fb9f30e00..1b3f8032c6 100644
--- a/fedora/jellyfin.service
+++ b/fedora/jellyfin.service
@@ -8,7 +8,7 @@ EnvironmentFile = /etc/sysconfig/jellyfin
User = jellyfin
Group = jellyfin
WorkingDirectory = /var/lib/jellyfin
-ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS
+ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS
Restart = on-failure
TimeoutSec = 15
SuccessExitStatus=0 143
diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec
index 08de715370..2456877890 100644
--- a/fedora/jellyfin.spec
+++ b/fedora/jellyfin.spec
@@ -17,10 +17,9 @@ Source0: jellyfin-server-%{version}.tar.gz
Source11: jellyfin.service
Source12: jellyfin.env
Source13: jellyfin.sudoers
-Source14: restart.sh
-Source15: jellyfin.override.conf
-Source16: jellyfin-firewalld.xml
-Source17: jellyfin-server-lowports.conf
+Source14: jellyfin.override.conf
+Source15: jellyfin-firewalld.xml
+Source16: jellyfin-server-lowports.conf
%{?systemd_requires}
BuildRequires: systemd
@@ -76,16 +75,15 @@ dotnet publish --configuration Release --self-contained --runtime %{dotnet_runti
%{__mkdir} -p %{buildroot}%{_libdir}/jellyfin %{buildroot}%{_bindir}
%{__cp} -r Jellyfin.Server/bin/Release/net7.0/%{dotnet_runtime}/publish/* %{buildroot}%{_libdir}/jellyfin
ln -srf %{_libdir}/jellyfin/jellyfin %{buildroot}%{_bindir}/jellyfin
-%{__install} -D %{SOURCE14} %{buildroot}%{_libexecdir}/jellyfin/restart.sh
# Jellyfin config
%{__install} -D Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/jellyfin/logging.json
%{__install} -D %{SOURCE12} %{buildroot}%{_sysconfdir}/sysconfig/jellyfin
# system config
-%{__install} -D %{SOURCE16} %{buildroot}%{_prefix}/lib/firewalld/services/jellyfin.xml
+%{__install} -D %{SOURCE15} %{buildroot}%{_prefix}/lib/firewalld/services/jellyfin.xml
%{__install} -D %{SOURCE13} %{buildroot}%{_sysconfdir}/sudoers.d/jellyfin-sudoers
-%{__install} -D %{SOURCE15} %{buildroot}%{_sysconfdir}/systemd/system/jellyfin.service.d/override.conf
+%{__install} -D %{SOURCE14} %{buildroot}%{_sysconfdir}/systemd/system/jellyfin.service.d/override.conf
%{__install} -D %{SOURCE11} %{buildroot}%{_unitdir}/jellyfin.service
# empty directories
@@ -95,7 +93,7 @@ ln -srf %{_libdir}/jellyfin/jellyfin %{buildroot}%{_bindir}/jellyfin
%{__mkdir} -p %{buildroot}%{_var}/log/jellyfin
# jellyfin-server-lowports subpackage
-%{__install} -D -m 0644 %{SOURCE17} %{buildroot}%{_unitdir}/jellyfin.service.d/jellyfin-server-lowports.conf
+%{__install} -D -m 0644 %{SOURCE16} %{buildroot}%{_unitdir}/jellyfin.service.d/jellyfin-server-lowports.conf
%files
@@ -110,7 +108,6 @@ ln -srf %{_libdir}/jellyfin/jellyfin %{buildroot}%{_bindir}/jellyfin
%attr(755,root,root) %{_libdir}/jellyfin/createdump
%attr(755,root,root) %{_libdir}/jellyfin/jellyfin
%{_libdir}/jellyfin/*
-%attr(755,root,root) %{_libexecdir}/jellyfin/restart.sh
# Jellyfin config
%config(noreplace) %attr(644,jellyfin,jellyfin) %{_sysconfdir}/jellyfin/logging.json
diff --git a/fedora/restart.sh b/fedora/restart.sh
deleted file mode 100755
index 4847b918be..0000000000
--- a/fedora/restart.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/bash
-
-# restart.sh - Jellyfin server restart script
-# Part of the Jellyfin project (https://github.com/jellyfin)
-#
-# This script restarts the Jellyfin daemon on Linux when using
-# the Restart button on the admin dashboard. It supports the
-# systemctl, service, and traditional /etc/init.d (sysv) restart
-# methods, chosen automatically by which one is found first (in
-# that order).
-#
-# This script is used by the Debian/Ubuntu/Fedora/CentOS packages.
-
-# This is the Right Way(tm) to check if we are booted with
-# systemd, according to sd_booted(3)
-if [ -d /run/systemd/system ]; then
- cmd=systemctl
-else
- # Everything else is really hard to figure out, so we just use
- # service(8) if it's available - that works with most init
- # systems/distributions I know of, including FreeBSD
- if type service >/dev/null 2>&1; then
- cmd=service
- else
- # If even service(8) isn't available, we just try /etc/init.d
- # and hope for the best
- if [ -d /etc/init.d ]; then
- cmd=sysv
- else
- echo "Unable to detect a way to restart Jellyfin; bailing out" 1>&2
- echo "Please report this bug to https://github.com/jellyfin/jellyfin/issues" 1>&2
- exit 1
- fi
- fi
-fi
-
-if type sudo >/dev/null 2>&1; then
- sudo_command=sudo
-else
- sudo_command=
-fi
-
-echo "Detected service control platform '$cmd'; using it to restart Jellyfin..."
-case $cmd in
- 'systemctl')
- # Without systemd-run here, `jellyfin.service`'s shutdown terminates this process too
- $sudo_command systemd-run systemctl restart jellyfin
- ;;
- 'service')
- echo "sleep 0.5; $sudo_command service jellyfin start" | at now
- ;;
- 'sysv')
- echo "sleep 0.5; /usr/bin/sudo /etc/init.d/jellyfin start" | at now
- ;;
-esac
-exit 0
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
index bbe1246ca7..a64604e99f 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
@@ -31,16 +31,6 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
public void GetFrameRate_Success(string value, float? expected)
=> Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value));
- [Theory]
- [InlineData(0.5f, "0/1", false)]
- [InlineData(24.5f, "8/196", false)]
- [InlineData(63.5f, "1/127", true)]
- [InlineData(null, "1/60", false)]
- [InlineData(30f, "2/120", true)]
- [InlineData(59.999996f, "1563/187560", true)]
- public void IsCodecTimeBaseDoubleTheFrameRate_Success(float? frameRate, string codecTimeBase, bool expected)
- => Assert.Equal(expected, ProbeResultNormalizer.IsCodecTimeBaseDoubleTheFrameRate(frameRate, codecTimeBase));
-
[Fact]
public void GetMediaInfo_MetaData_Success()
{
@@ -158,6 +148,99 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
Assert.False(res.MediaStreams[5].IsHearingImpaired);
}
+ [Fact]
+ public void GetMediaInfo_ProgressiveVideoNoFieldOrder_Success()
+ {
+ var bytes = File.ReadAllBytes("Test Data/Probing/video_progressive_no_field_order.json");
+
+ var internalMediaInfoResult = JsonSerializer.Deserialize(bytes, _jsonOptions);
+ MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_progressive_no_field_order.mp4", MediaProtocol.File);
+
+ Assert.Equal(2, res.MediaStreams.Count);
+
+ Assert.NotNull(res.VideoStream);
+ Assert.Equal(res.MediaStreams[0], res.VideoStream);
+ Assert.Equal(0, res.VideoStream.Index);
+ Assert.Equal("h264", res.VideoStream.Codec);
+ Assert.Equal("Main", res.VideoStream.Profile);
+ Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
+ Assert.Equal(1080, res.VideoStream.Height);
+ Assert.Equal(1920, res.VideoStream.Width);
+ Assert.False(res.VideoStream.IsInterlaced);
+ Assert.Equal("16:9", res.VideoStream.AspectRatio);
+ Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
+ Assert.Equal(41d, res.VideoStream.Level);
+ Assert.Equal(1, res.VideoStream.RefFrames);
+ Assert.True(res.VideoStream.IsAVC);
+ Assert.Equal(23.9760246f, res.VideoStream.RealFrameRate);
+ Assert.Equal("1/24000", res.VideoStream.TimeBase);
+ Assert.Equal(3948341, res.VideoStream.BitRate);
+ Assert.Equal(8, res.VideoStream.BitDepth);
+ Assert.True(res.VideoStream.IsDefault);
+ }
+
+ [Fact]
+ public void GetMediaInfo_ProgressiveVideoNoFieldOrder2_Success()
+ {
+ var bytes = File.ReadAllBytes("Test Data/Probing/video_progressive_no_field_order2.json");
+
+ var internalMediaInfoResult = JsonSerializer.Deserialize(bytes, _jsonOptions);
+ MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_progressive_no_field_order2.mp4", MediaProtocol.File);
+
+ Assert.Single(res.MediaStreams);
+
+ Assert.NotNull(res.VideoStream);
+ Assert.Equal(res.MediaStreams[0], res.VideoStream);
+ Assert.Equal(0, res.VideoStream.Index);
+ Assert.Equal("h264", res.VideoStream.Codec);
+ Assert.Equal("High", res.VideoStream.Profile);
+ Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
+ Assert.Equal(720, res.VideoStream.Height);
+ Assert.Equal(1280, res.VideoStream.Width);
+ Assert.False(res.VideoStream.IsInterlaced);
+ Assert.Equal("16:9", res.VideoStream.AspectRatio);
+ Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
+ Assert.Equal(31d, res.VideoStream.Level);
+ Assert.Equal(1, res.VideoStream.RefFrames);
+ Assert.True(res.VideoStream.IsAVC);
+ Assert.Equal(25f, res.VideoStream.RealFrameRate);
+ Assert.Equal("1/12800", res.VideoStream.TimeBase);
+ Assert.Equal(53288, res.VideoStream.BitRate);
+ Assert.Equal(8, res.VideoStream.BitDepth);
+ Assert.True(res.VideoStream.IsDefault);
+ }
+
+ [Fact]
+ public void GetMediaInfo_InterlacedVideo_Success()
+ {
+ var bytes = File.ReadAllBytes("Test Data/Probing/video_interlaced.json");
+
+ var internalMediaInfoResult = JsonSerializer.Deserialize(bytes, _jsonOptions);
+ MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_interlaced.mp4", MediaProtocol.File);
+
+ Assert.Single(res.MediaStreams);
+
+ Assert.NotNull(res.VideoStream);
+ Assert.Equal(res.MediaStreams[0], res.VideoStream);
+ Assert.Equal(0, res.VideoStream.Index);
+ Assert.Equal("h264", res.VideoStream.Codec);
+ Assert.Equal("High", res.VideoStream.Profile);
+ Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
+ Assert.Equal(720, res.VideoStream.Height);
+ Assert.Equal(1280, res.VideoStream.Width);
+ Assert.True(res.VideoStream.IsInterlaced);
+ Assert.Equal("16:9", res.VideoStream.AspectRatio);
+ Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
+ Assert.Equal(40d, res.VideoStream.Level);
+ Assert.Equal(1, res.VideoStream.RefFrames);
+ Assert.True(res.VideoStream.IsAVC);
+ Assert.Equal(25f, res.VideoStream.RealFrameRate);
+ Assert.Equal("1/12800", res.VideoStream.TimeBase);
+ Assert.Equal(56945, res.VideoStream.BitRate);
+ Assert.Equal(8, res.VideoStream.BitDepth);
+ Assert.True(res.VideoStream.IsDefault);
+ }
+
[Fact]
public void GetMediaInfo_MusicVideo_Success()
{
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json
new file mode 100644
index 0000000000..8102449208
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json
@@ -0,0 +1,81 @@
+{
+ "streams": [
+ {
+ "index": 0,
+ "codec_name": "h264",
+ "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
+ "profile": "High",
+ "codec_type": "video",
+ "codec_tag_string": "avc1",
+ "codec_tag": "0x31637661",
+ "width": 1280,
+ "height": 720,
+ "coded_width": 1280,
+ "coded_height": 720,
+ "closed_captions": 0,
+ "film_grain": 0,
+ "has_b_frames": 2,
+ "pix_fmt": "yuv420p",
+ "level": 40,
+ "chroma_location": "left",
+ "field_order": "tt",
+ "refs": 1,
+ "is_avc": "true",
+ "nal_length_size": "4",
+ "id": "0x1",
+ "r_frame_rate": "25/1",
+ "avg_frame_rate": "25/1",
+ "time_base": "1/12800",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "duration_ts": 3840000,
+ "duration": "300.000000",
+ "bit_rate": "56945",
+ "bits_per_raw_sample": "8",
+ "nb_frames": "7500",
+ "extradata_size": 42,
+ "disposition": {
+ "default": 1,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0,
+ "timed_thumbnails": 0,
+ "captions": 0,
+ "descriptions": 0,
+ "metadata": 0,
+ "dependent": 0,
+ "still_image": 0
+ },
+ "tags": {
+ "language": "und",
+ "handler_name": "VideoHandler",
+ "vendor_id": "[0][0][0][0]"
+ }
+ }
+ ],
+ "format": {
+ "filename": "test-gray.720i.mp4",
+ "nb_streams": 1,
+ "nb_programs": 0,
+ "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
+ "format_long_name": "QuickTime / MOV",
+ "start_time": "0.000000",
+ "duration": "300.000000",
+ "size": "2223957",
+ "bit_rate": "59305",
+ "probe_score": 100,
+ "tags": {
+ "major_brand": "isom",
+ "minor_version": "512",
+ "compatible_brands": "isomiso2avc1mp41",
+ "encoder": "Lavf58.20.100"
+ }
+ }
+}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json
new file mode 100644
index 0000000000..897c5e3aba
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json
@@ -0,0 +1,133 @@
+{
+ "streams": [
+ {
+ "index": 0,
+ "codec_name": "h264",
+ "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
+ "profile": "Main",
+ "codec_type": "video",
+ "codec_time_base": "1001/48000",
+ "codec_tag_string": "avc1",
+ "codec_tag": "0x31637661",
+ "width": 1920,
+ "height": 1080,
+ "coded_width": 1920,
+ "coded_height": 1088,
+ "closed_captions": 0,
+ "has_b_frames": 1,
+ "sample_aspect_ratio": "1:1",
+ "display_aspect_ratio": "16:9",
+ "pix_fmt": "yuv420p",
+ "level": 41,
+ "chroma_location": "left",
+ "refs": 1,
+ "is_avc": "true",
+ "nal_length_size": "4",
+ "r_frame_rate": "24000/1001",
+ "avg_frame_rate": "24000/1001",
+ "time_base": "1/24000",
+ "start_pts": 1000,
+ "start_time": "0.041667",
+ "duration_ts": 29095066,
+ "duration": "1212.294417",
+ "bit_rate": "3948341",
+ "bits_per_raw_sample": "8",
+ "nb_frames": "29066",
+ "disposition": {
+ "default": 1,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0,
+ "timed_thumbnails": 0
+ },
+ "tags": {
+ "creation_time": "2020-01-20T13:56:34.000000Z",
+ "language": "eng",
+ "handler_name": "\fVideoHandler",
+ "encoder": "h264"
+ }
+ },
+ {
+ "index": 1,
+ "codec_name": "ac3",
+ "codec_long_name": "ATSC A/52A (AC-3)",
+ "codec_type": "audio",
+ "codec_time_base": "1/48000",
+ "codec_tag_string": "ac-3",
+ "codec_tag": "0x332d6361",
+ "sample_fmt": "fltp",
+ "sample_rate": "48000",
+ "channels": 2,
+ "channel_layout": "stereo",
+ "bits_per_sample": 0,
+ "dmix_mode": "-1",
+ "ltrt_cmixlev": "-1.000000",
+ "ltrt_surmixlev": "-1.000000",
+ "loro_cmixlev": "-1.000000",
+ "loro_surmixlev": "-1.000000",
+ "r_frame_rate": "0/0",
+ "avg_frame_rate": "0/0",
+ "time_base": "1/48000",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "duration_ts": 58232832,
+ "duration": "1213.184000",
+ "bit_rate": "224000",
+ "nb_frames": "37912",
+ "disposition": {
+ "default": 1,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0,
+ "timed_thumbnails": 0
+ },
+ "tags": {
+ "creation_time": "2020-01-20T13:56:34.000000Z",
+ "language": "eng",
+ "handler_name": "\fSoundHandler"
+ },
+ "side_data_list": [
+ {
+ "side_data_type": "Audio Service Type"
+ }
+ ]
+ }
+ ],
+ "format": {
+ "filename": "The Big Bang Theory - S01E17.mp4",
+ "nb_streams": 2,
+ "nb_programs": 0,
+ "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
+ "format_long_name": "QuickTime / MOV",
+ "start_time": "0.000000",
+ "duration": "1213.184000",
+ "size": "633084606",
+ "bit_rate": "4174698",
+ "probe_score": 100,
+ "tags": {
+ "major_brand": "mp42",
+ "minor_version": "512",
+ "compatible_brands": "mp42",
+ "creation_time": "2020-01-20T13:56:34.000000Z",
+ "media_type": "9",
+ "season_number": "0",
+ "episode_sort": "0",
+ "hd_video": "0",
+ "iTunMOVI": "studiostudiocastnamedirectorsnameproducersnamecodirectorsnamecodirectorscreenwritersname"
+ }
+ }
+}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json
new file mode 100644
index 0000000000..4a03e0d61c
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json
@@ -0,0 +1,72 @@
+{
+ "streams": [
+ {
+ "index": 0,
+ "codec_name": "h264",
+ "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
+ "profile": "High",
+ "codec_type": "video",
+ "codec_time_base": "1/50",
+ "codec_tag_string": "avc1",
+ "codec_tag": "0x31637661",
+ "width": 1280,
+ "height": 720,
+ "coded_width": 1280,
+ "coded_height": 720,
+ "closed_captions": 0,
+ "has_b_frames": 2,
+ "pix_fmt": "yuv420p",
+ "level": 31,
+ "chroma_location": "left",
+ "refs": 1,
+ "is_avc": "true",
+ "nal_length_size": "4",
+ "r_frame_rate": "25/1",
+ "avg_frame_rate": "25/1",
+ "time_base": "1/12800",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "duration_ts": 3840000,
+ "duration": "300.000000",
+ "bit_rate": "53288",
+ "bits_per_raw_sample": "8",
+ "nb_frames": "7500",
+ "disposition": {
+ "default": 1,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0,
+ "timed_thumbnails": 0
+ },
+ "tags": {
+ "language": "und",
+ "handler_name": "VideoHandler"
+ }
+ }
+ ],
+ "format": {
+ "filename": "test-gray.720p.mp4",
+ "nb_streams": 1,
+ "nb_programs": 0,
+ "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
+ "format_long_name": "QuickTime / MOV",
+ "start_time": "0.000000",
+ "duration": "300.000000",
+ "size": "2086818",
+ "bit_rate": "55648",
+ "probe_score": 100,
+ "tags": {
+ "major_brand": "isom",
+ "minor_version": "512",
+ "compatible_brands": "isomiso2avc1mp41",
+ "encoder": "Lavf58.20.100"
+ }
+ }
+}
| | | |