mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-01-16 08:08:16 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
383d514353 | ||
|
|
6fc8237242 | ||
|
|
79d7a4d4df | ||
|
|
e90031b4cc | ||
|
|
4f3d562d75 | ||
|
|
6c8b40f413 | ||
|
|
ec81dc9be2 | ||
|
|
45f3fb1cfc | ||
|
|
f83a24ec43 | ||
|
|
84c03a2d93 | ||
|
|
bc8e249080 | ||
|
|
5ea9a74289 | ||
|
|
987d31ea16 | ||
|
|
f850779781 | ||
|
|
3bdc2bff5f | ||
|
|
5c6a84549a | ||
|
|
48da35f91f | ||
|
|
39b29eb9f1 | ||
|
|
a6740bf51e | ||
|
|
c7797d3ead | ||
|
|
c86d5838be | ||
|
|
43223b9036 | ||
|
|
c71385d2db | ||
|
|
ad5becc524 | ||
|
|
7c75dcfb9c | ||
|
|
7937e31a9b | ||
|
|
1f1f26306b | ||
|
|
577399ca05 | ||
|
|
e7ea7c0383 | ||
|
|
9fe7751d05 | ||
|
|
bf129ab9b8 | ||
|
|
6d23de64c0 | ||
|
|
e4f48bb486 | ||
|
|
866b4460b1 | ||
|
|
9db0b275ff | ||
|
|
14008fd7d0 | ||
|
|
8532d88a71 | ||
|
|
737c739d33 | ||
|
|
679e83082f | ||
|
|
d8e53f35a5 | ||
|
|
7a0e7b3cf8 | ||
|
|
373c63bcc7 | ||
|
|
be5d343efb | ||
|
|
c9c91cc34e | ||
|
|
774b4a0d3f | ||
|
|
23100c9b86 | ||
|
|
8753b7200f |
@@ -36,6 +36,7 @@
|
||||
- [dmitrylyzo](https://github.com/dmitrylyzo)
|
||||
- [DMouse10462](https://github.com/DMouse10462)
|
||||
- [DrPandemic](https://github.com/DrPandemic)
|
||||
- [eglia](https://github.com/eglia)
|
||||
- [EraYaN](https://github.com/EraYaN)
|
||||
- [escabe](https://github.com/escabe)
|
||||
- [excelite](https://github.com/excelite)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Naming</PackageId>
|
||||
<VersionPrefix>10.8.5</VersionPrefix>
|
||||
<VersionPrefix>10.8.8</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1088,15 +1088,7 @@ namespace Emby.Server.Implementations
|
||||
return GetLocalApiUrl(request.Host.Host, request.Scheme, requestPort);
|
||||
}
|
||||
|
||||
// Published server ends with a /
|
||||
if (!string.IsNullOrEmpty(PublishedServerUrl))
|
||||
{
|
||||
// Published server ends with a '/', so we need to remove it.
|
||||
return PublishedServerUrl.Trim('/');
|
||||
}
|
||||
|
||||
string smart = NetManager.GetBindInterface(request, out var port);
|
||||
return GetLocalApiUrl(smart.Trim('/'), request.Scheme, port);
|
||||
return GetSmartApiUrl(request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -3541,6 +3541,13 @@ namespace Emby.Server.Implementations.Data
|
||||
statement?.TryBind("@MinIndexNumber", query.MinIndexNumber.Value);
|
||||
}
|
||||
|
||||
if (query.MinParentAndIndexNumber.HasValue)
|
||||
{
|
||||
whereClauses.Add("((ParentIndexNumber=@MinParentAndIndexNumberParent and IndexNumber>=@MinParentAndIndexNumberIndex) or ParentIndexNumber>@MinParentAndIndexNumberParent)");
|
||||
statement?.TryBind("@MinParentAndIndexNumberParent", query.MinParentAndIndexNumber.Value.ParentIndexNumber);
|
||||
statement?.TryBind("@MinParentAndIndexNumberIndex", query.MinParentAndIndexNumber.Value.IndexNumber);
|
||||
}
|
||||
|
||||
if (query.MinDateCreated.HasValue)
|
||||
{
|
||||
whereClauses.Add("DateCreated>=@MinDateCreated");
|
||||
|
||||
@@ -165,12 +165,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
|
||||
const double DesiredAspect = 2.0 / 3;
|
||||
|
||||
programEntry.PrimaryImage = GetProgramImage(ApiUrl, imagesWithText, DesiredAspect) ??
|
||||
GetProgramImage(ApiUrl, allImages, DesiredAspect);
|
||||
programEntry.PrimaryImage = GetProgramImage(ApiUrl, imagesWithText, DesiredAspect, token) ??
|
||||
GetProgramImage(ApiUrl, allImages, DesiredAspect, token);
|
||||
|
||||
const double WideAspect = 16.0 / 9;
|
||||
|
||||
programEntry.ThumbImage = GetProgramImage(ApiUrl, imagesWithText, WideAspect);
|
||||
programEntry.ThumbImage = GetProgramImage(ApiUrl, imagesWithText, WideAspect, token);
|
||||
|
||||
// Don't supply the same image twice
|
||||
if (string.Equals(programEntry.PrimaryImage, programEntry.ThumbImage, StringComparison.Ordinal))
|
||||
@@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
programEntry.ThumbImage = null;
|
||||
}
|
||||
|
||||
programEntry.BackdropImage = GetProgramImage(ApiUrl, imagesWithoutText, WideAspect);
|
||||
programEntry.BackdropImage = GetProgramImage(ApiUrl, imagesWithoutText, WideAspect, token);
|
||||
|
||||
// programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
||||
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
|
||||
@@ -399,7 +399,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
return info;
|
||||
}
|
||||
|
||||
private static string GetProgramImage(string apiUrl, IEnumerable<ImageDataDto> images, double desiredAspect)
|
||||
private static string GetProgramImage(string apiUrl, IEnumerable<ImageDataDto> images, double desiredAspect, string token)
|
||||
{
|
||||
var match = images
|
||||
.OrderBy(i => Math.Abs(desiredAspect - GetAspectRatio(i)))
|
||||
@@ -423,7 +423,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
}
|
||||
else
|
||||
{
|
||||
return apiUrl + "/image/" + uri;
|
||||
return apiUrl + "/image/" + uri + "?token=" + token;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,6 +457,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
IReadOnlyList<string> programIds,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (programIds.Count == 0)
|
||||
{
|
||||
return Array.Empty<ShowImagesDto>();
|
||||
@@ -478,6 +480,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
{
|
||||
Content = new StringContent(str.ToString(), Encoding.UTF8, MediaTypeNames.Application.Json)
|
||||
};
|
||||
message.Headers.TryAddWithoutValidation("token", token);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -386,6 +386,7 @@ namespace Emby.Server.Implementations.Localization
|
||||
yield return new LocalizationOption("Español (Dominicana)", "es_DO");
|
||||
yield return new LocalizationOption("Español (México)", "es-MX");
|
||||
yield return new LocalizationOption("Eesti", "et");
|
||||
yield return new LocalizationOption("Basque", "eu");
|
||||
yield return new LocalizationOption("فارسی", "fa");
|
||||
yield return new LocalizationOption("Suomi", "fi");
|
||||
yield return new LocalizationOption("Filipino", "fil");
|
||||
|
||||
@@ -192,7 +192,6 @@ namespace Emby.Server.Implementations.TV
|
||||
AncestorWithPresentationUniqueKey = null,
|
||||
SeriesPresentationUniqueKey = seriesKey,
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode },
|
||||
OrderBy = new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) },
|
||||
IsPlayed = true,
|
||||
Limit = 1,
|
||||
ParentIndexNumberNotEquals = 0,
|
||||
@@ -203,11 +202,10 @@ namespace Emby.Server.Implementations.TV
|
||||
}
|
||||
};
|
||||
|
||||
if (rewatching)
|
||||
{
|
||||
// find last watched by date played, not by newest episode watched
|
||||
lastQuery.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) };
|
||||
}
|
||||
// If rewatching is enabled, sort first by date played and then by season and episode numbers
|
||||
lastQuery.OrderBy = rewatching
|
||||
? new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) }
|
||||
: new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) };
|
||||
|
||||
var lastWatchedEpisode = _libraryManager.GetItemList(lastQuery).Cast<Episode>().FirstOrDefault();
|
||||
|
||||
@@ -226,18 +224,16 @@ namespace Emby.Server.Implementations.TV
|
||||
DtoOptions = dtoOptions
|
||||
};
|
||||
|
||||
Episode nextEpisode;
|
||||
if (rewatching)
|
||||
// Locate the next up episode based on the last watched episode's season and episode number
|
||||
var lastWatchedParentIndexNumber = lastWatchedEpisode?.ParentIndexNumber;
|
||||
var lastWatchedIndexNumber = lastWatchedEpisode?.IndexNumberEnd ?? lastWatchedEpisode?.IndexNumber;
|
||||
if (lastWatchedParentIndexNumber.HasValue && lastWatchedIndexNumber.HasValue)
|
||||
{
|
||||
nextQuery.Limit = 2;
|
||||
// get watched episode after most recently watched
|
||||
nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().ElementAtOrDefault(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().FirstOrDefault();
|
||||
nextQuery.MinParentAndIndexNumber = (lastWatchedParentIndexNumber.Value, lastWatchedIndexNumber.Value + 1);
|
||||
}
|
||||
|
||||
var nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().FirstOrDefault();
|
||||
|
||||
if (_configurationManager.Configuration.DisplaySpecialsWithinSeasons)
|
||||
{
|
||||
var consideredEpisodes = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
|
||||
@@ -270,30 +270,13 @@ namespace Jellyfin.Api.Controllers
|
||||
includeItemTypes = new[] { BaseItemKind.Playlist };
|
||||
}
|
||||
|
||||
var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
|
||||
|
||||
bool isInEnabledFolder = Array.IndexOf(user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders), item.Id) != -1
|
||||
// Assume all folders inside an EnabledChannel are enabled
|
||||
|| Array.IndexOf(enabledChannels, item.Id) != -1
|
||||
// Assume all items inside an EnabledChannel are enabled
|
||||
|| Array.IndexOf(enabledChannels, item.ChannelId) != -1;
|
||||
|
||||
var collectionFolders = _libraryManager.GetCollectionFolders(item);
|
||||
foreach (var collectionFolder in collectionFolders)
|
||||
{
|
||||
if (user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id))
|
||||
{
|
||||
isInEnabledFolder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item is not UserRootFolder
|
||||
&& !isInEnabledFolder
|
||||
&& !user.HasPermission(PermissionKind.EnableAllFolders)
|
||||
&& !user.HasPermission(PermissionKind.EnableAllChannels)
|
||||
&& !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase))
|
||||
// api keys can always access all folders
|
||||
&& !ClaimHelpers.GetIsApiKey(User)
|
||||
// check the item is visible for the user
|
||||
&& !item.IsVisible(user))
|
||||
{
|
||||
_logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name);
|
||||
_logger.LogWarning("{UserName} is not permitted to access Library {ItemName}", user!.Username, item.Name);
|
||||
return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}.");
|
||||
}
|
||||
|
||||
|
||||
@@ -492,7 +492,7 @@ namespace Jellyfin.Api.Controllers
|
||||
/// <response code="200">Media folders returned.</response>
|
||||
/// <returns>List of user media folders.</returns>
|
||||
[HttpGet("Library/MediaFolders")]
|
||||
[Authorize(Policy = Policies.DefaultAuthorization)]
|
||||
[Authorize(Policy = Policies.RequiresElevation)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ActionResult<QueryResult<BaseItemDto>> GetMediaFolders([FromQuery] bool? isHidden)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Data</PackageId>
|
||||
<VersionPrefix>10.8.5</VersionPrefix>
|
||||
<VersionPrefix>10.8.8</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
657
Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs
generated
Normal file
657
Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs
generated
Normal file
@@ -0,0 +1,657 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Jellyfin.Server.Implementations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
[DbContext(typeof(JellyfinDb))]
|
||||
[Migration("20221022080052_AddIndexActivityLogsDateCreated")]
|
||||
partial class AddIndexActivityLogsDateCreated
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("jellyfin")
|
||||
.HasAnnotation("ProductVersion", "6.0.9");
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DayOfWeek")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("EndHour")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("StartHour")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AccessSchedules", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ItemId")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("LogSeverity")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ShortOverview")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DateCreated");
|
||||
|
||||
b.ToTable("ActivityLogs", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "ItemId", "Client", "Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CustomItemDisplayPreferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ChromecastVersion")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DashboardTheme")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableNextVideoInfoOverlay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("IndexBy")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ScrollDirection")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ShowBackdrop")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ShowSidebar")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SkipBackwardLength")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SkipForwardLength")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("TvHome")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "ItemId", "Client")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DisplayPreferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DisplayPreferencesId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DisplayPreferencesId");
|
||||
|
||||
b.ToTable("HomeSection", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("LastModified")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ImageInfos", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("IndexBy")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("RememberIndexing")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("RememberSorting")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SortBy")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ViewType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ItemDisplayPreferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("Permission_Permissions_Guid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Value")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "Kind")
|
||||
.IsUnique()
|
||||
.HasFilter("[UserId] IS NOT NULL");
|
||||
|
||||
b.ToTable("Permissions", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("Preference_Preferences_Guid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "Kind")
|
||||
.IsUnique()
|
||||
.HasFilter("[UserId] IS NOT NULL");
|
||||
|
||||
b.ToTable("Preferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("AccessToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DateLastActivity")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AccessToken")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ApiKeys", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("AccessToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AppName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AppVersion")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DateLastActivity")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DateModified")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DeviceId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DeviceName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId");
|
||||
|
||||
b.HasIndex("AccessToken", "DateLastActivity");
|
||||
|
||||
b.HasIndex("DeviceId", "DateLastActivity");
|
||||
|
||||
b.HasIndex("UserId", "DeviceId");
|
||||
|
||||
b.ToTable("Devices", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("CustomName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DeviceId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DeviceOptions", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AudioLanguagePreference")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AuthenticationProviderId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("DisplayCollectionsView")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("DisplayMissingEpisodes")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("EasyPassword")
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableAutoLogin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableLocalPassword")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableNextEpisodeAutoPlay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableUserPreferenceAccess")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("HidePlayedInLatest")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("InternalId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("InvalidLoginAttemptCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastActivityDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastLoginDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("LoginAttemptsBeforeLockout")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("MaxActiveSessions")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("MaxParentalAgeRating")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("MustUpdatePassword")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordResetProviderId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PlayDefaultAudioTrack")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("RememberAudioSelections")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("RememberSubtitleSelections")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("RemoteClientBitrateLimit")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SubtitleLanguagePreference")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SubtitleMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SyncPlayAccess")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT")
|
||||
.UseCollation("NOCASE");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Username")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("AccessSchedules")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("DisplayPreferences")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
|
||||
.WithMany("HomeSections")
|
||||
.HasForeignKey("DisplayPreferencesId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithOne("ProfileImage")
|
||||
.HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("ItemDisplayPreferences")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("Permissions")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("Preferences")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.Navigation("HomeSections");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("AccessSchedules");
|
||||
|
||||
b.Navigation("DisplayPreferences");
|
||||
|
||||
b.Navigation("ItemDisplayPreferences");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
|
||||
b.Navigation("Preferences");
|
||||
|
||||
b.Navigation("ProfileImage");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma warning disable CS1591, SA1601
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
public partial class AddIndexActivityLogsDateCreated : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ActivityLogs_DateCreated",
|
||||
schema: "jellyfin",
|
||||
table: "ActivityLogs",
|
||||
column: "DateCreated");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ActivityLogs_DateCreated",
|
||||
schema: "jellyfin",
|
||||
table: "ActivityLogs");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
[DbContext(typeof(JellyfinDb))]
|
||||
@@ -15,7 +17,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("jellyfin")
|
||||
.HasAnnotation("ProductVersion", "5.0.7");
|
||||
.HasAnnotation("ProductVersion", "6.0.9");
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
{
|
||||
@@ -39,7 +41,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AccessSchedules");
|
||||
b.ToTable("AccessSchedules", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
|
||||
@@ -85,7 +87,9 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ActivityLogs");
|
||||
b.HasIndex("DateCreated");
|
||||
|
||||
b.ToTable("ActivityLogs", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
|
||||
@@ -117,7 +121,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.HasIndex("UserId", "ItemId", "Client", "Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CustomItemDisplayPreferences");
|
||||
b.ToTable("CustomItemDisplayPreferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
@@ -174,7 +178,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.HasIndex("UserId", "ItemId", "Client")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DisplayPreferences");
|
||||
b.ToTable("DisplayPreferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
|
||||
@@ -196,7 +200,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
|
||||
b.HasIndex("DisplayPreferencesId");
|
||||
|
||||
b.ToTable("HomeSection");
|
||||
b.ToTable("HomeSection", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||
@@ -221,7 +225,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ImageInfos");
|
||||
b.ToTable("ImageInfos", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
|
||||
@@ -265,7 +269,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ItemDisplayPreferences");
|
||||
b.ToTable("ItemDisplayPreferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
@@ -296,7 +300,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
.IsUnique()
|
||||
.HasFilter("[UserId] IS NOT NULL");
|
||||
|
||||
b.ToTable("Permissions");
|
||||
b.ToTable("Permissions", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
|
||||
@@ -329,7 +333,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
.IsUnique()
|
||||
.HasFilter("[UserId] IS NOT NULL");
|
||||
|
||||
b.ToTable("Preferences");
|
||||
b.ToTable("Preferences", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b =>
|
||||
@@ -358,7 +362,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.HasIndex("AccessToken")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ApiKeys");
|
||||
b.ToTable("ApiKeys", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b =>
|
||||
@@ -416,7 +420,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
|
||||
b.HasIndex("UserId", "DeviceId");
|
||||
|
||||
b.ToTable("Devices");
|
||||
b.ToTable("Devices", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b =>
|
||||
@@ -437,7 +441,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.HasIndex("DeviceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DeviceOptions");
|
||||
b.ToTable("DeviceOptions", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
@@ -550,7 +554,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.HasIndex("Username")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users");
|
||||
b.ToTable("Users", "jellyfin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Jellyfin.Data.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.ModelConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// FluentAPI configuration for the ActivityLog entity.
|
||||
/// </summary>
|
||||
public class ActivityLogConfiguration : IEntityTypeConfiguration<ActivityLog>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void Configure(EntityTypeBuilder<ActivityLog> builder)
|
||||
{
|
||||
builder.HasIndex(entity => entity.DateCreated);
|
||||
}
|
||||
}
|
||||
@@ -434,11 +434,15 @@ namespace Jellyfin.Server.Extensions
|
||||
options.MapType<TranscodeReason>(() =>
|
||||
new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Enum = Enum.GetNames<TranscodeReason>()
|
||||
.Select(e => new OpenApiString(e))
|
||||
.Cast<IOpenApiAny>()
|
||||
.ToArray()
|
||||
Type = "array",
|
||||
Items = new OpenApiSchema
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Id = nameof(TranscodeReason),
|
||||
Type = ReferenceType.Schema,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Swashbuckle doesn't use JsonOptions to describe responses, so we need to manually describe it.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Jellyfin.Extensions;
|
||||
using Jellyfin.Server.Migrations;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
@@ -8,6 +9,7 @@ using MediaBrowser.Model.ApiClient;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
@@ -56,6 +58,15 @@ namespace Jellyfin.Server.Filters
|
||||
|
||||
context.SchemaGenerator.GenerateSchema(configuration.ConfigurationType, context.SchemaRepository);
|
||||
}
|
||||
|
||||
context.SchemaRepository.AddDefinition(nameof(TranscodeReason), new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Enum = Enum.GetNames<TranscodeReason>()
|
||||
.Select(e => new OpenApiString(e))
|
||||
.Cast<IOpenApiAny>()
|
||||
.ToArray()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Common</PackageId>
|
||||
<VersionPrefix>10.8.5</VersionPrefix>
|
||||
<VersionPrefix>10.8.8</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1863,7 +1863,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
data.PlaybackPositionTicks = 0;
|
||||
}
|
||||
|
||||
data.LastPlayedDate = datePlayed ?? data.LastPlayedDate ?? DateTime.UtcNow;
|
||||
data.LastPlayedDate = datePlayed ?? DateTime.UtcNow;
|
||||
data.Played = true;
|
||||
|
||||
UserDataManager.SaveUserData(user.Id, this, data, UserDataSaveReason.TogglePlayed, CancellationToken.None);
|
||||
|
||||
@@ -205,6 +205,16 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public int? MinIndexNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum ParentIndexNumber and IndexNumber.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It produces this where clause:
|
||||
/// <para>(ParentIndexNumber = X and IndexNumber >= Y) or ParentIndexNumber > X.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public (int ParentIndexNumber, int IndexNumber)? MinParentAndIndexNumber { get; set; }
|
||||
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
public double? MinCriticRating { get; set; }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Controller</PackageId>
|
||||
<VersionPrefix>10.8.5</VersionPrefix>
|
||||
<VersionPrefix>10.8.8</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1415,7 +1415,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
param += " -preset 7";
|
||||
}
|
||||
|
||||
param += " -look_ahead 0";
|
||||
// Only h264_qsv has look_ahead option
|
||||
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param += " -look_ahead 0";
|
||||
}
|
||||
}
|
||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
|
||||
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc)
|
||||
@@ -1453,7 +1457,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
break;
|
||||
|
||||
default:
|
||||
param += " -preset p4";
|
||||
param += " -preset p1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3404,6 +3408,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// map from d3d11va to qsv.
|
||||
mainFilters.Add("hwmap=derive_device=qsv");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert a qsv scaler to sync the decoder surface,
|
||||
// msdk will passthrough this internally.
|
||||
mainFilters.Add("hwmap=derive_device=qsv,scale_qsv");
|
||||
}
|
||||
}
|
||||
|
||||
// hw deint
|
||||
|
||||
@@ -436,9 +436,9 @@ namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
containerSupported = true;
|
||||
|
||||
videoSupported = videoStream != null && profile.SupportsVideoCodec(videoStream.Codec);
|
||||
videoSupported = videoStream == null || profile.SupportsVideoCodec(videoStream.Codec);
|
||||
|
||||
audioSupported = audioStream != null && profile.SupportsAudioCodec(audioStream.Codec);
|
||||
audioSupported = audioStream == null || profile.SupportsAudioCodec(audioStream.Codec);
|
||||
|
||||
if (videoSupported && audioSupported)
|
||||
{
|
||||
@@ -447,18 +447,17 @@ namespace MediaBrowser.Model.Dlna
|
||||
}
|
||||
}
|
||||
|
||||
var list = new List<TranscodeReason>();
|
||||
if (!containerSupported)
|
||||
{
|
||||
reasons |= TranscodeReason.ContainerNotSupported;
|
||||
}
|
||||
|
||||
if (videoStream != null && !videoSupported)
|
||||
if (!videoSupported)
|
||||
{
|
||||
reasons |= TranscodeReason.VideoCodecNotSupported;
|
||||
}
|
||||
|
||||
if (audioStream != null && !audioSupported)
|
||||
if (!audioSupported)
|
||||
{
|
||||
reasons |= TranscodeReason.AudioCodecNotSupported;
|
||||
}
|
||||
@@ -590,21 +589,19 @@ namespace MediaBrowser.Model.Dlna
|
||||
}
|
||||
|
||||
// Collect candidate audio streams
|
||||
IEnumerable<MediaStream> candidateAudioStreams = audioStream == null ? Array.Empty<MediaStream>() : new[] { audioStream };
|
||||
ICollection<MediaStream> candidateAudioStreams = audioStream == null ? Array.Empty<MediaStream>() : new[] { audioStream };
|
||||
if (!options.AudioStreamIndex.HasValue || options.AudioStreamIndex < 0)
|
||||
{
|
||||
if (audioStream?.IsDefault == true)
|
||||
{
|
||||
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault);
|
||||
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language);
|
||||
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
candidateAudioStreams = candidateAudioStreams.ToArray();
|
||||
|
||||
var videoStream = item.VideoStream;
|
||||
|
||||
var directPlayBitrateEligibility = IsBitrateEligibleForDirectPlayback(item, options.GetMaxBitrate(false) ?? 0, options, PlayMethod.DirectPlay);
|
||||
@@ -1060,7 +1057,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
MediaSourceInfo mediaSource,
|
||||
MediaStream videoStream,
|
||||
MediaStream audioStream,
|
||||
IEnumerable<MediaStream> candidateAudioStreams,
|
||||
ICollection<MediaStream> candidateAudioStreams,
|
||||
MediaStream subtitleStream,
|
||||
bool isEligibleForDirectPlay,
|
||||
bool isEligibleForDirectStream)
|
||||
@@ -1182,14 +1179,18 @@ namespace MediaBrowser.Model.Dlna
|
||||
}
|
||||
|
||||
// Check audio codec
|
||||
var selectedAudioStream = candidateAudioStreams.FirstOrDefault(audioStream => directPlayProfile.SupportsAudioCodec(audioStream.Codec));
|
||||
if (selectedAudioStream == null)
|
||||
MediaStream selectedAudioStream = null;
|
||||
if (candidateAudioStreams.Any())
|
||||
{
|
||||
directPlayProfileReasons |= TranscodeReason.AudioCodecNotSupported;
|
||||
}
|
||||
else
|
||||
{
|
||||
audioCodecProfileReasons = audioStreamMatches.GetValueOrDefault(selectedAudioStream);
|
||||
selectedAudioStream = candidateAudioStreams.FirstOrDefault(audioStream => directPlayProfile.SupportsAudioCodec(audioStream.Codec));
|
||||
if (selectedAudioStream == null)
|
||||
{
|
||||
directPlayProfileReasons |= TranscodeReason.AudioCodecNotSupported;
|
||||
}
|
||||
else
|
||||
{
|
||||
audioCodecProfileReasons = audioStreamMatches.GetValueOrDefault(selectedAudioStream);
|
||||
}
|
||||
}
|
||||
|
||||
var failureReasons = directPlayProfileReasons | containerProfileReasons | subtitleProfileReasons;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Model</PackageId>
|
||||
<VersionPrefix>10.8.5</VersionPrefix>
|
||||
<VersionPrefix>10.8.8</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -408,10 +408,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnglishRequested)
|
||||
{
|
||||
item.Overview = result.Plot;
|
||||
}
|
||||
item.Overview = result.Plot;
|
||||
|
||||
if (!Plugin.Instance.Configuration.CastAndCrew)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("10.8.5")]
|
||||
[assembly: AssemblyFileVersion("10.8.5")]
|
||||
[assembly: AssemblyVersion("10.8.8")]
|
||||
[assembly: AssemblyFileVersion("10.8.8")]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# We just wrap `build` so this is really it
|
||||
name: "jellyfin"
|
||||
version: "10.8.5"
|
||||
version: "10.8.8"
|
||||
packages:
|
||||
- debian.amd64
|
||||
- debian.arm64
|
||||
|
||||
18
debian/changelog
vendored
18
debian/changelog
vendored
@@ -1,3 +1,21 @@
|
||||
jellyfin-server (10.8.8-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.8.8; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.8
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 29 Nov 2022 13:42:47 -0500
|
||||
|
||||
jellyfin-server (10.8.7-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.8.7; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.7
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 31 Oct 2022 23:07:06 -0400
|
||||
|
||||
jellyfin-server (10.8.6-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.8.6; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.6
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 28 Oct 2022 22:41:01 -0400
|
||||
|
||||
jellyfin-server (10.8.5-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.8.5; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.5
|
||||
|
||||
2
debian/metapackage/jellyfin
vendored
2
debian/metapackage/jellyfin
vendored
@@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
|
||||
Standards-Version: 3.9.2
|
||||
|
||||
Package: jellyfin
|
||||
Version: 10.8.5
|
||||
Version: 10.8.8
|
||||
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
Depends: jellyfin-server, jellyfin-web
|
||||
Description: Provides the Jellyfin Free Software Media System
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%endif
|
||||
|
||||
Name: jellyfin
|
||||
Version: 10.8.5
|
||||
Version: 10.8.8
|
||||
Release: 1%{?dist}
|
||||
Summary: The Free Software Media System
|
||||
License: GPLv2
|
||||
@@ -176,6 +176,12 @@ fi
|
||||
%systemd_postun_with_restart jellyfin.service
|
||||
|
||||
%changelog
|
||||
* Tue Nov 29 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.8.8; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.8
|
||||
* Mon Oct 31 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.8.7; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.7
|
||||
* Fri Oct 28 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.8.6; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.6
|
||||
* Sat Sep 24 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.8.5; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.5
|
||||
* Sat Aug 13 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Extensions</PackageId>
|
||||
<VersionPrefix>10.8.5</VersionPrefix>
|
||||
<VersionPrefix>10.8.8</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Jellyfin.MediaEncoding.Keyframes.FfProbe;
|
||||
/// </summary>
|
||||
public static class FfProbeKeyframeExtractor
|
||||
{
|
||||
private const string DefaultArguments = "-v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\"";
|
||||
private const string DefaultArguments = "-fflags +genpts -v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\"";
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the keyframes using the ffprobe executable at the specified path.
|
||||
@@ -38,9 +38,28 @@ public static class FfProbeKeyframeExtractor
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
|
||||
process.Start();
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
return ParseStream(process.StandardOutput);
|
||||
return ParseStream(process.StandardOutput);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We do not care if this fails
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
internal static KeyframeData ParseStream(StreamReader reader)
|
||||
@@ -62,12 +81,17 @@ public static class FfProbeKeyframeExtractor
|
||||
var rest = line[(firstComma + 1)..];
|
||||
if (lineType.Equals("packet", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (rest.EndsWith(",K_"))
|
||||
// Split time and flags from the packet line. Example line: packet,7169.079000,K_
|
||||
var secondComma = rest.IndexOf(',');
|
||||
var ptsTime = rest[..secondComma];
|
||||
var flags = rest[(secondComma + 1)..];
|
||||
if (flags.StartsWith("K_"))
|
||||
{
|
||||
// Trim the flags from the packet line. Example line: packet,7169.079000,K_
|
||||
var keyframe = double.Parse(rest[..^3], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture);
|
||||
// Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double.
|
||||
keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond));
|
||||
if (double.TryParse(ptsTime, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var keyframe))
|
||||
{
|
||||
// Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double.
|
||||
keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lineType.Equals("stream", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
Reference in New Issue
Block a user