Feature/persistent watch data (#14262)

This commit is contained in:
JPVenson
2025-06-10 02:14:27 +03:00
committed by GitHub
parent 3554f068fb
commit d3ad2aec60
10 changed files with 1875 additions and 3 deletions

View File

@@ -68,6 +68,11 @@ public class UserData
/// <value><c>null</c> if [likes] contains no value, <c>true</c> if [likes]; otherwise, <c>false</c>.</value>
public bool? Likes { get; set; }
/// <summary>
/// Gets or Sets the date the referenced <see cref="Item"/> has been deleted.
/// </summary>
public DateTimeOffset? RetentionDate { get; set; }
/// <summary>
/// Gets or sets the key.
/// </summary>

View File

@@ -1,3 +1,4 @@
using System;
using Jellyfin.Database.Implementations.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
@@ -53,5 +54,12 @@ public class BaseItemConfiguration : IEntityTypeConfiguration<BaseItemEntity>
builder.HasIndex(e => new { e.IsFolder, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated });
// resume
builder.HasIndex(e => new { e.MediaType, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey });
builder.HasData(new BaseItemEntity()
{
Id = Guid.Parse("00000000-0000-0000-0000-000000000001"),
Type = "PLACEHOLDER",
Name = "This is a placeholder item for UserData that has been detacted from its original item",
});
}
}

View File

@@ -17,6 +17,6 @@ public class UserDataConfiguration : IEntityTypeConfiguration<UserData>
builder.HasIndex(d => new { d.ItemId, d.UserId, d.PlaybackPositionTicks });
builder.HasIndex(d => new { d.ItemId, d.UserId, d.IsFavorite });
builder.HasIndex(d => new { d.ItemId, d.UserId, d.LastPlayedDate });
builder.HasOne(e => e.Item);
builder.HasOne(e => e.Item).WithMany(e => e.UserData);
}
}

View File

@@ -0,0 +1,39 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Jellyfin.Server.Implementations.Migrations
{
/// <inheritdoc />
public partial class DetachUserDataInsteadOfDelete : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTimeOffset>(
name: "RetentionDate",
table: "UserData",
type: "TEXT",
nullable: true);
migrationBuilder.InsertData(
table: "BaseItems",
columns: new[] { "Id", "Album", "AlbumArtists", "Artists", "Audio", "ChannelId", "CleanName", "CommunityRating", "CriticRating", "CustomRating", "Data", "DateCreated", "DateLastMediaAdded", "DateLastRefreshed", "DateLastSaved", "DateModified", "EndDate", "EpisodeTitle", "ExternalId", "ExternalSeriesId", "ExternalServiceId", "ExtraIds", "ExtraType", "ForcedSortName", "Genres", "Height", "IndexNumber", "InheritedParentalRatingSubValue", "InheritedParentalRatingValue", "IsFolder", "IsInMixedFolder", "IsLocked", "IsMovie", "IsRepeat", "IsSeries", "IsVirtualItem", "LUFS", "MediaType", "Name", "NormalizationGain", "OfficialRating", "OriginalTitle", "Overview", "OwnerId", "ParentId", "ParentIndexNumber", "Path", "PreferredMetadataCountryCode", "PreferredMetadataLanguage", "PremiereDate", "PresentationUniqueKey", "PrimaryVersionId", "ProductionLocations", "ProductionYear", "RunTimeTicks", "SeasonId", "SeasonName", "SeriesId", "SeriesName", "SeriesPresentationUniqueKey", "ShowId", "Size", "SortName", "StartDate", "Studios", "Tagline", "Tags", "TopParentId", "TotalBitrate", "Type", "UnratedType", "Width" },
values: new object[] { new Guid("00000000-0000-0000-0000-000000000001"), null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, false, false, false, false, false, false, false, null, null, "This is a placeholder item for UserData that has been detacted from its original item", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "PLACEHOLDER", null, null });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "RetentionDate",
table: "UserData");
migrationBuilder.DeleteData(
table: "BaseItems",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000001"));
}
}
}

View File

@@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.HasAnnotation("ProductVersion", "9.0.5");
modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b =>
{
@@ -392,6 +392,21 @@ namespace Jellyfin.Server.Implementations.Migrations
b.ToTable("BaseItems");
b.HasAnnotation("Sqlite:UseSqlReturningClause", false);
b.HasData(
new
{
Id = new Guid("00000000-0000-0000-0000-000000000001"),
IsFolder = false,
IsInMixedFolder = false,
IsLocked = false,
IsMovie = false,
IsRepeat = false,
IsSeries = false,
IsVirtualItem = false,
Name = "This is a placeholder item for UserData that has been detacted from its original item",
Type = "PLACEHOLDER"
});
});
modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b =>
@@ -1373,6 +1388,9 @@ namespace Jellyfin.Server.Implementations.Migrations
b.Property<double?>("Rating")
.HasColumnType("REAL");
b.Property<DateTimeOffset?>("RetentionDate")
.HasColumnType("TEXT");
b.Property<int?>("SubtitleStreamIndex")
.HasColumnType("INTEGER");