mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* plex api cleanup * improve plex movie scanner * sync plex collections as tags * improve plex tv library scanner * update dependencies * fix plex season and episode collection tagspull/748/head
31 changed files with 5079 additions and 374 deletions
@ -0,0 +1,7 @@ |
|||||||
|
namespace ErsatzTV.Core.Plex; |
||||||
|
|
||||||
|
public class PlexItemEtag |
||||||
|
{ |
||||||
|
public string Key { get; set; } |
||||||
|
public string Etag { get; set; } |
||||||
|
} |
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@ |
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Migrations |
||||||
|
{ |
||||||
|
public partial class Add_PlexEtags : Migration |
||||||
|
{ |
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<string>( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexShow", |
||||||
|
type: "TEXT", |
||||||
|
nullable: true); |
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexSeason", |
||||||
|
type: "TEXT", |
||||||
|
nullable: true); |
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexMovie", |
||||||
|
type: "TEXT", |
||||||
|
nullable: true); |
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexEpisode", |
||||||
|
type: "TEXT", |
||||||
|
nullable: true); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexShow"); |
||||||
|
|
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexSeason"); |
||||||
|
|
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexMovie"); |
||||||
|
|
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "Etag", |
||||||
|
table: "PlexEpisode"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
using System.Xml.Serialization; |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Plex.Models; |
||||||
|
|
||||||
|
public class PlexCollectionResponse |
||||||
|
{ |
||||||
|
[XmlAttribute("id")] |
||||||
|
public int Id { get; set; } |
||||||
|
|
||||||
|
[XmlAttribute("tag")] |
||||||
|
public string Tag { get; set; } |
||||||
|
} |
||||||
@ -0,0 +1,244 @@ |
|||||||
|
using System.Security.Cryptography; |
||||||
|
using ErsatzTV.Infrastructure.Plex.Models; |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Plex; |
||||||
|
|
||||||
|
public static class PlexEtag |
||||||
|
{ |
||||||
|
public static string ForMovie(PlexMetadataResponse response) |
||||||
|
{ |
||||||
|
using var ms = new MemoryStream(); |
||||||
|
using var bw = new BinaryWriter(ms); |
||||||
|
|
||||||
|
// video key
|
||||||
|
bw.Write(response.Key); |
||||||
|
|
||||||
|
// video added at
|
||||||
|
bw.Write(response.AddedAt); |
||||||
|
|
||||||
|
// video updated at
|
||||||
|
bw.Write(response.UpdatedAt); |
||||||
|
|
||||||
|
foreach (PlexMediaResponse<PlexPartResponse> media in response.Media) |
||||||
|
{ |
||||||
|
// media id
|
||||||
|
bw.Write((byte)FieldKey.MediaId); |
||||||
|
bw.Write(media.Id); |
||||||
|
|
||||||
|
// media part id
|
||||||
|
foreach (PlexPartResponse part in media.Part) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.PartId); |
||||||
|
bw.Write(part.Id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// genre ids
|
||||||
|
foreach (PlexGenreResponse genre in Optional(response.Genre).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.GenreTag); |
||||||
|
bw.Write(genre.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// director ids
|
||||||
|
foreach (PlexDirectorResponse director in Optional(response.Director).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.DirectorTag); |
||||||
|
bw.Write(director.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// writer ids
|
||||||
|
foreach (PlexWriterResponse writer in Optional(response.Writer).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.WriterTag); |
||||||
|
bw.Write(writer.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// collection ids
|
||||||
|
foreach (PlexCollectionResponse collection in Optional(response.Collection).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.CollectionTag); |
||||||
|
bw.Write(collection.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// role ids
|
||||||
|
foreach (PlexRoleResponse role in Optional(response.Role).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.RoleTag); |
||||||
|
bw.Write(role.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
ms.Position = 0; |
||||||
|
byte[] hash = SHA1.Create().ComputeHash(ms); |
||||||
|
return BitConverter.ToString(hash).Replace("-", string.Empty); |
||||||
|
} |
||||||
|
|
||||||
|
public static string ForShow(PlexMetadataResponse response) |
||||||
|
{ |
||||||
|
using var ms = new MemoryStream(); |
||||||
|
using var bw = new BinaryWriter(ms); |
||||||
|
|
||||||
|
// video key
|
||||||
|
bw.Write(response.Key); |
||||||
|
|
||||||
|
// video added at
|
||||||
|
bw.Write(response.AddedAt); |
||||||
|
|
||||||
|
// video updated at
|
||||||
|
bw.Write(response.UpdatedAt); |
||||||
|
|
||||||
|
// genre ids
|
||||||
|
foreach (PlexGenreResponse genre in Optional(response.Genre).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.GenreTag); |
||||||
|
bw.Write(genre.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// collection ids
|
||||||
|
foreach (PlexCollectionResponse collection in Optional(response.Collection).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.CollectionTag); |
||||||
|
bw.Write(collection.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// role ids
|
||||||
|
foreach (PlexRoleResponse role in Optional(response.Role).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.RoleTag); |
||||||
|
bw.Write(role.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
ms.Position = 0; |
||||||
|
byte[] hash = SHA1.Create().ComputeHash(ms); |
||||||
|
return BitConverter.ToString(hash).Replace("-", string.Empty); |
||||||
|
} |
||||||
|
|
||||||
|
public static string ForSeason(PlexXmlMetadataResponse response) |
||||||
|
{ |
||||||
|
using var ms = new MemoryStream(); |
||||||
|
using var bw = new BinaryWriter(ms); |
||||||
|
|
||||||
|
// video key
|
||||||
|
bw.Write(response.Key); |
||||||
|
|
||||||
|
// video added at
|
||||||
|
bw.Write(response.AddedAt); |
||||||
|
|
||||||
|
// video updated at
|
||||||
|
bw.Write(response.UpdatedAt); |
||||||
|
|
||||||
|
// collection ids
|
||||||
|
foreach (PlexCollectionResponse collection in Optional(response.Collection).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.CollectionTag); |
||||||
|
bw.Write(collection.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// thumb
|
||||||
|
if (!string.IsNullOrWhiteSpace(response.Thumb)) |
||||||
|
{ |
||||||
|
bw.Write(response.Thumb); |
||||||
|
} |
||||||
|
|
||||||
|
// art
|
||||||
|
if (!string.IsNullOrWhiteSpace(response.Art)) |
||||||
|
{ |
||||||
|
bw.Write(response.Art); |
||||||
|
} |
||||||
|
|
||||||
|
ms.Position = 0; |
||||||
|
byte[] hash = SHA1.Create().ComputeHash(ms); |
||||||
|
return BitConverter.ToString(hash).Replace("-", string.Empty); |
||||||
|
} |
||||||
|
|
||||||
|
public static string ForEpisode(PlexXmlMetadataResponse response) |
||||||
|
{ |
||||||
|
using var ms = new MemoryStream(); |
||||||
|
using var bw = new BinaryWriter(ms); |
||||||
|
|
||||||
|
// video key
|
||||||
|
bw.Write(response.Key); |
||||||
|
|
||||||
|
// video added at
|
||||||
|
bw.Write(response.AddedAt); |
||||||
|
|
||||||
|
// video updated at
|
||||||
|
bw.Write(response.UpdatedAt); |
||||||
|
|
||||||
|
foreach (PlexMediaResponse<PlexXmlPartResponse> media in response.Media) |
||||||
|
{ |
||||||
|
// media id
|
||||||
|
bw.Write((byte)FieldKey.MediaId); |
||||||
|
bw.Write(media.Id); |
||||||
|
|
||||||
|
// media part id
|
||||||
|
foreach (PlexXmlPartResponse part in media.Part) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.PartId); |
||||||
|
bw.Write(part.Id); |
||||||
|
|
||||||
|
// media part id
|
||||||
|
foreach (PlexStreamResponse stream in part.Stream) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.StreamId); |
||||||
|
bw.Write(stream.Id); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// genre ids
|
||||||
|
foreach (PlexGenreResponse genre in Optional(response.Genre).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.GenreTag); |
||||||
|
bw.Write(genre.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// director ids
|
||||||
|
foreach (PlexDirectorResponse director in Optional(response.Director).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.DirectorTag); |
||||||
|
bw.Write(director.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// writer ids
|
||||||
|
foreach (PlexWriterResponse writer in Optional(response.Writer).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.WriterTag); |
||||||
|
bw.Write(writer.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// collection ids
|
||||||
|
foreach (PlexCollectionResponse collection in Optional(response.Collection).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.CollectionTag); |
||||||
|
bw.Write(collection.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
// role ids
|
||||||
|
foreach (PlexRoleResponse role in Optional(response.Role).Flatten()) |
||||||
|
{ |
||||||
|
bw.Write((byte)FieldKey.RoleTag); |
||||||
|
bw.Write(role.Tag); |
||||||
|
} |
||||||
|
|
||||||
|
ms.Position = 0; |
||||||
|
byte[] hash = SHA1.Create().ComputeHash(ms); |
||||||
|
return BitConverter.ToString(hash).Replace("-", string.Empty); |
||||||
|
} |
||||||
|
|
||||||
|
private enum FieldKey : byte |
||||||
|
{ |
||||||
|
MediaId = 0, |
||||||
|
PartId = 1, |
||||||
|
StreamId = 2, |
||||||
|
|
||||||
|
GenreTag = 10, |
||||||
|
DirectorTag = 11, |
||||||
|
WriterTag = 12, |
||||||
|
CollectionTag = 13, |
||||||
|
RoleTag = 14, |
||||||
|
|
||||||
|
Thumb = 20, |
||||||
|
Art = 21 |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
#! /usr/bin/env bash |
||||||
|
|
||||||
|
cd "$(git rev-parse --show-cdup)" || exit |
||||||
|
|
||||||
|
dotnet tool restore |
||||||
|
dotnet jb cleanupcode ErsatzTV.sln --exclude='CHANGELOG.md;scripts/**;generated/**;ErsatzTV/client-app/**' |
||||||
Loading…
Reference in new issue