mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* partial episode nfo metadata * nfo metadata reliability fixes * use recyclable memory streamspull/790/head
32 changed files with 531 additions and 120 deletions
@ -1,15 +1,21 @@
@@ -1,15 +1,21 @@
|
||||
using ErsatzTV.Core.Interfaces.Repositories; |
||||
using ErsatzTV.Core.Iptv; |
||||
using Microsoft.IO; |
||||
|
||||
namespace ErsatzTV.Application.Channels; |
||||
|
||||
public class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, ChannelGuide> |
||||
{ |
||||
private readonly IChannelRepository _channelRepository; |
||||
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager; |
||||
|
||||
public GetChannelGuideHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository; |
||||
public GetChannelGuideHandler(IChannelRepository channelRepository, RecyclableMemoryStreamManager recyclableMemoryStreamManager) |
||||
{ |
||||
_channelRepository = channelRepository; |
||||
_recyclableMemoryStreamManager = recyclableMemoryStreamManager; |
||||
} |
||||
|
||||
public Task<ChannelGuide> Handle(GetChannelGuide request, CancellationToken cancellationToken) => |
||||
_channelRepository.GetAllForGuide() |
||||
.Map(channels => new ChannelGuide(request.Scheme, request.Host, channels)); |
||||
.Map(channels => new ChannelGuide(_recyclableMemoryStreamManager, request.Scheme, request.Host, channels)); |
||||
} |
||||
|
||||
@ -1,83 +1,166 @@
@@ -1,83 +1,166 @@
|
||||
using System.Xml; |
||||
using System.Text; |
||||
using System.Text.RegularExpressions; |
||||
using System.Xml; |
||||
using System.Xml.Linq; |
||||
using Microsoft.Extensions.Logging; |
||||
using Microsoft.IO; |
||||
|
||||
namespace ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
public abstract class NfoReader<T> |
||||
{ |
||||
protected static async Task ReadStringContent(XmlReader reader, T nfo, Action<T, string> action) |
||||
{ |
||||
if (nfo != null) |
||||
private static readonly byte[] Buffer = new byte[8 * 1024 * 1024]; |
||||
private static readonly Regex Pattern = new(@"[\p{C}-[\r\n\t]]+"); |
||||
|
||||
protected static readonly XmlReaderSettings Settings = |
||||
new() |
||||
{ |
||||
string result = await reader.ReadElementContentAsStringAsync(); |
||||
action(nfo, result); |
||||
} |
||||
Async = true, |
||||
ConformanceLevel = ConformanceLevel.Fragment, |
||||
ValidationType = ValidationType.None, |
||||
CheckCharacters = false, |
||||
IgnoreProcessingInstructions = true, |
||||
IgnoreComments = true |
||||
}; |
||||
|
||||
private readonly ILogger _logger; |
||||
|
||||
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager; |
||||
|
||||
protected NfoReader(RecyclableMemoryStreamManager recyclableMemoryStreamManager, ILogger logger) |
||||
{ |
||||
_recyclableMemoryStreamManager = recyclableMemoryStreamManager; |
||||
_logger = logger; |
||||
} |
||||
|
||||
protected static async Task ReadIntContent(XmlReader reader, T nfo, Action<T, int> action) |
||||
protected async Task<Stream> SanitizedStreamForFile(string fileName) |
||||
{ |
||||
if (nfo != null && int.TryParse(await reader.ReadElementContentAsStringAsync(), out int result)) |
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, Buffer.Length, true)) |
||||
{ |
||||
action(nfo, result); |
||||
while (await fs.ReadAsync(Buffer) > 0) |
||||
{ |
||||
// read the file
|
||||
} |
||||
|
||||
string text = Encoding.UTF8.GetString(Buffer); |
||||
// trim BOM and zero width space, replace controls with replacement character
|
||||
string stripped = Pattern.Replace(text.Trim('\uFEFF', '\u200B'), "\ufffd"); |
||||
|
||||
MemoryStream ms = _recyclableMemoryStreamManager.GetStream(); |
||||
await ms.WriteAsync(Encoding.UTF8.GetBytes(stripped)); |
||||
ms.Position = 0; |
||||
return ms; |
||||
} |
||||
} |
||||
|
||||
protected static async Task ReadDateTimeContent(XmlReader reader, T nfo, Action<T, DateTime> action) |
||||
protected async Task ReadStringContent(XmlReader reader, T nfo, Action<T, string> action) |
||||
{ |
||||
if (nfo != null && DateTime.TryParse(await reader.ReadElementContentAsStringAsync(), out DateTime result)) |
||||
try |
||||
{ |
||||
action(nfo, result); |
||||
if (nfo != null) |
||||
{ |
||||
string result = await reader.ReadElementContentAsStringAsync(); |
||||
action(nfo, result); |
||||
} |
||||
} |
||||
catch (XmlException ex) |
||||
{ |
||||
_logger.LogWarning(ex, "Error reading string content from NFO {ElementName}", reader.Name); |
||||
} |
||||
} |
||||
|
||||
protected static void ReadActor(XmlReader reader, T nfo, Action<T, ActorNfo> action) |
||||
protected async Task ReadIntContent(XmlReader reader, T nfo, Action<T, int> action) |
||||
{ |
||||
if (nfo != null) |
||||
try |
||||
{ |
||||
var actor = new ActorNfo(); |
||||
var element = (XElement)XNode.ReadFrom(reader); |
||||
|
||||
XElement name = element.Element("name"); |
||||
if (name != null) |
||||
if (nfo != null && int.TryParse(await reader.ReadElementContentAsStringAsync(), out int result)) |
||||
{ |
||||
actor.Name = name.Value; |
||||
action(nfo, result); |
||||
} |
||||
} |
||||
catch (XmlException ex) |
||||
{ |
||||
_logger.LogWarning(ex, "Error reading int content from NFO {ElementName}", reader.Name); |
||||
} |
||||
} |
||||
|
||||
XElement role = element.Element("role"); |
||||
if (role != null) |
||||
protected async Task ReadDateTimeContent(XmlReader reader, T nfo, Action<T, DateTime> action) |
||||
{ |
||||
try |
||||
{ |
||||
if (nfo != null && DateTime.TryParse(await reader.ReadElementContentAsStringAsync(), out DateTime result)) |
||||
{ |
||||
actor.Role = role.Value; |
||||
action(nfo, result); |
||||
} |
||||
} |
||||
catch (XmlException ex) |
||||
{ |
||||
_logger.LogWarning(ex, "Error reading date content from NFO {ElementName}", reader.Name); |
||||
} |
||||
} |
||||
|
||||
XElement order = element.Element("order"); |
||||
if (order != null && int.TryParse(order.Value, out int orderValue)) |
||||
protected void ReadActor(XmlReader reader, T nfo, Action<T, ActorNfo> action) |
||||
{ |
||||
try |
||||
{ |
||||
if (nfo != null) |
||||
{ |
||||
actor.Order = orderValue; |
||||
} |
||||
var actor = new ActorNfo(); |
||||
var element = (XElement)XNode.ReadFrom(reader); |
||||
|
||||
XElement thumb = element.Element("thumb"); |
||||
if (thumb != null) |
||||
{ |
||||
actor.Thumb = thumb.Value; |
||||
} |
||||
XElement name = element.Element("name"); |
||||
if (name != null) |
||||
{ |
||||
actor.Name = name.Value; |
||||
} |
||||
|
||||
XElement role = element.Element("role"); |
||||
if (role != null) |
||||
{ |
||||
actor.Role = role.Value; |
||||
} |
||||
|
||||
action(nfo, actor); |
||||
XElement order = element.Element("order"); |
||||
if (order != null && int.TryParse(order.Value, out int orderValue)) |
||||
{ |
||||
actor.Order = orderValue; |
||||
} |
||||
|
||||
XElement thumb = element.Element("thumb"); |
||||
if (thumb != null) |
||||
{ |
||||
actor.Thumb = thumb.Value; |
||||
} |
||||
|
||||
action(nfo, actor); |
||||
} |
||||
} |
||||
catch (XmlException ex) |
||||
{ |
||||
_logger.LogWarning(ex, "Error reading actor content from NFO {ElementName}", reader.Name); |
||||
} |
||||
} |
||||
|
||||
protected static async Task ReadUniqueId(XmlReader reader, T nfo, Action<T, UniqueIdNfo> action) |
||||
protected async Task ReadUniqueId(XmlReader reader, T nfo, Action<T, UniqueIdNfo> action) |
||||
{ |
||||
if (nfo != null) |
||||
try |
||||
{ |
||||
if (nfo != null) |
||||
{ |
||||
var uniqueId = new UniqueIdNfo(); |
||||
reader.MoveToAttribute("default"); |
||||
uniqueId.Default = bool.TryParse(reader.Value, out bool def) && def; |
||||
reader.MoveToAttribute("type"); |
||||
uniqueId.Type = reader.Value; |
||||
reader.MoveToElement(); |
||||
uniqueId.Guid = await reader.ReadElementContentAsStringAsync(); |
||||
|
||||
action(nfo, uniqueId); |
||||
} |
||||
} |
||||
catch (XmlException ex) |
||||
{ |
||||
var uniqueId = new UniqueIdNfo(); |
||||
reader.MoveToAttribute("default"); |
||||
uniqueId.Default = bool.TryParse(reader.Value, out bool def) && def; |
||||
reader.MoveToAttribute("type"); |
||||
uniqueId.Type = reader.Value; |
||||
reader.MoveToElement(); |
||||
uniqueId.Guid = await reader.ReadElementContentAsStringAsync(); |
||||
|
||||
action(nfo, uniqueId); |
||||
_logger.LogWarning(ex, "Error reading uniqueid content from NFO {ElementName}", reader.Name); |
||||
} |
||||
} |
||||
} |
||||
|
||||
Loading…
Reference in new issue