Stream custom live channels using your own media
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

346 lines
9.7 KiB

using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using ErsatzTV.Infrastructure.Plex.Models;
using Microsoft.IO;
namespace ErsatzTV.Infrastructure.Plex;
[SuppressMessage("Security", "CA5350:Do Not Use Weak Cryptographic Algorithms")]
public class PlexEtag
{
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
public PlexEtag(RecyclableMemoryStreamManager recyclableMemoryStreamManager) =>
_recyclableMemoryStreamManager = recyclableMemoryStreamManager;
public string ForMovie(PlexMetadataResponse response)
{
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
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.Key);
bw.Write(part.Key);
bw.Write((byte)FieldKey.PartId);
bw.Write(part.Id);
bw.Write((byte)FieldKey.File);
bw.Write(part.File);
bw.Write((byte)FieldKey.Duration);
bw.Write(part.Duration);
bw.Write((byte)FieldKey.Size);
bw.Write(part.Size);
bw.Write((byte)FieldKey.Container);
bw.Write(part.Container ?? string.Empty);
bw.Write((byte)FieldKey.VideoProfile);
bw.Write(part.VideoProfile ?? string.Empty);
bw.Write((byte)FieldKey.AudioProfile);
bw.Write(part.AudioProfile ?? string.Empty);
}
}
// genre ids
foreach (PlexGenreResponse genre in Optional(response.Genre).Flatten())
{
bw.Write((byte)FieldKey.GenreTag);
bw.Write(genre.Tag);
}
// label ids
foreach (PlexLabelResponse label in Optional(response.Label).Flatten())
{
bw.Write((byte)FieldKey.LabelTag);
bw.Write(label.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 string ForShow(PlexMetadataResponse response)
{
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
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);
}
// label ids
foreach (PlexLabelResponse label in Optional(response.Label).Flatten())
{
bw.Write((byte)FieldKey.LabelTag);
bw.Write(label.Tag);
}
ms.Position = 0;
byte[] hash = SHA1.Create().ComputeHash(ms);
return BitConverter.ToString(hash).Replace("-", string.Empty);
}
public string ForSeason(PlexXmlMetadataResponse response)
{
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
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 string ForEpisode(PlexXmlMetadataResponse response)
{
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
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.Key);
bw.Write(part.Key);
bw.Write((byte)FieldKey.PartId);
bw.Write(part.Id);
bw.Write((byte)FieldKey.File);
bw.Write(part.File);
bw.Write((byte)FieldKey.Duration);
bw.Write(part.Duration);
bw.Write((byte)FieldKey.Size);
bw.Write(part.Size);
bw.Write((byte)FieldKey.Container);
bw.Write(part.Container ?? string.Empty);
bw.Write((byte)FieldKey.VideoProfile);
bw.Write(part.VideoProfile ?? string.Empty);
bw.Write((byte)FieldKey.AudioProfile);
bw.Write(part.AudioProfile ?? string.Empty);
// stream 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);
}
public string ForCollection(PlexCollectionMetadataResponse response)
{
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
using var bw = new BinaryWriter(ms);
// collection key
bw.Write(response.Key);
// collection added at
bw.Write(response.AddedAt);
// collection updated at
bw.Write(response.UpdatedAt);
// collection child count
bw.Write(response.ChildCount);
// collection is smart collection
bw.Write(response.Smart ?? "0");
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,
LabelTag = 15,
Thumb = 20,
Art = 21,
File = 30,
Key = 31,
ChildCount = 40,
Smart = 41, // smart collection bool
Duration = 50,
Size = 51,
Container = 52,
VideoProfile = 53,
AudioProfile = 54
}
}