mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-03 14:28:46 +01:00
Merge remote-tracking branch 'upstream/master' into warn-259810
This commit is contained in:
@@ -1100,7 +1100,6 @@ namespace Emby.Server.Implementations
|
||||
ServerName = FriendlyName,
|
||||
LocalAddress = GetSmartApiUrl(source),
|
||||
SupportsLibraryMonitor = true,
|
||||
EncoderLocation = _mediaEncoder.EncoderLocation,
|
||||
SystemArchitecture = RuntimeInformation.OSArchitecture,
|
||||
PackageName = _startupOptions.PackageName
|
||||
};
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
|
||||
var libraryOptions = new LibraryOptions
|
||||
{
|
||||
PathInfos = new[] { new MediaPathInfo { Path = path } },
|
||||
PathInfos = new[] { new MediaPathInfo(path) },
|
||||
EnableRealtimeMonitor = false,
|
||||
SaveLocalMetadata = true
|
||||
};
|
||||
|
||||
@@ -1141,15 +1141,25 @@ namespace Emby.Server.Implementations.Data
|
||||
Path = RestorePath(path.ToString())
|
||||
};
|
||||
|
||||
if (long.TryParse(dateModified, NumberStyles.Any, CultureInfo.InvariantCulture, out var ticks))
|
||||
if (long.TryParse(dateModified, NumberStyles.Any, CultureInfo.InvariantCulture, out var ticks)
|
||||
&& ticks >= DateTime.MinValue.Ticks
|
||||
&& ticks <= DateTime.MaxValue.Ticks)
|
||||
{
|
||||
image.DateModified = new DateTime(ticks, DateTimeKind.Utc);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Enum.TryParse(imageType.ToString(), true, out ImageType type))
|
||||
{
|
||||
image.Type = type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Optional parameters: width*height*blurhash
|
||||
if (nextSegment + 1 < value.Length - 1)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscUtils.Udf" Version="0.16.4" />
|
||||
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
||||
@@ -30,7 +31,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.9" />
|
||||
<PackageReference Include="Mono.Nat" Version="3.0.1" />
|
||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.1.0" />
|
||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.28.3" />
|
||||
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />
|
||||
<PackageReference Include="DotNet.Glob" Version="3.1.2" />
|
||||
|
||||
@@ -3173,10 +3173,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
if (!list.Any(i => string.Equals(i.Path, location, StringComparison.Ordinal)))
|
||||
{
|
||||
list.Add(new MediaPathInfo
|
||||
{
|
||||
Path = location
|
||||
});
|
||||
list.Add(new MediaPathInfo(location));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DiscUtils.Udf;
|
||||
using Emby.Naming.Video;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@@ -201,6 +202,22 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
video.IsoType = IsoType.BluRay;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use disc-utils, both DVDs and BDs use UDF filesystem
|
||||
using (var videoFileStream = File.Open(video.Path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
UdfReader udfReader = new UdfReader(videoFileStream);
|
||||
if (udfReader.DirectoryExists("VIDEO_TS"))
|
||||
{
|
||||
video.IsoType = IsoType.Dvd;
|
||||
}
|
||||
else if (udfReader.DirectoryExists("BDMV"))
|
||||
{
|
||||
video.IsoType = IsoType.BluRay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -33,7 +31,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
public Task Record(IDirectStreamProvider directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
public Task Record(IDirectStreamProvider? directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
if (directStreamProvider != null)
|
||||
{
|
||||
@@ -45,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile)));
|
||||
|
||||
// use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 .
|
||||
using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
@@ -71,7 +69,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
_logger.LogInformation("Opened recording stream from tuner provider");
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile)));
|
||||
|
||||
// use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 .
|
||||
await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
|
||||
@@ -159,8 +159,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
try
|
||||
{
|
||||
var recordingFolders = GetRecordingFolders().ToArray();
|
||||
var virtualFolders = _libraryManager.GetVirtualFolders()
|
||||
.ToList();
|
||||
var virtualFolders = _libraryManager.GetVirtualFolders();
|
||||
|
||||
var allExistingPaths = virtualFolders.SelectMany(i => i.Locations).ToList();
|
||||
|
||||
@@ -177,7 +176,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
continue;
|
||||
}
|
||||
|
||||
var mediaPathInfos = pathsToCreate.Select(i => new MediaPathInfo { Path = i }).ToArray();
|
||||
var mediaPathInfos = pathsToCreate.Select(i => new MediaPathInfo(i)).ToArray();
|
||||
|
||||
var libraryOptions = new LibraryOptions
|
||||
{
|
||||
@@ -210,7 +209,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
foreach (var path in pathsToRemove)
|
||||
{
|
||||
await RemovePathFromLibrary(path).ConfigureAwait(false);
|
||||
await RemovePathFromLibraryAsync(path).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -219,13 +218,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RemovePathFromLibrary(string path)
|
||||
private async Task RemovePathFromLibraryAsync(string path)
|
||||
{
|
||||
_logger.LogDebug("Removing path from library: {0}", path);
|
||||
|
||||
var requiresRefresh = false;
|
||||
var virtualFolders = _libraryManager.GetVirtualFolders()
|
||||
.ToList();
|
||||
var virtualFolders = _libraryManager.GetVirtualFolders();
|
||||
|
||||
foreach (var virtualFolder in virtualFolders)
|
||||
{
|
||||
@@ -460,7 +458,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
if (!string.IsNullOrWhiteSpace(tunerChannel.TunerChannelId))
|
||||
{
|
||||
var tunerChannelId = tunerChannel.TunerChannelId;
|
||||
if (tunerChannelId.IndexOf(".json.schedulesdirect.org", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (tunerChannelId.Contains(".json.schedulesdirect.org", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
tunerChannelId = tunerChannelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
|
||||
}
|
||||
@@ -620,8 +618,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
if (existingTimer != null)
|
||||
{
|
||||
if (existingTimer.Status == RecordingStatus.Cancelled ||
|
||||
existingTimer.Status == RecordingStatus.Completed)
|
||||
if (existingTimer.Status == RecordingStatus.Cancelled
|
||||
|| existingTimer.Status == RecordingStatus.Completed)
|
||||
{
|
||||
existingTimer.Status = RecordingStatus.New;
|
||||
existingTimer.IsManual = true;
|
||||
@@ -913,18 +911,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
var epgChannel = await GetEpgChannelFromTunerChannel(provider.Item1, provider.Item2, channel, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
List<ProgramInfo> programs;
|
||||
|
||||
if (epgChannel == null)
|
||||
{
|
||||
_logger.LogDebug("EPG channel not found for tuner channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
|
||||
programs = new List<ProgramInfo>();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
programs = (await provider.Item1.GetProgramsAsync(provider.Item2, epgChannel.Id, startDateUtc, endDateUtc, cancellationToken)
|
||||
|
||||
List<ProgramInfo> programs = (await provider.Item1.GetProgramsAsync(provider.Item2, epgChannel.Id, startDateUtc, endDateUtc, cancellationToken)
|
||||
.ConfigureAwait(false)).ToList();
|
||||
}
|
||||
|
||||
// Replace the value that came from the provider with a normalized value
|
||||
foreach (var program in programs)
|
||||
@@ -940,7 +934,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
}
|
||||
}
|
||||
|
||||
return new List<ProgramInfo>();
|
||||
return Enumerable.Empty<ProgramInfo>();
|
||||
}
|
||||
|
||||
private List<Tuple<IListingsProvider, ListingsProviderInfo>> GetListingProviders()
|
||||
@@ -1292,7 +1286,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
_logger.LogInformation("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
_logger.LogInformation("Writing file to path: " + recordPath);
|
||||
_logger.LogInformation("Writing file to: {Path}", recordPath);
|
||||
|
||||
Action onStarted = async () =>
|
||||
{
|
||||
@@ -1417,13 +1411,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
private void TriggerRefresh(string path)
|
||||
{
|
||||
_logger.LogInformation("Triggering refresh on {path}", path);
|
||||
_logger.LogInformation("Triggering refresh on {Path}", path);
|
||||
|
||||
var item = GetAffectedBaseItem(Path.GetDirectoryName(path));
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
_logger.LogInformation("Refreshing recording parent {path}", item.Path);
|
||||
_logger.LogInformation("Refreshing recording parent {Path}", item.Path);
|
||||
|
||||
_providerManager.QueueRefresh(
|
||||
item.Id,
|
||||
@@ -1512,8 +1506,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
DeleteLibraryItemsForTimers(timersToDelete);
|
||||
|
||||
var librarySeries = _libraryManager.FindByPath(seriesPath, true) as Folder;
|
||||
if (librarySeries == null)
|
||||
if (_libraryManager.FindByPath(seriesPath, true) is not Folder librarySeries)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1667,7 +1660,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
_logger.LogInformation("Running recording post processor {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||
|
||||
process.Exited += Process_Exited;
|
||||
process.Exited += OnProcessExited;
|
||||
process.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1681,7 +1674,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
return arguments.Replace("{path}", path, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void Process_Exited(object sender, EventArgs e)
|
||||
private void OnProcessExited(object sender, EventArgs e)
|
||||
{
|
||||
using (var process = (Process)sender)
|
||||
{
|
||||
@@ -2239,7 +2232,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
var enabledTimersForSeries = new List<TimerInfo>();
|
||||
foreach (var timer in allTimers)
|
||||
{
|
||||
var existingTimer = _timerProvider.GetTimer(timer.Id)
|
||||
var existingTimer = _timerProvider.GetTimer(timer.Id)
|
||||
?? (string.IsNullOrWhiteSpace(timer.ProgramId)
|
||||
? null
|
||||
: _timerProvider.GetTimerByProgramId(timer.ProgramId));
|
||||
|
||||
@@ -319,11 +319,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// TODO Investigate and properly fix.
|
||||
// Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error reading ffmpeg recording log");
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
/// <summary>
|
||||
/// Records the specified media source.
|
||||
/// </summary>
|
||||
Task Record(IDirectStreamProvider directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken);
|
||||
Task Record(IDirectStreamProvider? directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken);
|
||||
|
||||
string GetOutputPath(MediaSourceInfo mediaSource, string targetFile);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -23,7 +21,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
{
|
||||
}
|
||||
|
||||
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
|
||||
public event EventHandler<GenericEventArgs<TimerInfo>>? TimerFired;
|
||||
|
||||
public void RestartTimers()
|
||||
{
|
||||
@@ -145,9 +143,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
}
|
||||
}
|
||||
|
||||
private void TimerCallback(object state)
|
||||
private void TimerCallback(object? state)
|
||||
{
|
||||
var timerId = (string)state;
|
||||
var timerId = (string?)state ?? throw new ArgumentNullException(nameof(state));
|
||||
|
||||
var timer = GetAll().FirstOrDefault(i => string.Equals(i.Id, timerId, StringComparison.OrdinalIgnoreCase));
|
||||
if (timer != null)
|
||||
@@ -156,12 +154,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
}
|
||||
}
|
||||
|
||||
public TimerInfo GetTimer(string id)
|
||||
public TimerInfo? GetTimer(string id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(r => string.Equals(r.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public TimerInfo GetTimerByProgramId(string programId)
|
||||
public TimerInfo? GetTimerByProgramId(string programId)
|
||||
{
|
||||
return GetAll().FirstOrDefault(r => string.Equals(r.ProgramId, programId, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
@@ -295,11 +295,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
}
|
||||
}
|
||||
|
||||
attributes.TryGetValue("tvg-name", out string name);
|
||||
string name = nameInExtInf;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = nameInExtInf;
|
||||
attributes.TryGetValue("tvg-name", out name);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"HeaderLiveTV": "Canlı TV",
|
||||
"HeaderNextUp": "Gelecek Hafta",
|
||||
"HeaderRecordingGroups": "Kayıt Grupları",
|
||||
"HomeVideos": "Ev videoları",
|
||||
"HomeVideos": "Ana sayfa videoları",
|
||||
"Inherit": "Devral",
|
||||
"ItemAddedWithName": "{0} kütüphaneye eklendi",
|
||||
"ItemRemovedWithName": "{0} kütüphaneden silindi",
|
||||
|
||||
@@ -16,6 +16,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: InternalsVisibleTo("Jellyfin.Server.Implementations.Tests")]
|
||||
[assembly: InternalsVisibleTo("Emby.Server.Implementations.Fuzz")]
|
||||
|
||||
// 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
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
||||
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays;
|
||||
if (!retentionDays.HasValue || retentionDays <= 0)
|
||||
if (!retentionDays.HasValue || retentionDays < 0)
|
||||
{
|
||||
throw new Exception($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user