mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-07 10:14:13 -04:00
Creating a registerr subtitle task
This commit is contained in:
parent
f71ae0385c
commit
e66e59cf32
@ -1,5 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
@ -12,10 +13,21 @@ namespace Kyoo.Controllers
|
|||||||
/// Identify a path and return the parsed metadata.
|
/// Identify a path and return the parsed metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path of the episode file to parse.</param>
|
/// <param name="path">The path of the episode file to parse.</param>
|
||||||
|
/// <exception cref="IdentificationFailed">The identifier could not work for the given path.</exception>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// A tuple of models representing parsed metadata.
|
/// A tuple of models representing parsed metadata.
|
||||||
/// If no metadata could be parsed for a type, null can be returned.
|
/// If no metadata could be parsed for a type, null can be returned.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
Task<(Collection, Show, Season, Episode)> Identify(string path);
|
Task<(Collection, Show, Season, Episode)> Identify(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identify an external subtitle or track file from it's path and return the parsed metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the external track file to parse.</param>
|
||||||
|
/// <exception cref="IdentificationFailed">The identifier could not work for the given path.</exception>
|
||||||
|
/// <returns>
|
||||||
|
/// The metadata of the track identified.
|
||||||
|
/// </returns>
|
||||||
|
Task<Track> IdentifyTrack(string path);
|
||||||
}
|
}
|
||||||
}
|
}
|
37
Kyoo.Common/Models/Exceptions/IdentificationFailed.cs
Normal file
37
Kyoo.Common/Models/Exceptions/IdentificationFailed.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
|
||||||
|
namespace Kyoo.Models.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An exception raised when an <see cref="IIdentifier"/> failed.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class IdentificationFailed : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="IdentificationFailed"/> with a default message.
|
||||||
|
/// </summary>
|
||||||
|
public IdentificationFailed()
|
||||||
|
: base("An identification failed.")
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="IdentificationFailed"/> with a custom message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to use.</param>
|
||||||
|
public IdentificationFailed(string message)
|
||||||
|
: base(message)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The serialization constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">Serialization infos</param>
|
||||||
|
/// <param name="context">The serialization context</param>
|
||||||
|
protected IdentificationFailed(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,9 @@ using System.IO;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
using Kyoo.Models.Options;
|
using Kyoo.Models.Options;
|
||||||
using Microsoft.Extensions.Logging;
|
using Kyoo.Models.Watch;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
@ -18,23 +19,16 @@ namespace Kyoo.Controllers
|
|||||||
/// The configuration of kyoo to retrieve the identifier regex.
|
/// The configuration of kyoo to retrieve the identifier regex.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IOptions<MediaOptions> _configuration;
|
private readonly IOptions<MediaOptions> _configuration;
|
||||||
/// <summary>
|
|
||||||
/// A logger to print errors.
|
|
||||||
/// </summary>
|
|
||||||
private readonly ILogger<RegexIdentifier> _logger;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="RegexIdentifier"/>.
|
/// Create a new <see cref="RegexIdentifier"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configuration">The regex patterns to use.</param>
|
/// <param name="configuration">The regex patterns to use.</param>
|
||||||
/// <param name="logger">The logger to use.</param>
|
public RegexIdentifier(IOptions<MediaOptions> configuration)
|
||||||
public RegexIdentifier(IOptions<MediaOptions> configuration, ILogger<RegexIdentifier> logger)
|
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<(Collection, Show, Season, Episode)> Identify(string path)
|
public Task<(Collection, Show, Season, Episode)> Identify(string path)
|
||||||
{
|
{
|
||||||
@ -42,10 +36,7 @@ namespace Kyoo.Controllers
|
|||||||
Match match = regex.Match(path);
|
Match match = regex.Match(path);
|
||||||
|
|
||||||
if (!match.Success)
|
if (!match.Success)
|
||||||
{
|
throw new IdentificationFailed($"The episode at {path} does not match the episode's regex.");
|
||||||
_logger.LogError("The episode at {Path} does not match the episode's regex", path);
|
|
||||||
return Task.FromResult<(Collection, Show, Season, Episode)>(default);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Collection collection, Show show, Season season, Episode episode) ret = new();
|
(Collection collection, Show show, Season season, Episode episode) ret = new();
|
||||||
|
|
||||||
@ -81,5 +72,31 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
return Task.FromResult(ret);
|
return Task.FromResult(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<Track> IdentifyTrack(string path)
|
||||||
|
{
|
||||||
|
Regex regex = new(_configuration.Value.SubtitleRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
Match match = regex.Match(path);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
throw new IdentificationFailed($"The subtitle at {path} does not match the subtitle's regex.");
|
||||||
|
|
||||||
|
string episodePath = match.Groups["Episode"].Value;
|
||||||
|
return Task.FromResult(new Track
|
||||||
|
{
|
||||||
|
Type = StreamType.Subtitle,
|
||||||
|
Language = match.Groups["Language"].Value,
|
||||||
|
IsDefault = match.Groups["Default"].Value.Length > 0,
|
||||||
|
IsForced = match.Groups["Forced"].Value.Length > 0,
|
||||||
|
Codec = FileExtensions.SubtitleExtensions[Path.GetExtension(path)],
|
||||||
|
IsExternal = true,
|
||||||
|
Path = path,
|
||||||
|
Episode = new Episode
|
||||||
|
{
|
||||||
|
Path = episodePath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
53
Kyoo/Models/FileExtensions.cs
Normal file
53
Kyoo/Models/FileExtensions.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Kyoo.Models.Watch
|
||||||
|
{
|
||||||
|
public static class FileExtensions
|
||||||
|
{
|
||||||
|
public static readonly string[] VideoExtensions =
|
||||||
|
{
|
||||||
|
".webm",
|
||||||
|
".mkv",
|
||||||
|
".flv",
|
||||||
|
".vob",
|
||||||
|
".ogg",
|
||||||
|
".ogv",
|
||||||
|
".avi",
|
||||||
|
".mts",
|
||||||
|
".m2ts",
|
||||||
|
".ts",
|
||||||
|
".mov",
|
||||||
|
".qt",
|
||||||
|
".asf",
|
||||||
|
".mp4",
|
||||||
|
".m4p",
|
||||||
|
".m4v",
|
||||||
|
".mpg",
|
||||||
|
".mp2",
|
||||||
|
".mpeg",
|
||||||
|
".mpe",
|
||||||
|
".mpv",
|
||||||
|
".m2v",
|
||||||
|
".3gp",
|
||||||
|
".3g2"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool IsVideo(string filePath)
|
||||||
|
{
|
||||||
|
return VideoExtensions.Contains(Path.GetExtension(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, string> SubtitleExtensions = new()
|
||||||
|
{
|
||||||
|
{".ass", "ass"},
|
||||||
|
{".str", "subrip"}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool IsSubtitle(string filePath)
|
||||||
|
{
|
||||||
|
return SubtitleExtensions.ContainsKey(Path.GetExtension(filePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Kyoo.Models
|
|
||||||
{
|
|
||||||
public class LazyDi<T> : Lazy<T>
|
|
||||||
{
|
|
||||||
public LazyDi(IServiceProvider provider)
|
|
||||||
: base(provider.GetRequiredService<T>)
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,13 +3,11 @@ using Kyoo.Models;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models.Attributes;
|
using Kyoo.Models.Attributes;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Watch;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Kyoo.Tasks
|
namespace Kyoo.Tasks
|
||||||
@ -86,6 +84,7 @@ namespace Kyoo.Tasks
|
|||||||
float percent = 0;
|
float percent = 0;
|
||||||
|
|
||||||
ICollection<Episode> episodes = await LibraryManager.GetAll<Episode>();
|
ICollection<Episode> episodes = await LibraryManager.GetAll<Episode>();
|
||||||
|
ICollection<Track> tracks = await LibraryManager.GetAll<Track>();
|
||||||
foreach (Library library in libraries)
|
foreach (Library library in libraries)
|
||||||
{
|
{
|
||||||
IProgress<float> reporter = new Progress<float>(x =>
|
IProgress<float> reporter = new Progress<float>(x =>
|
||||||
@ -93,7 +92,7 @@ namespace Kyoo.Tasks
|
|||||||
// ReSharper disable once AccessToModifiedClosure
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
progress.Report(percent + x / libraries.Count);
|
progress.Report(percent + x / libraries.Count);
|
||||||
});
|
});
|
||||||
await Scan(library, episodes, reporter, cancellationToken);
|
await Scan(library, episodes, tracks, reporter, cancellationToken);
|
||||||
percent += 100f / libraries.Count;
|
percent += 100f / libraries.Count;
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
@ -105,6 +104,7 @@ namespace Kyoo.Tasks
|
|||||||
|
|
||||||
private async Task Scan(Library library,
|
private async Task Scan(Library library,
|
||||||
IEnumerable<Episode> episodes,
|
IEnumerable<Episode> episodes,
|
||||||
|
IEnumerable<Track> tracks,
|
||||||
IProgress<float> progress,
|
IProgress<float> progress,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -120,19 +120,20 @@ namespace Kyoo.Tasks
|
|||||||
// This speeds up the scan process because further episodes of a show are registered when all metadata
|
// This speeds up the scan process because further episodes of a show are registered when all metadata
|
||||||
// of the show has already been fetched.
|
// of the show has already been fetched.
|
||||||
List<IGrouping<string, string>> shows = files
|
List<IGrouping<string, string>> shows = files
|
||||||
.Where(IsVideo)
|
.Where(FileExtensions.IsVideo)
|
||||||
.Where(x => episodes.All(y => y.Path != x))
|
.Where(x => episodes.All(y => y.Path != x))
|
||||||
.GroupBy(Path.GetDirectoryName)
|
.GroupBy(Path.GetDirectoryName)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
string[] paths = shows.Select(x => x.First())
|
string[] paths = shows.Select(x => x.First())
|
||||||
.Concat(shows.SelectMany(x => x.Skip(1)))
|
.Concat(shows.SelectMany(x => x.Skip(1)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
float percent = 0;
|
float percent = 0;
|
||||||
IProgress<float> reporter = new Progress<float>(x =>
|
IProgress<float> reporter = new Progress<float>(x =>
|
||||||
{
|
{
|
||||||
// ReSharper disable once AccessToModifiedClosure
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
progress.Report((percent + x / paths.Length) / library.Paths.Length);
|
progress.Report((percent + x / paths.Length - 10) / library.Paths.Length);
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (string episodePath in paths)
|
foreach (string episodePath in paths)
|
||||||
@ -145,53 +146,27 @@ namespace Kyoo.Tasks
|
|||||||
percent += 100f / paths.Length;
|
percent += 100f / paths.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// await Task.WhenAll(files.Where(x => IsSubtitle(x) && tracks.All(y => y.Path != x))
|
|
||||||
// .Select(x => RegisterExternalSubtitle(x, cancellationToken)));
|
string[] subtitles = files
|
||||||
|
.Where(FileExtensions.IsSubtitle)
|
||||||
|
.Where(x => tracks.All(y => y.Path != x))
|
||||||
|
.ToArray();
|
||||||
|
percent = 0;
|
||||||
|
reporter = new Progress<float>(x =>
|
||||||
|
{
|
||||||
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
|
progress.Report((90 + (percent + x / subtitles.Length)) / library.Paths.Length);
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (string trackPath in subtitles)
|
||||||
|
{
|
||||||
|
TaskManager.StartTask<RegisterSubtitle>(reporter, new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["path"] = trackPath
|
||||||
|
}, cancellationToken);
|
||||||
|
percent += 100f / subtitles.Length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] VideoExtensions =
|
|
||||||
{
|
|
||||||
".webm",
|
|
||||||
".mkv",
|
|
||||||
".flv",
|
|
||||||
".vob",
|
|
||||||
".ogg",
|
|
||||||
".ogv",
|
|
||||||
".avi",
|
|
||||||
".mts",
|
|
||||||
".m2ts",
|
|
||||||
".ts",
|
|
||||||
".mov",
|
|
||||||
".qt",
|
|
||||||
".asf",
|
|
||||||
".mp4",
|
|
||||||
".m4p",
|
|
||||||
".m4v",
|
|
||||||
".mpg",
|
|
||||||
".mp2",
|
|
||||||
".mpeg",
|
|
||||||
".mpe",
|
|
||||||
".mpv",
|
|
||||||
".m2v",
|
|
||||||
".3gp",
|
|
||||||
".3g2"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static bool IsVideo(string filePath)
|
|
||||||
{
|
|
||||||
return VideoExtensions.Contains(Path.GetExtension(filePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> SubtitleExtensions = new()
|
|
||||||
{
|
|
||||||
{".ass", "ass"},
|
|
||||||
{".str", "subrip"}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static bool IsSubtitle(string filePath)
|
|
||||||
{
|
|
||||||
return SubtitleExtensions.ContainsKey(Path.GetExtension(filePath));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ using Kyoo.Controllers;
|
|||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Attributes;
|
using Kyoo.Models.Attributes;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Kyoo.Tasks
|
namespace Kyoo.Tasks
|
||||||
{
|
{
|
||||||
@ -56,10 +55,6 @@ namespace Kyoo.Tasks
|
|||||||
/// The transcoder used to extract subtitles and metadata.
|
/// The transcoder used to extract subtitles and metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Injected] public ITranscoder Transcoder { private get; set; }
|
[Injected] public ITranscoder Transcoder { private get; set; }
|
||||||
/// <summary>
|
|
||||||
/// The logger used to inform the current status to the console.
|
|
||||||
/// </summary>
|
|
||||||
[Injected] public ILogger<RegisterEpisode> Logger { private get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TaskParameters GetParameters()
|
public TaskParameters GetParameters()
|
||||||
@ -76,58 +71,67 @@ namespace Kyoo.Tasks
|
|||||||
{
|
{
|
||||||
string path = arguments["path"].As<string>();
|
string path = arguments["path"].As<string>();
|
||||||
Library library = arguments["library"].As<Library>();
|
Library library = arguments["library"].As<Library>();
|
||||||
|
progress.Report(0);
|
||||||
|
|
||||||
try
|
if (library.Providers == null)
|
||||||
|
await LibraryManager.Load(library, x => x.Providers);
|
||||||
|
MetadataProvider.UseProviders(library.Providers);
|
||||||
|
(Collection collection, Show show, Season season, Episode episode) = await Identifier.Identify(path);
|
||||||
|
progress.Report(15);
|
||||||
|
|
||||||
|
collection = await _RegisterAndFill(collection);
|
||||||
|
progress.Report(20);
|
||||||
|
|
||||||
|
Show registeredShow = await _RegisterAndFill(show);
|
||||||
|
if (registeredShow.Path != show.Path)
|
||||||
{
|
{
|
||||||
if (library != null)
|
if (show.StartAir.HasValue)
|
||||||
{
|
{
|
||||||
if (library.Providers == null)
|
show.Slug += $"-{show.StartAir.Value.Year}";
|
||||||
await LibraryManager.Load(library, x => x.Providers);
|
show = await LibraryManager.Create(show);
|
||||||
MetadataProvider.UseProviders(library.Providers);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Collection collection, Show show, Season season, Episode episode) = await Identifier.Identify(path);
|
|
||||||
|
|
||||||
collection = await _RegisterAndFill(collection);
|
|
||||||
|
|
||||||
Show registeredShow = await _RegisterAndFill(show);
|
|
||||||
if (registeredShow.Path != show.Path)
|
|
||||||
{
|
|
||||||
if (show.StartAir.HasValue)
|
|
||||||
{
|
|
||||||
show.Slug += $"-{show.StartAir.Value.Year}";
|
|
||||||
show = await LibraryManager.Create(show);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.LogError("Duplicated show found ({Slug}) at {Path1} and {Path2}",
|
|
||||||
show.Slug, registeredShow.Path, show.Path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
show = registeredShow;
|
{
|
||||||
|
throw new DuplicatedItemException($"Duplicated show found ({show.Slug}) " +
|
||||||
if (season != null)
|
$"at {registeredShow.Path} and {show.Path}");
|
||||||
season.Show = show;
|
}
|
||||||
season = await _RegisterAndFill(season);
|
|
||||||
|
|
||||||
episode = await MetadataProvider.Get(episode);
|
|
||||||
episode.Season = season;
|
|
||||||
episode.Tracks = (await Transcoder.ExtractInfos(episode, false))
|
|
||||||
.Where(x => x.Type != StreamType.Attachment)
|
|
||||||
.ToArray();
|
|
||||||
await ThumbnailsManager.DownloadImages(episode);
|
|
||||||
|
|
||||||
await LibraryManager.Create(episode);
|
|
||||||
await LibraryManager.AddShowLink(show, library, collection);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException ex)
|
|
||||||
{
|
|
||||||
Logger.LogWarning(ex, "Duplicated found at {Path}", path);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
show = registeredShow;
|
||||||
|
// If they are not already loaded, load external ids to allow metadata providers to use them.
|
||||||
|
if (show.ExternalIDs == null)
|
||||||
|
await LibraryManager.Load(show, x => x.ExternalIDs);
|
||||||
|
progress.Report(50);
|
||||||
|
|
||||||
|
if (season != null)
|
||||||
|
season.Show = show;
|
||||||
|
season = await _RegisterAndFill(season);
|
||||||
|
progress.Report(60);
|
||||||
|
|
||||||
|
episode = await MetadataProvider.Get(episode);
|
||||||
|
progress.Report(70);
|
||||||
|
episode.Show = show;
|
||||||
|
episode.Season = season;
|
||||||
|
episode.Tracks = (await Transcoder.ExtractInfos(episode, false))
|
||||||
|
.Where(x => x.Type != StreamType.Attachment)
|
||||||
|
.ToArray();
|
||||||
|
await ThumbnailsManager.DownloadImages(episode);
|
||||||
|
progress.Report(90);
|
||||||
|
|
||||||
|
await LibraryManager.Create(episode);
|
||||||
|
progress.Report(95);
|
||||||
|
await LibraryManager.AddShowLink(show, library, collection);
|
||||||
|
progress.Report(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the equivalent item if it already exists in the database,
|
||||||
|
/// if it does not, fill metadata using the metadata provider, download images and register the item to the
|
||||||
|
/// database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to retrieve or fill and register</param>
|
||||||
|
/// <typeparam name="T">The type of the item</typeparam>
|
||||||
|
/// <returns>The existing or filled item.</returns>
|
||||||
private async Task<T> _RegisterAndFill<T>(T item)
|
private async Task<T> _RegisterAndFill<T>(T item)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
@ -141,54 +145,5 @@ namespace Kyoo.Tasks
|
|||||||
await ThumbnailsManager.DownloadImages(item);
|
await ThumbnailsManager.DownloadImages(item);
|
||||||
return await LibraryManager.CreateIfNotExists(item);
|
return await LibraryManager.CreateIfNotExists(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
private async Task RegisterExternalSubtitle(string path, CancellationToken token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (token.IsCancellationRequested || path.Split(Path.DirectorySeparatorChar).Contains("Subtitles"))
|
|
||||||
return;
|
|
||||||
using IServiceScope serviceScope = ServiceProvider.CreateScope();
|
|
||||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
|
||||||
|
|
||||||
string patern = Config.GetValue<string>("subtitleRegex");
|
|
||||||
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
|
||||||
Match match = regex.Match(path);
|
|
||||||
|
|
||||||
if (!match.Success)
|
|
||||||
{
|
|
||||||
await Console.Error.WriteLineAsync($"The subtitle at {path} does not match the subtitle's regex.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string episodePath = match.Groups["Episode"].Value;
|
|
||||||
Episode episode = await libraryManager!.Get<Episode>(x => x.Path.StartsWith(episodePath));
|
|
||||||
Track track = new()
|
|
||||||
{
|
|
||||||
Type = StreamType.Subtitle,
|
|
||||||
Language = match.Groups["Language"].Value,
|
|
||||||
IsDefault = match.Groups["Default"].Value.Length > 0,
|
|
||||||
IsForced = match.Groups["Forced"].Value.Length > 0,
|
|
||||||
Codec = SubtitleExtensions[Path.GetExtension(path)],
|
|
||||||
IsExternal = true,
|
|
||||||
Path = path,
|
|
||||||
Episode = episode
|
|
||||||
};
|
|
||||||
|
|
||||||
await libraryManager.Create(track);
|
|
||||||
Console.WriteLine($"Registering subtitle at: {path}.");
|
|
||||||
}
|
|
||||||
catch (ItemNotFoundException)
|
|
||||||
{
|
|
||||||
await Console.Error.WriteLineAsync($"No episode found for subtitle at: ${path}.");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await Console.Error.WriteLineAsync($"Unknown error while registering subtitle: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
85
Kyoo/Tasks/RegisterSubtitle.cs
Normal file
85
Kyoo/Tasks/RegisterSubtitle.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Attributes;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
|
||||||
|
namespace Kyoo.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A task to register a new episode
|
||||||
|
/// </summary>
|
||||||
|
public class RegisterSubtitle : ITask
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Slug => "register-sub";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "Register subtitle";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "Register a new subtitle";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string HelpMessage => null;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool RunOnStartup => false;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Priority => 0;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsHidden => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An identifier to extract metadata from paths.
|
||||||
|
/// </summary>
|
||||||
|
[Injected] public IIdentifier Identifier { private get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The library manager used to register the episode
|
||||||
|
/// </summary>
|
||||||
|
[Injected] public ILibraryManager LibraryManager { private get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public TaskParameters GetParameters()
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
TaskParameter.CreateRequired<string>("path", "The path of the episode file"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task Run(TaskParameters arguments, IProgress<float> progress, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
string path = arguments["path"].As<string>();
|
||||||
|
|
||||||
|
progress.Report(0);
|
||||||
|
Track track = await Identifier.IdentifyTrack(path);
|
||||||
|
progress.Report(25);
|
||||||
|
|
||||||
|
if (track.Episode == null)
|
||||||
|
throw new IdentificationFailed($"No episode identified for the track at {path}");
|
||||||
|
if (track.Episode.ID == 0)
|
||||||
|
{
|
||||||
|
if (track.Episode.Slug != null)
|
||||||
|
track.Episode = await LibraryManager.Get<Episode>(track.Episode.Slug);
|
||||||
|
else if (track.Episode.Path != null)
|
||||||
|
{
|
||||||
|
track.Episode = await LibraryManager.GetOrDefault<Episode>(x => x.Path == track.Episode.Path);
|
||||||
|
if (track.Episode == null)
|
||||||
|
throw new ItemNotFoundException($"No episode found for subtitle at: ${path}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new IdentificationFailed($"No episode identified for the track at {path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.Report(50);
|
||||||
|
await LibraryManager.Create(track);
|
||||||
|
progress.Report(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user