mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-16 12:40:27 +01:00
Compare commits
1 Commits
renovate/s
...
renovate/s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
259b025dfe |
@@ -61,20 +61,20 @@
|
||||
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageVersion Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
||||
<PackageVersion Include="Serilog.Expressions" Version="5.0.0" />
|
||||
<PackageVersion Include="Serilog.Settings.Configuration" Version="10.0.1" />
|
||||
<PackageVersion Include="Serilog.Settings.Configuration" Version="10.0.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.Async" Version="2.1.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.Graylog" Version="3.1.1" />
|
||||
<PackageVersion Include="SerilogAnalyzer" Version="0.15.0" />
|
||||
<PackageVersion Include="SharpCompress" Version="0.49.1" />
|
||||
<PackageVersion Include="SharpFuzz" Version="2.3.0" />
|
||||
<PackageVersion Include="SharpCompress" Version="0.38.0" />
|
||||
<PackageVersion Include="SharpFuzz" Version="2.2.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="3.119.4" />
|
||||
<PackageVersion Include="SkiaSharp.HarfBuzz" Version="3.119.4" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.4" />
|
||||
<PackageVersion Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<PackageVersion Include="Svg.Skia" Version="3.7.0" />
|
||||
<PackageVersion Include="Svg.Skia" Version="5.1.1" />
|
||||
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="10.2.1" />
|
||||
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.2.1" />
|
||||
<PackageVersion Include="System.Text.Json" Version="10.0.9" />
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"NotificationOptionInstallationFailed": "ಸ್ಥಾಪನ ವೈಫಲ್ಯ",
|
||||
"NotificationOptionNewLibraryContent": "ಹೊಸ ವಿಷಯವನ್ನು ಒಳಗೊಂಡಿದೆ",
|
||||
"NotificationOptionPluginError": "ಪ್ಲಗಿನ್ ವೈಫಲ್ಯ",
|
||||
"NotificationOptionPluginInstalled": "ಪ್ಲಗಿನ್ ಸ್ಥಾಪಿಸಲಾಗಿದೆ",
|
||||
"NotificationOptionPluginInstalled": "ಪ್ಲಗಿನ್ ವೈಫಲ್ಯ",
|
||||
"NotificationOptionPluginUpdateInstalled": "ಪ್ಲಗಿನ್ ನವೀಕರಣವನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ",
|
||||
"NotificationOptionServerRestartRequired": "ಸರ್ವರ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ",
|
||||
"NotificationOptionTaskFailed": "ನಿಗದಿತ ಕಾರ್ಯ ವೈಫಲ್ಯ",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
@@ -13,6 +12,7 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Providers.Books.ComicBookInfo.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SharpCompress.Archives.Zip;
|
||||
|
||||
namespace MediaBrowser.Providers.Books.ComicBookInfo;
|
||||
|
||||
@@ -48,27 +48,35 @@ public class ComicBookInfoProvider : IComicProvider
|
||||
|
||||
try
|
||||
{
|
||||
Stream stream = AsyncFile.OpenRead(path);
|
||||
Stream stream = File.OpenRead(path);
|
||||
|
||||
// not yet async: https://github.com/adamhathcock/sharpcompress/pull/565
|
||||
await using (stream.ConfigureAwait(false))
|
||||
using (var archive = ZipArchive.Open(stream))
|
||||
{
|
||||
var archive = await ZipArchive.CreateAsync(stream, ZipArchiveMode.Read, false, null, cancellationToken).ConfigureAwait(false);
|
||||
await using (archive.ConfigureAwait(false))
|
||||
if (!archive.IsComplete)
|
||||
{
|
||||
if (archive.Comment is null)
|
||||
{
|
||||
_logger.LogInformation("missing ComicBookInfo in archive comment: {Path}", info.Path);
|
||||
return new MetadataResult<Book> { HasMetadata = false };
|
||||
}
|
||||
|
||||
var comicBookMetadata = JsonSerializer.Deserialize<ComicBookInfoFormat>(archive.Comment, JsonDefaults.Options);
|
||||
if (comicBookMetadata is null)
|
||||
{
|
||||
_logger.LogError("ComicBookInfo deserialization failure: {Path}", info.Path);
|
||||
return new MetadataResult<Book> { HasMetadata = false };
|
||||
}
|
||||
|
||||
return SaveMetadata(comicBookMetadata);
|
||||
_logger.LogError("incomplete comic archive: {Path}", info.Path);
|
||||
return new MetadataResult<Book> { HasMetadata = false };
|
||||
}
|
||||
|
||||
var volume = archive.Volumes.First();
|
||||
|
||||
if (volume.Comment is null)
|
||||
{
|
||||
_logger.LogInformation("missing ComicBookInfo in archive comment: {Path}", info.Path);
|
||||
return new MetadataResult<Book> { HasMetadata = false };
|
||||
}
|
||||
|
||||
var comicBookMetadata = JsonSerializer.Deserialize<ComicBookInfoFormat>(volume.Comment, JsonDefaults.Options);
|
||||
|
||||
if (comicBookMetadata is null)
|
||||
{
|
||||
_logger.LogError("ComicBookInfo deserialization failure: {Path}", info.Path);
|
||||
return new MetadataResult<Book> { HasMetadata = false };
|
||||
}
|
||||
|
||||
return SaveMetadata(comicBookMetadata);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -9,7 +9,6 @@ using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SharpCompress.Archives;
|
||||
|
||||
@@ -39,16 +38,16 @@ public class ComicImageProvider : IDynamicImageProvider
|
||||
public string Name => "Comic Book Archive Cover Extractor";
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<DynamicImageResponse> GetImage(BaseItem item, ImageType type, CancellationToken cancellationToken)
|
||||
public Task<DynamicImageResponse> GetImage(BaseItem item, ImageType type, CancellationToken cancellationToken)
|
||||
{
|
||||
var extension = Path.GetExtension(item.Path);
|
||||
|
||||
if (_comicBookExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return await LoadCoverAsync(item, cancellationToken).ConfigureAwait(false);
|
||||
return LoadCover(item);
|
||||
}
|
||||
|
||||
return new DynamicImageResponse { HasImage = false };
|
||||
return Task.FromResult(new DynamicImageResponse { HasImage = false });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -68,8 +67,7 @@ public class ComicImageProvider : IDynamicImageProvider
|
||||
/// with no image if nothing is found.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to check for covers.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private async Task<DynamicImageResponse> LoadCoverAsync(BaseItem item, CancellationToken cancellationToken)
|
||||
private async Task<DynamicImageResponse> LoadCover(BaseItem item)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
@@ -77,22 +75,14 @@ public class ComicImageProvider : IDynamicImageProvider
|
||||
{
|
||||
ImageFormat imageFormat;
|
||||
|
||||
using (Stream stream = AsyncFile.OpenRead(item.Path))
|
||||
using (Stream stream = File.OpenRead(item.Path))
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
var archive = await ArchiveFactory.OpenAsyncArchive(stream, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
await using (archive.ConfigureAwait(false))
|
||||
{
|
||||
// throw exception to log results if no cover is found
|
||||
(var cover, imageFormat) = await FindCoverEntryInArchiveAsync(archive).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("no supported cover found");
|
||||
// throw exception to log results if no cover is found
|
||||
(var cover, imageFormat) = FindCoverEntryInArchive(archive) ?? throw new InvalidOperationException("no supported cover found");
|
||||
|
||||
// copy the cover to memory stream
|
||||
var coverStream = await cover.OpenEntryStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
await using (coverStream.ConfigureAwait(false))
|
||||
{
|
||||
await coverStream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
// copy the cover to memory stream
|
||||
await cover.OpenEntryStream().CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// reset stream position after copying
|
||||
@@ -112,7 +102,7 @@ public class ComicImageProvider : IDynamicImageProvider
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to search.</param>
|
||||
/// <returns>The search result.</returns>
|
||||
private async ValueTask<(IArchiveEntry CoverEntry, ImageFormat ImageFormat)?> FindCoverEntryInArchiveAsync(IAsyncArchive archive)
|
||||
private (IArchiveEntry CoverEntry, ImageFormat ImageFormat)? FindCoverEntryInArchive(IArchive archive)
|
||||
{
|
||||
IArchiveEntry? cover;
|
||||
|
||||
@@ -120,7 +110,7 @@ public class ComicImageProvider : IDynamicImageProvider
|
||||
// in many cases the cover will simply be the first image in the archive
|
||||
foreach (var extension in _coverExtensions)
|
||||
{
|
||||
cover = await archive.EntriesAsync.FirstOrDefaultAsync(e => e.Key == "cover" + extension).ConfigureAwait(false);
|
||||
cover = archive.Entries.FirstOrDefault(e => e.Key == "cover" + extension);
|
||||
|
||||
if (cover is not null)
|
||||
{
|
||||
@@ -130,9 +120,7 @@ public class ComicImageProvider : IDynamicImageProvider
|
||||
}
|
||||
}
|
||||
|
||||
cover = await archive.EntriesAsync.OrderBy(x => x.Key)
|
||||
.FirstOrDefaultAsync(x => _coverExtensions.Contains(Path.GetExtension(x.Key), StringComparison.OrdinalIgnoreCase))
|
||||
.ConfigureAwait(false);
|
||||
cover = archive.Entries.OrderBy(x => x.Key).FirstOrDefault(x => _coverExtensions.Contains(Path.GetExtension(x.Key), StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (cover is not null)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Xml.XPath;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using SharpCompress;
|
||||
|
||||
namespace MediaBrowser.Providers.Books.ComicInfo;
|
||||
|
||||
@@ -40,13 +41,7 @@ public static class ComicInfoReader
|
||||
hasFoundMetadata |= ReadStringInto(xml, "ComicInfo/Summary", summary => book.Overview = summary);
|
||||
hasFoundMetadata |= ReadIntInto(xml, "ComicInfo/Year", year => book.ProductionYear = year);
|
||||
hasFoundMetadata |= ReadThreePartDateInto(xml, "ComicInfo/Year", "ComicInfo/Month", "ComicInfo/Day", dateTime => book.PremiereDate = dateTime);
|
||||
hasFoundMetadata |= ReadCommaSeparatedStringsInto(xml, "ComicInfo/Genre", genres =>
|
||||
{
|
||||
foreach (var genre in genres)
|
||||
{
|
||||
book.AddGenre(genre);
|
||||
}
|
||||
});
|
||||
hasFoundMetadata |= ReadCommaSeparatedStringsInto(xml, "ComicInfo/Genre", genres => genres.ForEach(genre => book.AddGenre(genre)));
|
||||
hasFoundMetadata |= ReadStringInto(xml, "ComicInfo/Publisher", publisher => book.SetStudios([publisher]));
|
||||
|
||||
hasFoundMetadata |= ReadStringInto(xml, "ComicInfo/AlternateSeries", title =>
|
||||
@@ -76,50 +71,32 @@ public static class ComicInfoReader
|
||||
{
|
||||
ReadCommaSeparatedStringsInto(xml, "ComicInfo/Writer", authors =>
|
||||
{
|
||||
foreach (var p in authors)
|
||||
{
|
||||
metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Author });
|
||||
}
|
||||
authors.ForEach(p => metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Author }));
|
||||
});
|
||||
|
||||
ReadCommaSeparatedStringsInto(xml, "ComicInfo/Penciller", pencillers =>
|
||||
{
|
||||
foreach (var p in pencillers)
|
||||
{
|
||||
metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Penciller });
|
||||
}
|
||||
pencillers.ForEach(p => metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Penciller }));
|
||||
});
|
||||
|
||||
ReadCommaSeparatedStringsInto(xml, "ComicInfo/Inker", inkers =>
|
||||
{
|
||||
foreach (var p in inkers)
|
||||
{
|
||||
metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Inker });
|
||||
}
|
||||
inkers.ForEach(p => metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Inker }));
|
||||
});
|
||||
|
||||
ReadCommaSeparatedStringsInto(xml, "ComicInfo/Letterer", letterers =>
|
||||
{
|
||||
foreach (var p in letterers)
|
||||
{
|
||||
metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Letterer });
|
||||
}
|
||||
letterers.ForEach(p => metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Letterer }));
|
||||
});
|
||||
|
||||
ReadCommaSeparatedStringsInto(xml, "ComicInfo/CoverArtist", artists =>
|
||||
{
|
||||
foreach (var p in artists)
|
||||
{
|
||||
metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.CoverArtist });
|
||||
}
|
||||
artists.ForEach(p => metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.CoverArtist }));
|
||||
});
|
||||
|
||||
ReadCommaSeparatedStringsInto(xml, "ComicInfo/Colourist", colorists =>
|
||||
{
|
||||
foreach (var p in colorists)
|
||||
{
|
||||
metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Colorist });
|
||||
}
|
||||
colorists.ForEach(p => metadataResult.AddPerson(new PersonInfo { Name = p, Type = PersonKind.Colorist }));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
Reference in New Issue
Block a user