diff --git a/back/src/Directory.Build.props b/back/src/Directory.Build.props
index 396e44e6..c0c382c2 100644
--- a/back/src/Directory.Build.props
+++ b/back/src/Directory.Build.props
@@ -29,13 +29,6 @@
- true
- true
- true
-
-
- true
-
true
diff --git a/back/src/Kyoo.Abstractions/Controllers/IFileSystem.cs b/back/src/Kyoo.Abstractions/Controllers/IFileSystem.cs
deleted file mode 100644
index f70a577b..00000000
--- a/back/src/Kyoo.Abstractions/Controllers/IFileSystem.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-using JetBrains.Annotations;
-using Kyoo.Abstractions.Models;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Kyoo.Abstractions.Controllers
-{
- ///
- /// A service to abstract the file system to allow custom file systems
- /// (like distant file systems or external providers).
- ///
- public interface IFileSystem
- {
- ///
- /// Used for http queries returning a file. This should be used to return local files
- /// or proxy them from a distant server.
- ///
- ///
- /// If no file exists at the given path or if the path is null, a NotFoundResult is returned
- /// to handle it gracefully.
- ///
- /// The path of the file.
- ///
- /// Should the file be downloaded at once or is the client allowed to request only part of the file
- ///
- ///
- /// You can manually specify the content type of your file.
- /// For example you can force a file to be returned as plain text using text/plain .
- /// If the type is not specified, it will be deduced automatically (from the extension or by sniffing the file).
- ///
- /// An representing the file returned.
- IActionResult FileResult([CanBeNull] string path, bool rangeSupport = false, string type = null);
-
- ///
- /// Read a file present at . The reader can be used in an arbitrary context.
- /// To return files from an http endpoint, use .
- ///
- /// The path of the file
- /// If the file could not be found.
- /// A reader to read the file.
- Task GetReader([NotNull] string path);
-
- ///
- /// Read a file present at . The reader can be used in an arbitrary context.
- /// To return files from an http endpoint, use .
- ///
- /// The path of the file
- /// The mime type of the opened file.
- /// If the file could not be found.
- /// A reader to read the file.
- Task GetReader([NotNull] string path, AsyncRef mime);
-
- ///
- /// Create a new file at .
- ///
- /// The path of the new file.
- /// A writer to write to the new file.
- Task NewFile([NotNull] string path);
-
- ///
- /// Create a new directory at the given path
- ///
- /// The path of the directory
- /// The path of the newly created directory is returned.
- Task CreateDirectory([NotNull] string path);
-
- ///
- /// Combine multiple paths.
- ///
- /// The paths to combine
- /// The combined path.
- string Combine(params string[] paths);
-
- ///
- /// List files in a directory.
- ///
- /// The path of the directory
- /// Should the search be recursive or not.
- /// A list of files's path.
- Task> ListFiles([NotNull] string path,
- SearchOption options = SearchOption.TopDirectoryOnly);
-
- ///
- /// Check if a file exists at the given path.
- ///
- /// The path to check
- /// True if the path exists, false otherwise
- Task Exists([NotNull] string path);
-
- ///
- /// Get the extra directory of a resource .
- /// This method is in this system to allow a filesystem to use a different metadata policy for one.
- /// It can be useful if the filesystem is readonly.
- ///
- /// The resource to proceed
- /// The type of the resource.
- /// The extra directory of the resource.
- Task GetExtraDirectory([NotNull] T resource);
-
- ///
- /// Retrieve tracks for a specific episode.
- /// Subtitles, chapters and fonts should also be extracted and cached when calling this method.
- ///
- /// The episode to retrieve tracks for.
- /// Should the cache be invalidated and subtitles and others be re-extracted?
- /// The list of tracks available for this episode.
- Task> ExtractInfos([NotNull] Episode episode, bool reExtract);
-
- ///
- /// Transmux the selected episode to hls.
- ///
- /// The episode to transmux.
- /// The master file (m3u8) of the transmuxed hls file.
- IActionResult Transmux([NotNull] Episode episode);
-
- // Maybe add options for to select the codec.
- // IActionResult Transcode(Episode episode);
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
index 624f72eb..792e1978 100644
--- a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
@@ -70,11 +70,6 @@ namespace Kyoo.Abstractions.Controllers
///
IEpisodeRepository EpisodeRepository { get; }
- ///
- /// The repository that handle tracks.
- ///
- ITrackRepository TrackRepository { get; }
-
///
/// The repository that handle people.
///
diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
index 56e91cd7..a45827f0 100644
--- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
@@ -330,11 +330,6 @@ namespace Kyoo.Abstractions.Controllers
Task GetAbsolute(string showSlug, int absoluteNumber);
}
- ///
- /// A repository to handle tracks
- ///
- public interface ITrackRepository : IRepository { }
-
///
/// A repository to handle libraries.
///
diff --git a/back/src/Kyoo.Abstractions/Controllers/IThumbnailsManager.cs b/back/src/Kyoo.Abstractions/Controllers/IThumbnailsManager.cs
index eb26335a..69ffe0bc 100644
--- a/back/src/Kyoo.Abstractions/Controllers/IThumbnailsManager.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/IThumbnailsManager.cs
@@ -17,9 +17,10 @@
// along with Kyoo. If not, see .
using System.Threading.Tasks;
-using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
+#nullable enable
+
namespace Kyoo.Abstractions.Controllers
{
///
@@ -39,17 +40,17 @@ namespace Kyoo.Abstractions.Controllers
///
/// The type of the item
/// true if an image has been downloaded, false otherwise.
- Task DownloadImages([NotNull] T item, bool alwaysDownload = false)
+ Task DownloadImages(T item, bool alwaysDownload = false)
where T : IThumbnails;
///
/// Retrieve the local path of an image of the given item.
///
/// The item to retrieve the poster from.
- /// The ID of the image. See for values.
+ /// The ID of the image. See for values.
/// The type of the item
/// The path of the image for the given resource or null if it does not exists.
- Task GetImagePath([NotNull] T item, int imageID)
+ string? GetImagePath(T item, int imageId)
where T : IThumbnails;
}
}
diff --git a/back/src/Kyoo.Abstractions/Controllers/ITranscoder.cs b/back/src/Kyoo.Abstractions/Controllers/ITranscoder.cs
deleted file mode 100644
index b87a8d5d..00000000
--- a/back/src/Kyoo.Abstractions/Controllers/ITranscoder.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using JetBrains.Annotations;
-using Kyoo.Abstractions.Models;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Kyoo.Abstractions.Controllers
-{
- ///
- /// Transcoder responsible of handling low level video details.
- ///
- public interface ITranscoder
- {
- ///
- /// Retrieve tracks for a specific episode.
- /// Subtitles, chapters and fonts should also be extracted and cached when calling this method.
- ///
- /// The episode to retrieve tracks for.
- /// Should the cache be invalidated and subtitles and others be re-extracted?
- /// The list of tracks available for this episode.
- Task> ExtractInfos(Episode episode, bool reExtract);
-
- ///
- /// List fonts assosiated with this episode.
- ///
- /// Th episode to list fonts for.
- /// The list of attachements for this epiosode.
- Task> ListFonts(Episode episode);
-
- ///
- /// Get the specified font for this episode.
- ///
- /// The episode to list fonts for.
- /// The slug of the specific font to retrive.
- /// The with the given slug or null.
- [ItemCanBeNull] Task GetFont(Episode episode, string slug);
-
- ///
- /// Transmux the selected episode to hls.
- ///
- /// The episode to transmux.
- /// The master file (m3u8) of the transmuxed hls file.
- IActionResult Transmux(Episode episode);
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Attributes/FileSystemMetadataAttribute.cs b/back/src/Kyoo.Abstractions/Models/Attributes/FileSystemMetadataAttribute.cs
deleted file mode 100644
index 207ab91c..00000000
--- a/back/src/Kyoo.Abstractions/Models/Attributes/FileSystemMetadataAttribute.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.Composition;
-using Kyoo.Abstractions.Controllers;
-
-namespace Kyoo.Abstractions.Models.Attributes
-{
- ///
- /// An attribute to inform how a works.
- ///
- [MetadataAttribute]
- [AttributeUsage(AttributeTargets.Class)]
- public class FileSystemMetadataAttribute : Attribute
- {
- ///
- /// The scheme(s) used to identify this path.
- /// It can be something like http, https, ftp, file and so on.
- ///
- ///
- /// If multiples files with the same schemes exists, an exception will be thrown.
- ///
- public string[] Scheme { get; }
-
- ///
- /// true if the scheme should be removed from the path before calling
- /// methods of this , false otherwise.
- ///
- public bool StripScheme { get; set; }
-
- ///
- /// Create a new using the specified schemes.
- ///
- /// The schemes to use.
- public FileSystemMetadataAttribute(string[] schemes)
- {
- Scheme = schemes;
- }
-
- ///
- /// Create a new using a dictionary of metadata.
- ///
- ///
- /// The dictionary of metadata. This method expect the dictionary to contain a field
- /// per property in this attribute, with the same types as the properties of this attribute.
- ///
- public FileSystemMetadataAttribute(IDictionary metadata)
- {
- Scheme = (string[])metadata[nameof(Scheme)];
- StripScheme = (bool)metadata[nameof(StripScheme)];
- }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Attributes/TaskMetadataAttribute.cs b/back/src/Kyoo.Abstractions/Models/Attributes/TaskMetadataAttribute.cs
deleted file mode 100644
index 3683fe77..00000000
--- a/back/src/Kyoo.Abstractions/Models/Attributes/TaskMetadataAttribute.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.Composition;
-using Kyoo.Abstractions.Controllers;
-
-namespace Kyoo.Abstractions.Models.Attributes
-{
- ///
- /// An attribute to inform how a works.
- ///
- [MetadataAttribute]
- [AttributeUsage(AttributeTargets.Class)]
- public class TaskMetadataAttribute : Attribute
- {
- ///
- /// The slug of the task, used to start it.
- ///
- public string Slug { get; }
-
- ///
- /// The name of the task that will be displayed to the user.
- ///
- public string Name { get; }
-
- ///
- /// A quick description of what this task will do.
- ///
- public string Description { get; }
-
- ///
- /// Should this task be automatically run at app startup?
- ///
- public bool RunOnStartup { get; set; }
-
- ///
- /// The priority of this task. Only used if is true.
- /// It allow one to specify witch task will be started first as tasked are run on a Priority's descending order.
- ///
- public int Priority { get; set; }
-
- ///
- /// true if this task should not be displayed to the user, false otherwise.
- ///
- public bool IsHidden { get; set; }
-
- ///
- /// Create a new with the given slug, name and description.
- ///
- /// The slug of the task, used to start it.
- /// The name of the task that will be displayed to the user.
- /// A quick description of what this task will do.
- public TaskMetadataAttribute(string slug, string name, string description)
- {
- Slug = slug;
- Name = name;
- Description = description;
- }
-
- ///
- /// Create a new using a dictionary of metadata.
- ///
- ///
- /// The dictionary of metadata. This method expect the dictionary to contain a field
- /// per property in this attribute, with the same types as the properties of this attribute.
- ///
- public TaskMetadataAttribute(IDictionary metadata)
- {
- Slug = (string)metadata[nameof(Slug)];
- Name = (string)metadata[nameof(Name)];
- Description = (string)metadata[nameof(Description)];
- RunOnStartup = (bool)metadata[nameof(RunOnStartup)];
- Priority = (int)metadata[nameof(Priority)];
- IsHidden = (bool)metadata[nameof(IsHidden)];
- }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Chapter.cs b/back/src/Kyoo.Abstractions/Models/Chapter.cs
deleted file mode 100644
index c03e1045..00000000
--- a/back/src/Kyoo.Abstractions/Models/Chapter.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-namespace Kyoo.Abstractions.Models
-{
- ///
- /// A chapter to split an episode in multiple parts.
- ///
- public class Chapter
- {
- ///
- /// The start time of the chapter (in second from the start of the episode).
- ///
- public float StartTime { get; set; }
-
- ///
- /// The end time of the chapter (in second from the start of the episode).
- ///
- public float EndTime { get; set; }
-
- ///
- /// The name of this chapter. This should be a human-readable name that could be presented to the user.
- /// There should be well-known chapters name for commonly used chapters.
- /// For example, use "Opening" for the introduction-song and "Credits" for the end chapter with credits.
- ///
- public string Name { get; set; }
-
- ///
- /// Create a new .
- ///
- /// The start time of the chapter (in second)
- /// The end time of the chapter (in second)
- /// The name of this chapter
- public Chapter(float startTime, float endTime, string name)
- {
- StartTime = startTime;
- EndTime = endTime;
- Name = name;
- }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Exceptions/HealthException.cs b/back/src/Kyoo.Abstractions/Models/Exceptions/HealthException.cs
deleted file mode 100644
index 6b4d86e2..00000000
--- a/back/src/Kyoo.Abstractions/Models/Exceptions/HealthException.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Runtime.Serialization;
-
-namespace Kyoo.Abstractions.Models.Exceptions
-{
- ///
- /// An exception thrown when a part of the app has a fatal issue.
- ///
- [Serializable]
- public class HealthException : Exception
- {
- ///
- /// Create a new with a custom message.
- ///
- /// The message to use.
- public HealthException(string message)
- : base(message)
- { }
-
- ///
- /// The serialization constructor
- ///
- /// Serialization infos
- /// The serialization context
- protected HealthException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Font.cs b/back/src/Kyoo.Abstractions/Models/Font.cs
deleted file mode 100644
index ca9c4680..00000000
--- a/back/src/Kyoo.Abstractions/Models/Font.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using Kyoo.Abstractions.Models.Attributes;
-using Kyoo.Utils;
-using PathIO = System.IO.Path;
-
-namespace Kyoo.Abstractions.Models
-{
- ///
- /// A font of an .
- ///
- public class Font : ILink
- {
- ///
- /// A human-readable identifier, used in the URL.
- ///
- public string Slug { get; set; }
-
- ///
- /// The name of the font file (with the extension).
- ///
- public string File { get; set; }
-
- ///
- /// The format of this font (the extension).
- ///
- public string Format { get; set; }
-
- ///
- /// The path of the font.
- ///
- [SerializeIgnore] public string Path { get; set; }
-
- ///
- public object Link { get; init; }
-
- ///
- /// Create a new empty .
- ///
- public Font() { }
-
- ///
- /// Create a new from a path.
- ///
- /// The path of the font.
- /// The slug of the episode that contains this font.
- public Font(string path, string episodeSlug)
- {
- Slug = Utility.ToSlug(PathIO.GetFileNameWithoutExtension(path));
- Path = path;
- File = PathIO.GetFileName(path);
- Format = PathIO.GetExtension(path).Replace(".", string.Empty);
- Link = $"/watch/{episodeSlug}/font/{Slug}.{Format}";
- }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs
index 619b802e..f6dcb41e 100644
--- a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs
+++ b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs
@@ -123,7 +123,7 @@ namespace Kyoo.Abstractions.Models
public int? AbsoluteNumber { get; set; }
///
- /// The path of the video file for this episode. Any format supported by a is allowed.
+ /// The path of the video file for this episode.
///
public string Path { get; set; }
@@ -148,11 +148,6 @@ namespace Kyoo.Abstractions.Models
///
[EditableRelation][LoadableRelation] public ICollection ExternalIDs { get; set; }
- ///
- /// The list of tracks this episode has. This lists video, audio and subtitles available.
- ///
- [EditableRelation][LoadableRelation] public ICollection Tracks { get; set; }
-
///
/// Get the slug of an episode.
///
diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs
index 6a84977f..071ddc35 100644
--- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs
+++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs
@@ -28,7 +28,6 @@ namespace Kyoo.Abstractions.Models
{
///
/// The list of images mapped to a certain index.
- /// The string value should be a path supported by the .
///
///
/// An arbitrary index should not be used, instead use indexes from
diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs
index 90600d0d..646dee9f 100644
--- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs
+++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs
@@ -46,7 +46,6 @@ namespace Kyoo.Abstractions.Models
///
/// The path of the root directory of this show.
- /// This can be any kind of path supported by
///
[SerializeIgnore] public string Path { get; set; }
@@ -61,7 +60,7 @@ namespace Kyoo.Abstractions.Models
public Status Status { get; set; }
///
- /// An URL to a trailer. This could be any path supported by the .
+ /// An URL to a trailer.
///
/// TODO for now, this is set to a youtube url. It should be cached and converted to a local file.
[Obsolete("Use Images instead of this, this is only kept for the API response.")]
diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Track.cs b/back/src/Kyoo.Abstractions/Models/Resources/Track.cs
deleted file mode 100644
index f838c813..00000000
--- a/back/src/Kyoo.Abstractions/Models/Resources/Track.cs
+++ /dev/null
@@ -1,229 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Text.RegularExpressions;
-using JetBrains.Annotations;
-using Kyoo.Abstractions.Models.Attributes;
-
-namespace Kyoo.Abstractions.Models
-{
- ///
- /// The list of available stream types.
- /// Attachments are only used temporarily by the transcoder but are not stored in a database.
- ///
- public enum StreamType
- {
- ///
- /// The type of the stream is not known.
- ///
- Unknown = 0,
-
- ///
- /// The stream is a video.
- ///
- Video = 1,
-
- ///
- /// The stream is an audio.
- ///
- Audio = 2,
-
- ///
- /// The stream is a subtitle.
- ///
- Subtitle = 3,
- }
-
- ///
- /// A video, audio or subtitle track for an episode.
- ///
- public class Track : IResource, ILink
- {
- ///
- public int ID { get; set; }
-
- ///
- [Computed]
- public string Slug
- {
- get
- {
- string type = Type.ToString().ToLowerInvariant();
- string index = TrackIndex != 0 ? $"-{TrackIndex}" : string.Empty;
- string episode = EpisodeSlug ?? Episode?.Slug ?? EpisodeID.ToString(CultureInfo.InvariantCulture);
- return $"{episode}.{Language ?? "und"}{index}{(IsForced ? ".forced" : string.Empty)}.{type}";
- }
-
- [UsedImplicitly]
- private set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(value));
- Match match = Regex.Match(value,
- @"(?[^\.]+)\.(?\w{0,3})(-(?\d+))?(\.(?forced))?\.(?\w+)(\.\w*)?");
-
- if (!match.Success)
- {
- throw new ArgumentException(
- "Invalid track slug. " +
- "Format: {episodeSlug}.{language}[-{index}][.forced].{type}[.{extension}]"
- );
- }
-
- EpisodeSlug = match.Groups["ep"].Value;
- Language = match.Groups["lang"].Value;
- if (Language == "und")
- Language = null;
- TrackIndex = match.Groups["index"].Success ? int.Parse(match.Groups["index"].Value, CultureInfo.InvariantCulture) : 0;
- IsForced = match.Groups["forced"].Success;
- Type = Enum.Parse(match.Groups["type"].Value, true);
- }
- }
-
- ///
- /// The title of the stream.
- ///
- public string Title { get; set; }
-
- ///
- /// The language of this stream (as a ISO-639-2 language code)
- ///
- public string Language { get; set; }
-
- ///
- /// The codec of this stream.
- ///
- public string Codec { get; set; }
-
- ///
- /// Is this stream the default one of it's type?
- ///
- public bool IsDefault { get; set; }
-
- ///
- /// Is this stream tagged as forced?
- ///
- public bool IsForced { get; set; }
-
- ///
- /// Is this track extern to the episode's file?
- ///
- public bool IsExternal { get; set; }
-
- ///
- /// The path of this track.
- ///
- [SerializeIgnore] public string Path { get; set; }
-
- ///
- /// The type of this stream.
- ///
- [SerializeIgnore] public StreamType Type { get; set; }
-
- ///
- /// The ID of the episode that uses this track.
- ///
- [SerializeIgnore] public int EpisodeID { get; set; }
-
- ///
- /// The episode that uses this track.
- ///
- [LoadableRelation(nameof(EpisodeID))]
- public Episode Episode
- {
- get => _episode;
- set
- {
- _episode = value;
- if (_episode != null)
- EpisodeSlug = _episode.Slug;
- }
- }
-
- ///
- /// The index of this track on the episode.
- ///
- public int TrackIndex { get; set; }
-
- ///
- /// A user-friendly name for this track. It does not include the track type.
- ///
- public string DisplayName
- {
- get
- {
- string language = _GetLanguage(Language);
-
- if (language == null)
- return $"Unknown (index: {TrackIndex})";
- CultureInfo info = CultureInfo.GetCultures(CultureTypes.NeutralCultures)
- .FirstOrDefault(x => x.ThreeLetterISOLanguageName == language);
- string name = info?.EnglishName ?? language;
- if (IsForced)
- name += " Forced";
- if (IsExternal)
- name += " (External)";
- if (Title is { Length: > 1 })
- name += " - " + Title;
- return name;
- }
- }
-
- ///
- /// The slug of the episode that contain this track. If this is not set, this track is ill-formed.
- ///
- [SerializeIgnore] public string EpisodeSlug { private get; set; }
-
- ///
- /// The episode that uses this track.
- /// This is the baking field of .
- ///
- [SerializeIgnore] private Episode _episode;
-
- ///
- public object Link => Type == StreamType.Subtitle ? $"/subtitle/{Slug}" : null;
-
- // Converting mkv track language to c# system language tag.
- private static string _GetLanguage(string mkvLanguage)
- {
- // TODO delete this and have a real way to get the language string from the ISO-639-2.
- return mkvLanguage switch
- {
- "fre" => "fra",
- null => "und",
- _ => mkvLanguage
- };
- }
-
- ///
- /// Utility method to create a track slug from a incomplete slug (only add the type of the track).
- ///
- /// The slug to edit
- /// The new type of this
- /// The completed slug.
- public static string BuildSlug(string baseSlug, StreamType type)
- {
- return baseSlug.EndsWith($".{type}", StringComparison.InvariantCultureIgnoreCase)
- ? baseSlug
- : $"{baseSlug}.{type.ToString().ToLowerInvariant()}";
- }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/AsyncRef.cs b/back/src/Kyoo.Abstractions/Models/Utils/AsyncRef.cs
deleted file mode 100644
index 18ffd7d1..00000000
--- a/back/src/Kyoo.Abstractions/Models/Utils/AsyncRef.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-namespace Kyoo.Abstractions.Models
-{
- ///
- /// A class wrapping a value that will be set after the completion of the task it is related to.
- ///
- ///
- /// This class replace the use of an out parameter on a task since tasks and out can't be combined.
- ///
- /// The type of the value
- public class AsyncRef
- {
- ///
- /// The value that will be set before the completion of the task.
- ///
- public T Value { get; set; }
- }
-}
diff --git a/back/src/Kyoo.Abstractions/Models/WatchItem.cs b/back/src/Kyoo.Abstractions/Models/WatchItem.cs
index 13e61ae0..bd5d989a 100644
--- a/back/src/Kyoo.Abstractions/Models/WatchItem.cs
+++ b/back/src/Kyoo.Abstractions/Models/WatchItem.cs
@@ -19,12 +19,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.IO;
using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Json;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
-using PathIO = System.IO.Path;
namespace Kyoo.Abstractions.Models
{
@@ -85,11 +85,6 @@ namespace Kyoo.Abstractions.Models
///
public DateTime? ReleaseDate { get; set; }
- ///
- /// The path of the video file for this episode. Any format supported by a is allowed.
- ///
- [SerializeIgnore] public string Path { get; set; }
-
///
/// The episode that come before this one if you follow usual watch orders.
/// If this is the first episode or this is a movie, it will be null.
@@ -111,35 +106,9 @@ namespace Kyoo.Abstractions.Models
public Dictionary Images { get; set; }
///
- /// The container of the video file of this episode.
- /// Common containers are mp4, mkv, avi and so on.
+ /// The transcoder's info for this item. This include subtitles, fonts, chapters...
///
- public string Container { get; set; }
-
- ///
- /// The video track. See for more information.
- ///
- public Track Video { get; set; }
-
- ///
- /// The list of audio tracks. See for more information.
- ///
- public ICollection Audios { get; set; }
-
- ///
- /// The list of subtitles tracks. See for more information.
- ///
- public ICollection Subtitles { get; set; }
-
- ///
- /// The list of fonts that can be used to draw the subtitles.
- ///
- public ICollection Fonts { get; set; }
-
- ///
- /// The list of chapters. See for more information.
- ///
- public ICollection Chapters { get; set; }
+ public object Info { get; set; }
[SerializeIgnore]
private string _Type => IsMovie ? "movie" : "episode";
@@ -158,13 +127,11 @@ namespace Kyoo.Abstractions.Models
///
/// A library manager to retrieve the next and previous episode and load the show and tracks of the episode.
///
- /// A file system used to retrieve chapters informations.
- /// The transcoder used to list fonts.
+ /// A http client to reach the transcoder.
/// A new WatchItem representing the given episode.
- public static async Task FromEpisode(Episode ep, ILibraryManager library, IFileSystem fs, ITranscoder transcoder)
+ public static async Task FromEpisode(Episode ep, ILibraryManager library, HttpClient client)
{
await library.Load(ep, x => x.Show);
- await library.Load(ep, x => x.Tracks);
return new WatchItem
{
@@ -178,13 +145,7 @@ namespace Kyoo.Abstractions.Models
Title = ep.Title,
Overview = ep.Overview,
ReleaseDate = ep.ReleaseDate,
- Path = ep.Path,
Images = ep.Show.Images,
- Container = PathIO.GetExtension(ep.Path).Replace(".", string.Empty),
- Video = ep.Tracks.FirstOrDefault(x => x.Type == StreamType.Video),
- Audios = ep.Tracks.Where(x => x.Type == StreamType.Audio).ToArray(),
- Subtitles = ep.Tracks.Where(x => x.Type == StreamType.Subtitle).ToArray(),
- Fonts = await transcoder.ListFonts(ep),
PreviousEpisode = ep.Show.IsMovie
? null
: (await library.GetAll(
@@ -197,50 +158,16 @@ namespace Kyoo.Abstractions.Models
where: x => x.ShowID == ep.ShowID,
limit: new Pagination(1, ep.ID)
)).FirstOrDefault(),
- Chapters = await _GetChapters(ep, fs),
- IsMovie = ep.Show.IsMovie
+ IsMovie = ep.Show.IsMovie,
+ Info = await _GetInfo(ep, client),
};
}
- // TODO move this method in a controller to support abstraction.
- private static async Task> _GetChapters(Episode episode, IFileSystem fs)
+ private static async Task _GetInfo(Episode ep, HttpClient client)
{
- string path = fs.Combine(
- await fs.GetExtraDirectory(episode),
- "Chapters",
- PathIO.GetFileNameWithoutExtension(episode.Path) + ".txt"
+ return await client.GetFromJsonAsync(
+ $"http://transcoder:7666/info/{(ep.Show.IsMovie ? "movie" : "episode")}/${ep.Slug}/info"
);
- if (!await fs.Exists(path))
- return Array.Empty();
- try
- {
- using StreamReader sr = new(await fs.GetReader(path));
- string chapters = await sr.ReadToEndAsync();
- return chapters.Split('\n')
- .Select(x =>
- {
- string[] values = x.Split(' ');
- if (
- values.Length < 3
- || !float.TryParse(values[0], out float start)
- || !float.TryParse(values[1], out float end)
- )
- return null;
- return new Chapter(
- start,
- end,
- string.Join(' ', values.Skip(2))
- );
- })
- .Where(x => x != null)
- .ToArray();
- }
- catch (Exception ex)
- {
- await Console.Error.WriteLineAsync($"Invalid chapter file at {path}");
- Console.Error.WriteLine(ex.ToString());
- return Array.Empty();
- }
}
///
diff --git a/back/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs b/back/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs
deleted file mode 100644
index e004b796..00000000
--- a/back/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.Net.Http;
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Attributes;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Kyoo.Core.Controllers
-{
- ///
- /// A for http/https links.
- ///
- [FileSystemMetadata(new[] { "http", "https" })]
- public class HttpFileSystem : IFileSystem
- {
- ///
- /// The http client factory used to create clients.
- ///
- private readonly IHttpClientFactory _clientFactory;
-
- ///
- /// Create a using the given client factory.
- ///
- /// The http client factory used to create clients.
- public HttpFileSystem(IHttpClientFactory factory)
- {
- _clientFactory = factory;
- }
-
- ///
- public IActionResult FileResult(string path, bool rangeSupport = false, string type = null)
- {
- if (path == null)
- return new NotFoundResult();
- return new HttpForwardResult(new Uri(path), rangeSupport, type);
- }
-
- ///
- public Task GetReader(string path)
- {
- HttpClient client = _clientFactory.CreateClient();
- return client.GetStreamAsync(path);
- }
-
- ///
- public async Task GetReader(string path, AsyncRef mime)
- {
- HttpClient client = _clientFactory.CreateClient();
- HttpResponseMessage response = await client.GetAsync(path);
- response.EnsureSuccessStatusCode();
- mime.Value = response.Content.Headers.ContentType?.MediaType;
- return await response.Content.ReadAsStreamAsync();
- }
-
- ///
- public Task NewFile(string path)
- {
- throw new NotSupportedException("An http filesystem is readonly, a new file can't be created.");
- }
-
- ///
- public Task CreateDirectory(string path)
- {
- throw new NotSupportedException("An http filesystem is readonly, a directory can't be created.");
- }
-
- ///
- public string Combine(params string[] paths)
- {
- return Path.Combine(paths);
- }
-
- ///
- public Task> ListFiles(string path, SearchOption options = SearchOption.TopDirectoryOnly)
- {
- throw new NotSupportedException("Listing files is not supported on an http filesystem.");
- }
-
- ///
- public Task Exists(string path)
- {
- throw new NotSupportedException("Checking if a file exists is not supported on an http filesystem.");
- }
-
- ///
- public Task GetExtraDirectory(T resource)
- {
- throw new NotSupportedException("Extras can not be stored inside an http filesystem.");
- }
-
- ///
- public Task> ExtractInfos(Episode episode, bool reExtract)
- {
- throw new NotSupportedException("Extracting infos is not supported on an http filesystem.");
- }
-
- ///
- public IActionResult Transmux(Episode episode)
- {
- throw new NotSupportedException("Transmuxing is not supported on an http filesystem.");
- }
-
- ///
- /// An to proxy an http request.
- ///
- // TODO remove this suppress message once the class has been implemented.
- [SuppressMessage("ReSharper", "NotAccessedField.Local", Justification = "Not Implemented Yet.")]
- public class HttpForwardResult : IActionResult
- {
- ///
- /// The path of the request to forward.
- ///
- private readonly Uri _path;
-
- ///
- /// Should the proxied result support ranges requests?
- ///
- private readonly bool _rangeSupport;
-
- ///
- /// If not null, override the content type of the resulting request.
- ///
- private readonly string _type;
-
- ///
- /// Create a new .
- ///
- /// The path of the request to forward.
- /// Should the proxied result support ranges requests?
- /// If not null, override the content type of the resulting request.
- public HttpForwardResult(Uri path, bool rangeSupport, string type = null)
- {
- _path = path;
- _rangeSupport = rangeSupport;
- _type = type;
- }
-
- ///
- public Task ExecuteResultAsync(ActionContext context)
- {
- // TODO implement that, example: https://github.com/twitchax/AspNetCore.Proxy/blob/14dd0f212d7abb43ca1bf8c890d5efb95db66acb/src/Core/Extensions/Http.cs#L15
- throw new NotImplementedException();
- }
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs b/back/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs
deleted file mode 100644
index 42d77f92..00000000
--- a/back/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Attributes;
-using Kyoo.Core.Models.Options;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.AspNetCore.StaticFiles;
-using Microsoft.Extensions.Options;
-
-namespace Kyoo.Core.Controllers
-{
- ///
- /// A for the local filesystem (using System.IO).
- ///
- [FileSystemMetadata(new[] { "", "file" }, StripScheme = true)]
- public class LocalFileSystem : IFileSystem
- {
- ///
- /// An extension provider to get content types from files extensions.
- ///
- private readonly IContentTypeProvider _provider;
-
- ///
- /// The transcoder of local files.
- ///
- private readonly ITranscoder _transcoder;
-
- ///
- /// Options to check if the metadata should be kept in the show directory or in a kyoo's directory.
- ///
- private readonly IOptionsMonitor _options;
-
- ///
- /// Create a new with the specified options.
- ///
- /// The options to use.
- /// An extension provider to get content types from files extensions.
- /// The transcoder of local files.
- public LocalFileSystem(IOptionsMonitor options,
- IContentTypeProvider provider,
- ITranscoder transcoder)
- {
- _options = options;
- _provider = provider;
- _transcoder = transcoder;
- }
-
- ///
- /// Get the content type of a file using it's extension.
- ///
- /// The path of the file
- /// The extension of the file is not known.
- /// The content type of the file
- private string _GetContentType(string path)
- {
- if (_provider.TryGetContentType(path, out string contentType))
- return contentType;
- throw new NotImplementedException($"Can't get the content type of the file at: {path}");
- }
-
- ///
- public IActionResult FileResult(string path, bool rangeSupport = false, string type = null)
- {
- if (path == null)
- return new NotFoundResult();
- if (!File.Exists(path))
- return new NotFoundResult();
- return new PhysicalFileResult(Path.GetFullPath(path), type ?? _GetContentType(path))
- {
- EnableRangeProcessing = rangeSupport
- };
- }
-
- ///
- public Task GetReader(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return Task.FromResult(File.OpenRead(path));
- }
-
- ///
- public Task GetReader(string path, AsyncRef mime)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- _provider.TryGetContentType(path, out string mimeValue);
- mime.Value = mimeValue;
- return Task.FromResult(File.OpenRead(path));
- }
-
- ///
- public Task NewFile(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return Task.FromResult(File.Create(path));
- }
-
- ///
- public Task CreateDirectory(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- Directory.CreateDirectory(path);
- return Task.FromResult(path);
- }
-
- ///
- public string Combine(params string[] paths)
- {
- return Path.Combine(paths);
- }
-
- ///
- public Task> ListFiles(string path, SearchOption options = SearchOption.TopDirectoryOnly)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- string[] ret = Directory.Exists(path)
- ? Directory.GetFiles(path, "*", options)
- : Array.Empty();
- return Task.FromResult>(ret);
- }
-
- ///
- public Task Exists(string path)
- {
- return Task.FromResult(File.Exists(path) || Directory.Exists(path));
- }
-
- ///
- public Task GetExtraDirectory(T resource)
- {
- string path = resource switch
- {
- IResource res => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name.ToLower(), res.Slug),
- _ => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name.ToLower())
- };
- return CreateDirectory(path);
- }
-
- ///
- public Task> ExtractInfos(Episode episode, bool reExtract)
- {
- return _transcoder.ExtractInfos(episode, reExtract);
- }
-
- ///
- public IActionResult Transmux(Episode episode)
- {
- return _transcoder.Transmux(episode);
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs
index d07a5da3..453d6b10 100644
--- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs
+++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs
@@ -57,9 +57,6 @@ namespace Kyoo.Core.Controllers
///
public IEpisodeRepository EpisodeRepository { get; }
- ///
- public ITrackRepository TrackRepository { get; }
-
///
public IPeopleRepository PeopleRepository { get; }
@@ -89,7 +86,6 @@ namespace Kyoo.Core.Controllers
ShowRepository = GetRepository() as IShowRepository;
SeasonRepository = GetRepository() as ISeasonRepository;
EpisodeRepository = GetRepository() as IEpisodeRepository;
- TrackRepository = GetRepository() as ITrackRepository;
PeopleRepository = GetRepository() as IPeopleRepository;
StudioRepository = GetRepository() as IStudioRepository;
GenreRepository = GetRepository() as IGenreRepository;
@@ -354,11 +350,6 @@ namespace Kyoo.Core.Controllers
(x, y) => x.ExternalIDs = y,
(x, y) => { x.ResourceID = y.ID; }),
- (Episode e, nameof(Episode.Tracks)) => _SetRelation(e,
- TrackRepository.GetAll(x => x.Episode.ID == obj.ID),
- (x, y) => x.Tracks = y,
- (x, y) => { x.Episode = y; x.EpisodeID = y.ID; }),
-
(Episode e, nameof(Episode.Show)) => ShowRepository
.GetOrDefault(x => x.Episodes.Any(y => y.ID == obj.ID))
.Then(x =>
@@ -376,15 +367,6 @@ namespace Kyoo.Core.Controllers
}),
- (Track t, nameof(Track.Episode)) => EpisodeRepository
- .GetOrDefault(x => x.Tracks.Any(y => y.ID == obj.ID))
- .Then(x =>
- {
- t.Episode = x;
- t.EpisodeID = x?.ID ?? 0;
- }),
-
-
(Genre g, nameof(Genre.Shows)) => ShowRepository
.GetAll(x => x.Genres.Any(y => y.ID == obj.ID))
.Then(x => g.Shows = x),
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
index ab8bc7f5..e5fefb8f 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
@@ -44,11 +44,6 @@ namespace Kyoo.Core.Controllers
///
private readonly IProviderRepository _providers;
- ///
- /// A track repository to handle creation and deletion of tracks related to the current episode.
- ///
- private readonly Lazy _tracks;
-
///
// Use absolute numbers by default and fallback to season/episodes if it does not exists.
protected override Sort DefaultSort => new Sort.Conglomerate(
@@ -63,16 +58,13 @@ namespace Kyoo.Core.Controllers
/// The database handle to use.
/// A show repository
/// A provider repository
- /// A track repository
public EpisodeRepository(DatabaseContext database,
IShowRepository shows,
- IProviderRepository providers,
- Lazy tracks)
+ IProviderRepository providers)
: base(database)
{
_database = database;
_providers = providers;
- _tracks = tracks;
// Edit episode slugs when the show's slug changes.
shows.OnEdited += (show) =>
@@ -162,7 +154,7 @@ namespace Kyoo.Core.Controllers
? Get(obj.ShowID, obj.SeasonNumber.Value, obj.EpisodeNumber.Value)
: GetAbsolute(obj.ShowID, obj.AbsoluteNumber.Value));
OnResourceCreated(obj);
- return await _ValidateTracks(obj);
+ return obj;
}
///
@@ -170,13 +162,6 @@ namespace Kyoo.Core.Controllers
{
await Validate(changed);
- if (changed.Tracks != null || resetOld)
- {
- await _tracks.Value.DeleteAll(x => x.EpisodeID == resource.ID);
- resource.Tracks = changed.Tracks;
- await _ValidateTracks(resource);
- }
-
if (changed.ExternalIDs != null || resetOld)
{
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
@@ -184,25 +169,6 @@ namespace Kyoo.Core.Controllers
}
}
- ///
- /// Set track's index and ensure that every tracks is well-formed.
- ///
- /// The resource to fix.
- /// The parameter is returned.
- private async Task _ValidateTracks(Episode resource)
- {
- if (resource.Tracks == null)
- return resource;
-
- resource.Tracks = await resource.Tracks.SelectAsync(x =>
- {
- x.Episode = resource;
- return _tracks.Value.Create(x);
- }).ToListAsync();
- _database.Tracks.AttachRange(resource.Tracks);
- return resource;
- }
-
///
protected override async Task Validate(Episode resource)
{
@@ -236,7 +202,6 @@ namespace Kyoo.Core.Controllers
throw new ArgumentNullException(nameof(obj));
_database.Entry(obj).State = EntityState.Deleted;
- await obj.Tracks.ForEachAsync(x => _tracks.Value.Delete(x));
obj.ExternalIDs.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
await _database.SaveChangesAsync();
await base.Delete(obj);
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/TrackRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/TrackRepository.cs
deleted file mode 100644
index 83945c2e..00000000
--- a/back/src/Kyoo.Core/Controllers/Repositories/TrackRepository.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Postgresql;
-using Microsoft.EntityFrameworkCore;
-
-namespace Kyoo.Core.Controllers
-{
- ///
- /// A local repository to handle tracks.
- ///
- public class TrackRepository : LocalRepository, ITrackRepository
- {
- ///
- /// The database handle
- ///
- private readonly DatabaseContext _database;
-
- ///
- protected override Sort DefaultSort => new Sort.By(x => x.TrackIndex);
-
- ///
- /// Create a new .
- ///
- /// The database handle
- /// The episode repository
- public TrackRepository(DatabaseContext database, IEpisodeRepository episodes)
- : base(database)
- {
- _database = database;
-
- // Edit tracks slugs when the episodes's slug changes.
- episodes.OnEdited += (ep) =>
- {
- List tracks = _database.Tracks.AsTracking().Where(x => x.EpisodeID == ep.ID).ToList();
- foreach (Track track in tracks)
- {
- track.EpisodeSlug = ep.Slug;
- _database.SaveChanges();
- OnResourceEdited(track);
- }
- };
- }
-
- ///
- public override Task> Search(string query)
- {
- throw new InvalidOperationException("Tracks do not support the search method.");
- }
-
- ///
- protected override async Task Validate(Track resource)
- {
- await base.Validate(resource);
- if (resource.EpisodeID <= 0)
- {
- resource.EpisodeID = resource.Episode?.ID ?? 0;
- if (resource.EpisodeID <= 0)
- {
- throw new ArgumentException("Can't store a track not related to any episode " +
- $"(episodeID: {resource.EpisodeID}).");
- }
- }
- }
-
- ///
- public override async Task Create(Track obj)
- {
- if (obj == null)
- throw new ArgumentNullException(nameof(obj));
-
- await base.Create(obj);
- obj.EpisodeSlug = _database.Episodes.First(x => x.ID == obj.EpisodeID).Slug;
- _database.Entry(obj).State = EntityState.Added;
- await _database.SaveChangesAsync();
- OnResourceCreated(obj);
- return obj;
- }
-
- ///
- public override async Task Delete(Track obj)
- {
- if (obj == null)
- throw new ArgumentNullException(nameof(obj));
-
- _database.Entry(obj).State = EntityState.Deleted;
- await _database.SaveChangesAsync();
- await base.Delete(obj);
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs
index 45cefc35..9dbb7c40 100644
--- a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs
+++ b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs
@@ -19,13 +19,15 @@
using System;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Threading.Tasks;
-using JetBrains.Annotations;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;
+#nullable enable
+
namespace Kyoo.Core.Controllers
{
///
@@ -33,30 +35,27 @@ namespace Kyoo.Core.Controllers
///
public class ThumbnailsManager : IThumbnailsManager
{
- ///
- /// The file manager used to download the image if the file is distant
- ///
- private readonly IFileSystem _files;
-
///
/// A logger to report errors.
///
private readonly ILogger _logger;
+ private readonly IHttpClientFactory _clientFactory;
+
///
/// Create a new .
///
- /// The file manager to use.
+ /// Client factory
/// A logger to report errors
- public ThumbnailsManager(IFileSystem files,
+ public ThumbnailsManager(IHttpClientFactory clientFactory,
ILogger logger)
{
- _files = files;
+ _clientFactory = clientFactory;
_logger = logger;
}
///
- /// An helper function to download an image using a .
+ /// An helper function to download an image.
///
/// The distant url of the image
/// The local path of the image
@@ -70,12 +69,17 @@ namespace Kyoo.Core.Controllers
try
{
_logger.LogInformation("Downloading image {What}", what);
- AsyncRef mime = new();
- await using Stream reader = await _files.GetReader(url, mime);
+
+ HttpClient client = _clientFactory.CreateClient();
+ HttpResponseMessage response = await client.GetAsync(url);
+ response.EnsureSuccessStatusCode();
+ string mime = response.Content.Headers.ContentType?.MediaType!;
+ await using Stream reader = await response.Content.ReadAsStreamAsync();
+
string extension = new FileExtensionContentTypeProvider()
- .Mappings.FirstOrDefault(x => x.Value == mime.Value)
+ .Mappings.FirstOrDefault(x => x.Value == mime)
.Key;
- await using Stream local = await _files.NewFile(localPath + extension);
+ await using Stream local = File.Create(localPath + extension);
await reader.CopyToAsync(local);
return true;
}
@@ -101,8 +105,8 @@ namespace Kyoo.Core.Controllers
foreach ((int id, string image) in item.Images.Where(x => x.Value != null))
{
- string localPath = await _GetPrivateImagePath(item, id);
- if (alwaysDownload || !await _files.Exists(localPath))
+ string localPath = _GetPrivateImagePath(item, id);
+ if (alwaysDownload || !Path.Exists(localPath))
ret |= await _DownloadImage(image, localPath, $"The image n {id} of {name}");
}
@@ -113,34 +117,41 @@ namespace Kyoo.Core.Controllers
/// Retrieve the local path of an image of the given item without an extension .
///
/// The item to retrieve the poster from.
- /// The ID of the image. See for values.
+ /// The ID of the image. See for values.
/// The type of the item
/// The path of the image for the given resource, even if it does not exists
- private async Task _GetPrivateImagePath([NotNull] T item, int imageID)
+ private static string _GetPrivateImagePath(T item, int imageId)
{
if (item == null)
throw new ArgumentNullException(nameof(item));
- string directory = await _files.GetExtraDirectory(item);
- string imageName = imageID switch
+ string directory = item switch
+ {
+ IResource res => Path.Combine("/metadata", typeof(T).Name.ToLowerInvariant(), res.Slug),
+ _ => Path.Combine("/metadata", typeof(T).Name.ToLowerInvariant())
+ };
+ Directory.CreateDirectory(directory);
+ string imageName = imageId switch
{
Images.Poster => "poster",
Images.Logo => "logo",
Images.Thumbnail => "thumbnail",
Images.Trailer => "trailer",
- _ => $"{imageID}"
+ _ => $"{imageId}"
};
- return _files.Combine(directory, imageName);
+ return Path.Combine(directory, imageName);
}
///
- public async Task GetImagePath(T item, int imageID)
+ public string? GetImagePath(T item, int imageId)
where T : IThumbnails
{
- string basePath = await _GetPrivateImagePath(item, imageID);
- string directory = Path.GetDirectoryName(basePath);
+ string basePath = _GetPrivateImagePath(item, imageId);
+ string directory = Path.GetDirectoryName(basePath)!;
string baseFile = Path.GetFileName(basePath);
- return (await _files.ListFiles(directory!))
+ if (!Directory.Exists(directory))
+ return null;
+ return Directory.GetFiles(directory, "*", SearchOption.TopDirectoryOnly)
.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == baseFile);
}
}
diff --git a/back/src/Kyoo.Core/Controllers/Transcoder.cs b/back/src/Kyoo.Core/Controllers/Transcoder.cs
deleted file mode 100644
index 04bb3414..00000000
--- a/back/src/Kyoo.Core/Controllers/Transcoder.cs
+++ /dev/null
@@ -1,342 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Exceptions;
-using Kyoo.Core.Models.Options;
-using Kyoo.Core.Models.Watch;
-using Kyoo.Utils;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-
-namespace Kyoo.Core.Controllers
-{
- ///
- /// The transcoder used by the .
- ///
- public class Transcoder : ITranscoder
- {
-#pragma warning disable IDE1006
- ///
- /// The class that interact with the transcoder written in C.
- ///
- private static class TranscoderAPI
- {
- ///
- /// The name of the library. For windows '.dll' should be appended, on linux or macos it should be prefixed
- /// by 'lib' and '.so' or '.dylib' should be appended.
- ///
- private const string TranscoderPath = "transcoder";
-
- ///
- /// Initialize the C library, setup the logger and return the size of a .
- ///
- /// The size of a
- [DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
- private static extern int init();
-
- ///
- /// Initialize the C library, setup the logger and return the size of a .
- ///
- /// The size of a
- public static int Init() => init();
-
- ///
- /// Transmux the file at the specified path. The path must be a local one with '/' as a separator.
- ///
- /// The path of a local file with '/' as a separators.
- /// The path of the hls output file.
- ///
- /// The number of seconds currently playable. This is incremented as the file gets transmuxed.
- ///
- /// 0 on success, non 0 on failure.
- [DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
- CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
- private static extern int transmux(string path, string outPath, out float playableDuration);
-
- ///
- /// Transmux the file at the specified path. The path must be a local one.
- ///
- /// The path of a local file.
- /// The path of the hls output file.
- ///
- /// The number of seconds currently playable. This is incremented as the file gets transmuxed.
- ///
- /// 0 on success, non 0 on failure.
- public static int Transmux(string path, string outPath, out float playableDuration)
- {
- path = path.Replace('\\', '/');
- outPath = outPath.Replace('\\', '/');
- return transmux(path, outPath, out playableDuration);
- }
-
- ///
- /// Retrieve tracks from a video file and extract subtitles, fonts and chapters to an external file.
- ///
- ///
- /// The path of the video file to analyse. This must be a local path with '/' as a separator.
- ///
- /// The directory that will be used to store extracted files.
- /// The size of the returned array.
- /// The number of tracks in the returned array.
- /// Should the cache be invalidated and information re-extracted or not?
- /// A pointer to an array of
- [DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
- CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
- private static extern IntPtr extract_infos(string path,
- string outPath,
- out uint length,
- out uint trackCount,
- bool reExtract);
-
- ///
- /// An helper method to free an array of .
- ///
- /// A pointer to the first element of the array
- /// The number of items in the array.
- [DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
- private static extern void free_streams(IntPtr streams, uint count);
-
- ///
- /// Retrieve tracks from a video file and extract subtitles, fonts and chapters to an external file.
- ///
- /// The path of the video file to analyse. This must be a local path.
- /// The directory that will be used to store extracted files.
- /// Should the cache be invalidated and information re-extracted or not?
- /// An array of .
- public static Track[] ExtractInfos(string path, string outPath, bool reExtract)
- {
- path = path.Replace('\\', '/');
- outPath = outPath.Replace('\\', '/');
-
- int size = Marshal.SizeOf();
- IntPtr ptr = extract_infos(path, outPath, out uint arrayLength, out uint trackCount, reExtract);
- IntPtr streamsPtr = ptr;
- Track[] tracks;
-
- if (trackCount > 0 && ptr != IntPtr.Zero)
- {
- tracks = new Track[trackCount];
-
- int j = 0;
- for (int i = 0; i < arrayLength; i++, streamsPtr += size)
- {
- FTrack stream = Marshal.PtrToStructure(streamsPtr);
- if (stream!.Type == FTrackType.Unknown || stream.Type == FTrackType.Attachment)
- continue;
- tracks[j] = stream.ToTrack();
- j++;
- }
- Array.Resize(ref tracks, j);
- }
- else
- tracks = Array.Empty();
-
- if (ptr != IntPtr.Zero)
- free_streams(ptr, trackCount);
- return tracks;
- }
- }
-#pragma warning restore IDE1006
-
- ///
- /// The file system used to retrieve the extra directory of shows to know where to extract information.
- ///
- private readonly IFileSystem _files;
-
- ///
- /// Options to know where to cache transmuxed/transcoded episodes.
- ///
- private readonly IOptions _options;
-
- ///
- /// The logger to use. This is also used by the wrapped C library.
- ///
- private readonly ILogger _logger;
-
- ///
- /// if the C library has been checked, otherwise.
- ///
- private bool _initialized;
-
- ///
- /// Create a new .
- ///
- ///
- /// The file system used to retrieve the extra directory of shows to know where to extract information.
- ///
- /// Options to know where to cache transmuxed/transcoded episodes.
- /// The logger to use. This is also used by the wrapped C library.
- public Transcoder(IFileSystem files, IOptions options, ILogger logger)
- {
- _files = files;
- _options = options;
- _logger = logger;
- }
-
- ///
- /// Check if the C library can be used or if there is an issue with it.
- ///
- /// Should the healthcheck be abborted if the transcoder was already initialized?
- /// If the transcoder is corrupted, this exception in thrown.
- public void CheckHealth(bool fastStop = false)
- {
- if (fastStop && _initialized)
- return;
- if (TranscoderAPI.Init() != Marshal.SizeOf())
- {
- _logger.LogCritical("The transcoder library could not be initialized correctly");
- throw new HealthException("The transcoder library is corrupted or invalid.");
- }
- _initialized = true;
- }
-
- ///
- public async Task> ExtractInfos(Episode episode, bool reExtract)
- {
- CheckHealth(true);
-
- string dir = await _files.GetExtraDirectory(episode);
- if (dir == null)
- throw new ArgumentException("Invalid path.");
- return await Task.Factory.StartNew(
- () => TranscoderAPI.ExtractInfos(episode.Path, dir, reExtract),
- TaskCreationOptions.LongRunning
- );
- }
-
- ///
- public async Task> ListFonts(Episode episode)
- {
- string path = _files.Combine(await _files.GetExtraDirectory(episode), "Attachments");
- return (await _files.ListFiles(path))
- .Select(x => new Font(x, episode.Slug))
- .ToArray();
- }
-
- ///
- public async Task GetFont(Episode episode, string slug)
- {
- string path = _files.Combine(await _files.GetExtraDirectory(episode), "Attachments");
- string font = (await _files.ListFiles(path))
- .FirstOrDefault(x => Utility.ToSlug(Path.GetFileNameWithoutExtension(x)) == slug);
- if (font == null)
- return null;
- return new Font(font, episode.Slug);
- }
-
- ///
- public IActionResult Transmux(Episode episode)
- {
- CheckHealth(true);
-
- string folder = Path.Combine(_options.Value.TransmuxPath, episode.Slug);
- string manifest = Path.GetFullPath(Path.Combine(folder, episode.Slug + ".m3u8"));
-
- try
- {
- Directory.CreateDirectory(folder);
- if (File.Exists(manifest))
- return new PhysicalFileResult(manifest, "application/x-mpegurl");
- }
- catch (UnauthorizedAccessException)
- {
- _logger.LogCritical("Access to the path {Manifest} is denied. " +
- "Please change your transmux path in the config", manifest);
- return new StatusCodeResult(500);
- }
-
- return new TransmuxResult(episode.Path, manifest, _logger);
- }
-
- ///
- /// An action result that runs the transcoder and return the created manifest file after a few seconds of
- /// the video has been proceeded. If the transcoder fails, it returns a 500 error code.
- ///
- private class TransmuxResult : IActionResult
- {
- ///
- /// The path of the episode to transmux. It must be a local one.
- ///
- private readonly string _path;
-
- ///
- /// The path of the manifest file to create. It must be a local one.
- ///
- private readonly string _manifest;
-
- ///
- /// The logger to use in case of issue.
- ///
- private readonly ILogger _logger;
-
- ///
- /// Create a new .
- ///
- /// The path of the episode to transmux. It must be a local one.
- /// The path of the manifest file to create. It must be a local one.
- /// The logger to use in case of issue.
- public TransmuxResult(string path, string manifest, ILogger logger)
- {
- _path = path;
- _manifest = Path.GetFullPath(manifest);
- _logger = logger;
- }
-
- // We use threads so tasks are not always awaited.
-#pragma warning disable 4014
-
- ///
- public async Task ExecuteResultAsync(ActionContext context)
- {
- float playableDuration = 0;
- bool transmuxFailed = false;
-
- Task.Factory.StartNew(() =>
- {
- transmuxFailed = TranscoderAPI.Transmux(_path, _manifest, out playableDuration) != 0;
- }, TaskCreationOptions.LongRunning);
-
- while (playableDuration < 10 || (!File.Exists(_manifest) && !transmuxFailed))
- await Task.Delay(10);
-
- if (!transmuxFailed)
- {
- new PhysicalFileResult(_manifest, "application/x-mpegurl")
- .ExecuteResultAsync(context);
- }
- else
- {
- _logger.LogCritical("The transmuxing failed on the C library");
- new StatusCodeResult(500)
- .ExecuteResultAsync(context);
- }
- }
-
-#pragma warning restore 4014
- }
- }
-}
diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs
index 4160b9a5..5c55c01b 100644
--- a/back/src/Kyoo.Core/CoreModule.cs
+++ b/back/src/Kyoo.Core/CoreModule.cs
@@ -27,7 +27,6 @@ using Kyoo.Core.Controllers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
-using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
@@ -46,10 +45,6 @@ namespace Kyoo.Core
///
public void Configure(ContainerBuilder builder)
{
- builder.RegisterType().As().SingleInstance();
- builder.RegisterType().As().SingleInstance();
-
- builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().InstancePerLifetimeScope();
builder.RegisterType().As().InstancePerLifetimeScope();
@@ -59,22 +54,11 @@ namespace Kyoo.Core
builder.RegisterRepository();
builder.RegisterRepository();
builder.RegisterRepository();
- builder.RegisterRepository();
builder.RegisterRepository();
builder.RegisterRepository();
builder.RegisterRepository();
builder.RegisterRepository();
builder.RegisterRepository();
-
- builder.RegisterType().As().SingleInstance()
- .OnActivating(x =>
- {
- x.Instance.Mappings[".data"] = "application/octet-stream";
- x.Instance.Mappings[".mkv"] = "video/x-matroska";
- x.Instance.Mappings[".ass"] = "text/x-ssa";
- x.Instance.Mappings[".srt"] = "application/x-subrip";
- x.Instance.Mappings[".m3u8"] = "application/x-mpegurl";
- });
}
///
diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj
index 88166a30..917b6986 100644
--- a/back/src/Kyoo.Core/Kyoo.Core.csproj
+++ b/back/src/Kyoo.Core/Kyoo.Core.csproj
@@ -2,13 +2,6 @@
Kyoo.Core
Kyoo.Core
- ../Kyoo.Transcoder/
-
-
-
- transcoder.dll
- libtranscoder.dylib
- libtranscoder.so
@@ -22,21 +15,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- PreserveNewest
- false
-
-
diff --git a/back/src/Kyoo.Core/Models/FTrack.cs b/back/src/Kyoo.Core/Models/FTrack.cs
deleted file mode 100644
index cb779e23..00000000
--- a/back/src/Kyoo.Core/Models/FTrack.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System.Runtime.InteropServices;
-using Kyoo.Abstractions.Models;
-
-namespace Kyoo.Core.Models.Watch
-{
- ///
- /// The list of available stream types.
- /// Attachments are only used temporarily by the transcoder but are not stored in a database.
- /// This is another enum used internally to communicate with ffmpeg.
- ///
- public enum FTrackType
- {
- ///
- /// The type of the stream is not known.
- ///
- Unknown = StreamType.Unknown,
-
- ///
- /// The stream is a video.
- ///
- Video = StreamType.Video,
-
- ///
- /// The stream is an audio.
- ///
- Audio = StreamType.Audio,
-
- ///
- /// The stream is a subtitle.
- ///
- Subtitle = StreamType.Subtitle,
-
- ///
- /// The stream is an attachment (a font, an image or something else).
- /// Only fonts are handled by kyoo but they are not saved to the database.
- ///
- Attachment
- }
-
- ///
- /// The unmanaged stream that the transcoder will return.
- ///
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct FTrack
- {
- ///
- /// The title of the stream.
- ///
- public string Title;
-
- ///
- /// The language of this stream (as a ISO-639-2 language code)
- ///
- public string Language;
-
- ///
- /// The codec of this stream.
- ///
- public string Codec;
-
- ///
- /// Is this stream the default one of it's type?
- ///
- [MarshalAs(UnmanagedType.I1)] public bool IsDefault;
-
- ///
- /// Is this stream tagged as forced?
- ///
- [MarshalAs(UnmanagedType.I1)] public bool IsForced;
-
- ///
- /// The path of this track.
- ///
- public string Path;
-
- ///
- /// The type of this stream.
- ///
- public FTrackType Type;
-
- ///
- /// Create a track from this stream.
- ///
- /// A new track that represent this stream.
- public Track ToTrack()
- {
- return new()
- {
- Title = Title,
- Language = Language,
- Codec = Codec,
- IsDefault = IsDefault,
- IsForced = IsForced,
- Path = Path,
- Type = Type < FTrackType.Attachment ? (StreamType)Type : StreamType.Unknown,
- IsExternal = false
- };
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Models/Options/BasicOptions.cs b/back/src/Kyoo.Core/Models/Options/BasicOptions.cs
deleted file mode 100644
index 056a8686..00000000
--- a/back/src/Kyoo.Core/Models/Options/BasicOptions.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-namespace Kyoo.Core.Models.Options
-{
- ///
- /// The typed list of basic/global options for Kyoo
- ///
- public class BasicOptions
- {
- ///
- /// The path of this list of options
- ///
- public const string Path = "Basics";
-
- ///
- /// The temporary folder to cache transmuxed file.
- ///
- public string TransmuxPath { get; set; } = "cached/transmux";
-
- ///
- /// The temporary folder to cache transcoded file.
- ///
- public string TranscodePath { get; set; } = "cached/transcode";
-
- ///
- /// The path where metadata is stored.
- ///
- public string MetadataPath { get; set; } = "metadata/";
- }
-}
diff --git a/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs b/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
index 8bff58e8..20a9715c 100644
--- a/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
+++ b/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
@@ -16,6 +16,8 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
+using System;
+using System.IO;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -23,6 +25,7 @@ using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Abstractions.Models.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.StaticFiles;
using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api
@@ -37,11 +40,6 @@ namespace Kyoo.Core.Api
public class CrudThumbsApi : CrudApi
where T : class, IResource, IThumbnails
{
- ///
- /// The file manager used to send images.
- ///
- private readonly IFileSystem _files;
-
///
/// The thumbnail manager used to retrieve images paths.
///
@@ -53,17 +51,28 @@ namespace Kyoo.Core.Api
///
/// The repository to use as a baking store for the type .
///
- /// The file manager used to send images.
/// The thumbnail manager used to retrieve images paths.
public CrudThumbsApi(IRepository repository,
- IFileSystem files,
IThumbnailsManager thumbs)
: base(repository)
{
- _files = files;
_thumbs = thumbs;
}
+ ///
+ /// Get the content type of a file using it's extension.
+ ///
+ /// The path of the file
+ /// The extension of the file is not known.
+ /// The content type of the file
+ private static string _GetContentType(string path)
+ {
+ FileExtensionContentTypeProvider provider = new();
+ if (provider.TryGetContentType(path, out string contentType))
+ return contentType;
+ throw new NotImplementedException($"Can't get the content type of the file at: {path}");
+ }
+
///
/// Get image
///
@@ -80,11 +89,7 @@ namespace Kyoo.Core.Api
/// The number of the image to retrieve.
/// The image asked.
/// No item exist with the specific identifier or the image does not exists on kyoo.
- [HttpGet("{identifier:id}/image-{image:int}")]
- [PartialPermission(Kind.Read)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task GetImage(Identifier identifier, int image)
+ private async Task _GetImage(Identifier identifier, int image)
{
T resource = await identifier.Match(
id => Repository.GetOrDefault(id),
@@ -92,8 +97,10 @@ namespace Kyoo.Core.Api
);
if (resource == null)
return NotFound();
- string path = await _thumbs.GetImagePath(resource, image);
- return _files.FileResult(path);
+ string path = _thumbs.GetImagePath(resource, image);
+ if (path == null || !System.IO.File.Exists(path))
+ return NotFound();
+ return PhysicalFile(Path.GetFullPath(path), _GetContentType(path), true);
}
///
@@ -113,7 +120,7 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)]
public Task GetPoster(Identifier identifier)
{
- return GetImage(identifier, Images.Poster);
+ return _GetImage(identifier, Images.Poster);
}
///
@@ -133,7 +140,7 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)]
public Task GetLogo(Identifier identifier)
{
- return GetImage(identifier, Images.Logo);
+ return _GetImage(identifier, Images.Logo);
}
///
@@ -151,7 +158,7 @@ namespace Kyoo.Core.Api
[HttpGet("{identifier:id}/thumbnail", Order = AlternativeRoute)]
public Task GetBackdrop(Identifier identifier)
{
- return GetImage(identifier, Images.Thumbnail);
+ return _GetImage(identifier, Images.Thumbnail);
}
///
diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs
index 796f9f70..c272e942 100644
--- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs
+++ b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs
@@ -16,7 +16,6 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
-using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
diff --git a/back/src/Kyoo.Core/Views/Metadata/ProviderApi.cs b/back/src/Kyoo.Core/Views/Metadata/ProviderApi.cs
deleted file mode 100644
index 97369ddf..00000000
--- a/back/src/Kyoo.Core/Views/Metadata/ProviderApi.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Attributes;
-using Kyoo.Abstractions.Models.Permissions;
-using Microsoft.AspNetCore.Mvc;
-using static Kyoo.Abstractions.Models.Utils.Constants;
-
-namespace Kyoo.Core.Api
-{
- ///
- /// Information about one or multiple .
- /// Providers are links to external websites or database.
- /// They are mostly linked to plugins that provide metadata from those websites.
- ///
- [Route("providers")]
- [Route("provider", Order = AlternativeRoute)]
- [ApiController]
- [ResourceView]
- [PartialPermission(nameof(Provider))]
- [ApiDefinition("Providers", Group = MetadataGroup)]
- public class ProviderApi : CrudThumbsApi
- {
- ///
- /// Create a new .
- ///
- ///
- /// The library manager used to modify or retrieve information about the data store.
- ///
- /// The file manager used to send images and fonts.
- /// The thumbnail manager used to retrieve images paths.
- public ProviderApi(ILibraryManager libraryManager,
- IFileSystem files,
- IThumbnailsManager thumbnails)
- : base(libraryManager.ProviderRepository, files, thumbnails)
- { }
- }
-}
diff --git a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs
index 682b027a..afcfe3b0 100644
--- a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs
+++ b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs
@@ -53,12 +53,10 @@ namespace Kyoo.Core.Api
///
/// The library manager used to modify or retrieve information about the data store.
///
- /// The file manager used to send images and fonts.
/// The thumbnail manager used to retrieve images paths.
public StaffApi(ILibraryManager libraryManager,
- IFileSystem files,
IThumbnailsManager thumbs)
- : base(libraryManager.PeopleRepository, files, thumbs)
+ : base(libraryManager.PeopleRepository, thumbs)
{
_libraryManager = libraryManager;
}
diff --git a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs
index e09ba2e5..ffd13752 100644
--- a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs
+++ b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs
@@ -51,12 +51,10 @@ namespace Kyoo.Core.Api
///
/// The library manager used to modify or retrieve information about the data store.
///
- /// The file manager used to send images.
/// The thumbnail manager used to retrieve images paths.
public CollectionApi(ILibraryManager libraryManager,
- IFileSystem files,
IThumbnailsManager thumbs)
- : base(libraryManager.CollectionRepository, files, thumbs)
+ : base(libraryManager.CollectionRepository, thumbs)
{
_libraryManager = libraryManager;
}
diff --git a/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs b/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs
index 188f3c81..6b73a246 100644
--- a/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs
+++ b/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs
@@ -16,15 +16,12 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
-using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Abstractions.Models.Utils;
-using Kyoo.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static Kyoo.Abstractions.Models.Utils.Constants;
@@ -47,43 +44,18 @@ namespace Kyoo.Core.Api
///
private readonly ILibraryManager _libraryManager;
- ///
- /// The transcoder used to retrive fonts.
- ///
- private readonly ITranscoder _transcoder;
-
- ///
- /// The file system used to send fonts.
- ///
- private readonly IFileSystem _files;
-
///
/// Create a new .
///
///
/// The library manager used to modify or retrieve information in the data store.
///
- /// The transcoder used to retrive fonts
- /// The file manager used to send images.
/// The thumbnail manager used to retrieve images paths.
public EpisodeApi(ILibraryManager libraryManager,
- ITranscoder transcoder,
- IFileSystem files,
IThumbnailsManager thumbnails)
- : base(libraryManager.EpisodeRepository, files, thumbnails)
+ : base(libraryManager.EpisodeRepository, thumbnails)
{
_libraryManager = libraryManager;
- _transcoder = transcoder;
- _files = files;
- }
-
- ///
- public override async Task> Create([FromBody] Episode resource)
- {
- // TODO: Remove this method and use a websocket API to do that.
- resource.Tracks = await _transcoder.ExtractInfos(resource, false);
- ActionResult ret = await base.Create(resource);
- return ret;
}
///
@@ -132,43 +104,5 @@ namespace Kyoo.Core.Api
? NotFound()
: NoContent();
}
-
- ///
- /// Get tracks
- ///
- ///
- /// List the tracks (video, audio and subtitles) available for this episode.
- /// This endpoint provide the list of raw tracks, without transcode on it. To get a schema easier to watch
- /// on a player, see the [/watch endpoint](#/watch).
- ///
- /// The ID or slug of the .
- /// A key to sort tracks by.
- /// An optional list of filters.
- /// The number of tracks to return.
- /// A page of tracks.
- /// The filters or the sort parameters are invalid.
- /// No episode with the given ID or slug could be found.
- /// TODO fix the /watch endpoint link (when operations ID are specified).
- [HttpGet("{identifier:id}/tracks")]
- [HttpGet("{identifier:id}/track", Order = AlternativeRoute)]
- [PartialPermission(Kind.Read)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task>> GetEpisode(Identifier identifier,
- [FromQuery] string sortBy,
- [FromQuery] Dictionary where,
- [FromQuery] Pagination pagination)
- {
- ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, identifier.Matcher(x => x.EpisodeID, x => x.Episode.Slug)),
- Sort.From(sortBy),
- pagination
- );
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
- return NotFound();
- return Page(resources, pagination.Limit);
- }
}
}
diff --git a/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs b/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs
index ca0acff5..d336e22c 100644
--- a/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs
+++ b/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs
@@ -51,12 +51,10 @@ namespace Kyoo.Core.Api
///
/// The library manager used to modify or retrieve information in the data store.
///
- /// The file manager used to send images.
/// The thumbnail manager used to retrieve images paths.
public SeasonApi(ILibraryManager libraryManager,
- IFileSystem files,
IThumbnailsManager thumbs)
- : base(libraryManager.SeasonRepository, files, thumbs)
+ : base(libraryManager.SeasonRepository, thumbs)
{
_libraryManager = libraryManager;
}
diff --git a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs
index 7fb6a843..95a9492e 100644
--- a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs
+++ b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs
@@ -48,7 +48,6 @@ namespace Kyoo.Core.Api
/// The library manager used to modify or retrieve information in the data store.
///
private readonly ILibraryManager _libraryManager;
- private readonly ITranscoder _transcoder;
///
/// Create a new .
@@ -56,17 +55,12 @@ namespace Kyoo.Core.Api
///
/// The library manager used to modify or retrieve information about the data store.
///
- /// The file manager used to send images and fonts.
/// The thumbnail manager used to retrieve images paths.
- /// TODO: Remove this.
public ShowApi(ILibraryManager libraryManager,
- IFileSystem files,
- IThumbnailsManager thumbs,
- ITranscoder transcoder)
- : base(libraryManager.ShowRepository, files, thumbs)
+ IThumbnailsManager thumbs)
+ : base(libraryManager.ShowRepository, thumbs)
{
_libraryManager = libraryManager;
- _transcoder = transcoder;
}
///
@@ -82,7 +76,6 @@ namespace Kyoo.Core.Api
Path = ret.Value.Path
};
- episode.Tracks = await _transcoder.ExtractInfos(episode, false);
await _libraryManager.Create(episode);
}
return ret;
diff --git a/back/src/Kyoo.Core/Views/Watch/SubtitleApi.cs b/back/src/Kyoo.Core/Views/Watch/SubtitleApi.cs
deleted file mode 100644
index 7e89bef6..00000000
--- a/back/src/Kyoo.Core/Views/Watch/SubtitleApi.cs
+++ /dev/null
@@ -1,205 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Attributes;
-using Kyoo.Abstractions.Models.Permissions;
-using Kyoo.Abstractions.Models.Utils;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using static Kyoo.Abstractions.Models.Utils.Constants;
-
-namespace Kyoo.Core.Api
-{
- ///
- /// An endpoint to retrieve subtitles for a specific episode.
- ///
- [Route("subtitles")]
- [Route("subtitle", Order = AlternativeRoute)]
- [PartialPermission("subtitle")]
- [ApiController]
- [ApiDefinition("Subtitles", Group = WatchGroup)]
- public class SubtitleApi : ControllerBase
- {
- ///
- /// The library manager used to modify or retrieve information about the data store.
- ///
- private readonly ILibraryManager _libraryManager;
-
- ///
- /// The file manager used to send subtitles files.
- ///
- private readonly IFileSystem _files;
-
- ///
- /// Create a new .
- ///
- /// The library manager used to interact with the data store.
- /// The file manager used to send subtitle files.
- public SubtitleApi(ILibraryManager libraryManager, IFileSystem files)
- {
- _libraryManager = libraryManager;
- _files = files;
- }
-
- ///
- /// Get subtitle
- ///
- ///
- /// Get the subtitle file with the given identifier.
- /// The extension is optional and can be used to ask Kyoo to convert the subtitle file on the fly.
- ///
- ///
- /// The ID or slug of the subtitle (the same as the corresponding ).
- ///
- /// An optional extension for the subtitle file.
- /// The subtitle file
- /// No subtitle exist with the given ID or slug.
- [HttpGet("{identifier:int}", Order = AlternativeRoute)]
- [HttpGet("{identifier:id}.{extension}")]
- [PartialPermission(Kind.Read)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- [SuppressMessage("ReSharper", "RouteTemplates.ParameterTypeAndConstraintsMismatch",
- Justification = "An indentifier can be constructed with an int.")]
- public async Task GetSubtitle(Identifier identifier, string extension)
- {
- Track subtitle = await identifier.Match(
- id => _libraryManager.GetOrDefault(id),
- slug =>
- {
- if (slug.Count(x => x == '.') == 3)
- {
- int idx = slug.LastIndexOf('.');
- extension = slug[(idx + 1)..];
- slug = slug[..idx];
- }
- return _libraryManager.GetOrDefault(Track.BuildSlug(slug, StreamType.Subtitle));
- });
-
- if (subtitle == null)
- return NotFound();
- if (subtitle.Codec == "subrip" && extension == "vtt")
- return new ConvertSubripToVtt(subtitle.Path, _files);
- return _files.FileResult(subtitle.Path);
- }
-
- ///
- /// An action result that convert a subrip subtitle to vtt.
- ///
- private class ConvertSubripToVtt : IActionResult
- {
- ///
- /// The path of the file to convert. It can be any path supported by a .
- ///
- private readonly string _path;
-
- ///
- /// The file system used to manipulate the given file.
- ///
- private readonly IFileSystem _files;
-
- ///
- /// Create a new .
- ///
- ///
- /// The path of the subtitle file. It can be any path supported by the given .
- ///
- ///
- /// The file system used to interact with the file at the given .
- ///
- public ConvertSubripToVtt(string subtitlePath, IFileSystem files)
- {
- _path = subtitlePath;
- _files = files;
- }
-
- ///
- public async Task ExecuteResultAsync(ActionContext context)
- {
- List lines = new();
-
- context.HttpContext.Response.StatusCode = 200;
- context.HttpContext.Response.Headers.Add("Content-Type", "text/vtt");
-
- await using (StreamWriter writer = new(context.HttpContext.Response.Body))
- {
- await writer.WriteLineAsync("WEBVTT");
- await writer.WriteLineAsync(string.Empty);
- await writer.WriteLineAsync(string.Empty);
-
- using StreamReader reader = new(await _files.GetReader(_path));
- string line;
- while ((line = await reader.ReadLineAsync()) != null)
- {
- if (line == string.Empty)
- {
- lines.Add(string.Empty);
- IEnumerable processedBlock = _ConvertBlock(lines);
- foreach (string t in processedBlock)
- await writer.WriteLineAsync(t);
- lines.Clear();
- }
- else
- lines.Add(line);
- }
- }
-
- await context.HttpContext.Response.Body.FlushAsync();
- }
-
- ///
- /// Convert a block from subrip to vtt.
- ///
- /// All the lines in the block.
- /// The given block, converted to vtt.
- private static IList _ConvertBlock(IList lines)
- {
- if (lines.Count < 3)
- return lines;
- lines[1] = lines[1].Replace(',', '.');
- if (lines[2].Length > 5)
- {
- lines[1] += lines[2].Substring(0, 6) switch
- {
- "{\\an1}" => " line:93% position:15%",
- "{\\an2}" => " line:93%",
- "{\\an3}" => " line:93% position:85%",
- "{\\an4}" => " line:50% position:15%",
- "{\\an5}" => " line:50%",
- "{\\an6}" => " line:50% position:85%",
- "{\\an7}" => " line:7% position:15%",
- "{\\an8}" => " line:7%",
- "{\\an9}" => " line:7% position:85%",
- _ => " line:93%"
- };
- }
-
- if (lines[2].StartsWith("{\\an"))
- lines[2] = lines[2][6..];
- return lines;
- }
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Views/Watch/TrackApi.cs b/back/src/Kyoo.Core/Views/Watch/TrackApi.cs
deleted file mode 100644
index 29d31323..00000000
--- a/back/src/Kyoo.Core/Views/Watch/TrackApi.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Attributes;
-using Kyoo.Abstractions.Models.Permissions;
-using Kyoo.Abstractions.Models.Utils;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using static Kyoo.Abstractions.Models.Utils.Constants;
-
-namespace Kyoo.Core.Api
-{
- ///
- /// Information about one or multiple .
- /// A track contain metadata about a video, an audio or a subtitles.
- ///
- [Route("tracks")]
- [Route("track", Order = AlternativeRoute)]
- [ApiController]
- [ResourceView]
- [PartialPermission(nameof(Track))]
- [ApiDefinition("Tracks", Group = WatchGroup)]
- public class TrackApi : CrudApi
- {
- ///
- /// The library manager used to modify or retrieve information in the data store.
- ///
- private readonly ILibraryManager _libraryManager;
-
- ///
- /// Create a new .
- ///
- ///
- /// The library manager used to modify or retrieve information in the data store.
- ///
- public TrackApi(ILibraryManager libraryManager)
- : base(libraryManager.TrackRepository)
- {
- _libraryManager = libraryManager;
- }
-
- ///
- /// Get track's episode
- ///
- ///
- /// Get the episode that uses this track.
- ///
- /// The ID or slug of the .
- /// The episode that uses this track.
- /// No track with the given ID or slug could be found.
- [HttpGet("{identifier:id}/episode")]
- [PartialPermission(Kind.Read)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task> GetEpisode(Identifier identifier)
- {
- return await _libraryManager.Get(identifier.IsContainedIn(x => x.Tracks));
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Views/Watch/WatchApi.cs b/back/src/Kyoo.Core/Views/Watch/WatchApi.cs
index 506176ad..24f53174 100644
--- a/back/src/Kyoo.Core/Views/Watch/WatchApi.cs
+++ b/back/src/Kyoo.Core/Views/Watch/WatchApi.cs
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
+using System.Net.Http;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -46,14 +47,9 @@ namespace Kyoo.Core.Api
private readonly ILibraryManager _libraryManager;
///
- /// A file system used to retrieve chapters informations.
+ /// The http client to reach transcoder.
///
- private readonly IFileSystem _files;
-
- ///
- /// The transcoder used to list fonts.
- ///
- private readonly ITranscoder _transcoder;
+ private readonly HttpClient _client;
///
/// Create a new .
@@ -61,13 +57,11 @@ namespace Kyoo.Core.Api
///
/// The library manager used to modify or retrieve information in the data store.
///
- /// A file system used to retrieve chapters informations.
- /// The transcoder used to list fonts.
- public WatchApi(ILibraryManager libraryManager, IFileSystem fs, ITranscoder transcoder)
+ /// The http client to reach transcoder.
+ public WatchApi(ILibraryManager libraryManager, HttpClient client)
{
_libraryManager = libraryManager;
- _files = fs;
- _transcoder = transcoder;
+ _client = client;
}
///
@@ -91,38 +85,7 @@ namespace Kyoo.Core.Api
);
if (item == null)
return NotFound();
- return await WatchItem.FromEpisode(item, _libraryManager, _files, _transcoder);
- }
-
- ///
- /// Get font
- ///
- ///
- /// Get a font file that is used in subtitles of this episode.
- ///
- /// The ID or slug of the .
- /// The slug of the font to retrieve.
- /// A page of collections.
- /// No show with the given ID/slug could be found or the font does not exist.
- [HttpGet("{identifier:id}/fonts/{slug}")]
- [HttpGet("{identifier:id}/font/{slug}", Order = AlternativeRoute)]
- [PartialPermission(Kind.Read)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task GetFont(Identifier identifier, string slug)
- {
- Episode episode = await identifier.Match(
- id => _libraryManager.GetOrDefault(id),
- slug => _libraryManager.GetOrDefault(slug)
- );
- if (episode == null)
- return NotFound();
- if (slug.Contains('.'))
- slug = slug[..slug.LastIndexOf('.')];
- Font font = await _transcoder.GetFont(episode, slug);
- if (font == null)
- return NotFound();
- return _files.FileResult(font.Path);
+ return await WatchItem.FromEpisode(item, _libraryManager, _client);
}
}
}
diff --git a/back/src/Kyoo.Host/Contollers/FileSystemComposite.cs b/back/src/Kyoo.Host/Contollers/FileSystemComposite.cs
deleted file mode 100644
index 71e5ff22..00000000
--- a/back/src/Kyoo.Host/Contollers/FileSystemComposite.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Autofac.Features.Metadata;
-using JetBrains.Annotations;
-using Kyoo.Abstractions.Controllers;
-using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Attributes;
-using Kyoo.Core.Models.Options;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Options;
-
-namespace Kyoo.Host.Controllers
-{
- ///
- /// A composite that merge every available
- /// using .
- ///
- public class FileSystemComposite : IFileSystem
- {
- ///
- /// The list of mapped to their metadata.
- ///
- private readonly ICollection , FileSystemMetadataAttribute>> _fileSystems;
-
- ///
- /// Options to check if the metadata should be kept in the show directory or in a kyoo's directory.
- ///
- private readonly IOptionsMonitor _options;
-
- ///
- /// Create a new from a list of mapped to their
- /// metadata.
- ///
- /// The list of filesystem mapped to their metadata.
- /// The options to use.
- public FileSystemComposite(ICollection , FileSystemMetadataAttribute>> fileSystems,
- IOptionsMonitor options)
- {
- _fileSystems = fileSystems;
- _options = options;
- }
-
- ///
- /// Retrieve the file system that should be used for a given path.
- ///
- ///
- /// The path that was requested.
- ///
- ///
- /// The path that the returned file system wants
- /// (respecting ).
- ///
- /// No file system was registered for the given path.
- /// The file system that should be used for a given path
- [NotNull]
- private IFileSystem _GetFileSystemForPath([NotNull] string path, [NotNull] out string usablePath)
- {
- Regex schemeMatcher = new(@"(.+)://(.*)", RegexOptions.Compiled);
- Match match = schemeMatcher.Match(path);
-
- if (!match.Success)
- {
- usablePath = path;
- Meta, FileSystemMetadataAttribute> defaultFs = _fileSystems
- .SingleOrDefault(x => x.Metadata.Scheme.Contains(string.Empty));
- if (defaultFs == null)
- throw new ArgumentException($"No file system registered for the default scheme.");
- return defaultFs.Value.Invoke();
- }
- string scheme = match.Groups[1].Value;
- Meta, FileSystemMetadataAttribute> ret = _fileSystems
- .SingleOrDefault(x => x.Metadata.Scheme.Contains(scheme));
- if (ret == null)
- throw new ArgumentException($"No file system registered for the scheme: {scheme}.");
- usablePath = ret.Metadata.StripScheme ? match.Groups[2].Value : path;
- return ret.Value.Invoke();
- }
-
- ///
- public IActionResult FileResult(string path, bool rangeSupport = false, string type = null)
- {
- if (path == null)
- return new NotFoundResult();
- return _GetFileSystemForPath(path, out string relativePath)
- .FileResult(relativePath, rangeSupport, type);
- }
-
- ///
- public Task GetReader(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return _GetFileSystemForPath(path, out string relativePath)
- .GetReader(relativePath);
- }
-
- ///
- public Task GetReader(string path, AsyncRef mime)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return _GetFileSystemForPath(path, out string relativePath)
- .GetReader(relativePath, mime);
- }
-
- ///
- public Task NewFile(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return _GetFileSystemForPath(path, out string relativePath)
- .NewFile(relativePath);
- }
-
- ///
- public Task CreateDirectory(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return _GetFileSystemForPath(path, out string relativePath)
- .CreateDirectory(relativePath);
- }
-
- ///
- public string Combine(params string[] paths)
- {
- return _GetFileSystemForPath(paths[0], out string relativePath)
- .Combine(paths[1..].Prepend(relativePath).ToArray());
- }
-
- ///
- public Task> ListFiles(string path, SearchOption options = SearchOption.TopDirectoryOnly)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return _GetFileSystemForPath(path, out string relativePath)
- .ListFiles(relativePath, options);
- }
-
- ///
- public Task Exists(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- return _GetFileSystemForPath(path, out string relativePath)
- .Exists(relativePath);
- }
-
- ///
- public Task GetExtraDirectory(T resource)
- {
- IFileSystem fs = _GetFileSystemForPath(_options.CurrentValue.MetadataPath, out string path);
- return fs.GetExtraDirectory(resource);
- }
-
- ///
- public Task> ExtractInfos(Episode episode, bool reExtract)
- {
- IFileSystem fs = _GetFileSystemForPath(episode.Path, out string _);
- return fs.ExtractInfos(episode, reExtract);
- }
-
- ///
- public IActionResult Transmux(Episode episode)
- {
- IFileSystem fs = _GetFileSystemForPath(episode.Path, out string _);
- return fs.Transmux(episode);
- }
- }
-}
diff --git a/back/src/Kyoo.Host/Contollers/PluginManager.cs b/back/src/Kyoo.Host/Contollers/PluginManager.cs
index 01a68311..6305c1b1 100644
--- a/back/src/Kyoo.Host/Contollers/PluginManager.cs
+++ b/back/src/Kyoo.Host/Contollers/PluginManager.cs
@@ -20,10 +20,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Kyoo.Abstractions.Controllers;
-using Kyoo.Core.Models.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
namespace Kyoo.Host.Controllers
{
@@ -38,11 +36,6 @@ namespace Kyoo.Host.Controllers
///
private readonly IServiceProvider _provider;
- ///
- /// The configuration to get the plugin's directory.
- ///
- private readonly IOptions _options;
-
///
/// The logger used by this class.
///
@@ -57,14 +50,11 @@ namespace Kyoo.Host.Controllers
/// Create a new instance.
///
/// A service container to allow initialization of plugins
- /// The configuration instance, to get the plugin's directory path.
/// The logger used by this class.
public PluginManager(IServiceProvider provider,
- IOptions options,
ILogger logger)
{
_provider = provider;
- _options = options;
_logger = logger;
}
diff --git a/back/src/Kyoo.Host/HostModule.cs b/back/src/Kyoo.Host/HostModule.cs
index 4f83bb62..3b9b4c55 100644
--- a/back/src/Kyoo.Host/HostModule.cs
+++ b/back/src/Kyoo.Host/HostModule.cs
@@ -20,11 +20,7 @@ using System.Collections.Generic;
using Autofac;
using Autofac.Extras.AttributeMetadata;
using Kyoo.Abstractions.Controllers;
-using Kyoo.Core.Models.Options;
-using Kyoo.Host.Controllers;
using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
using Serilog;
namespace Kyoo.Host
@@ -42,20 +38,13 @@ namespace Kyoo.Host
///
private readonly IPluginManager _plugins;
- ///
- /// The configuration used to register options.
- ///
- private readonly IConfiguration _configuration;
-
///
/// Create a new .
///
/// The plugin manager that loaded all plugins.
- /// The configuration used to register options.
- public HostModule(IPluginManager plugins, IConfiguration configuration)
+ public HostModule(IPluginManager plugins)
{
_plugins = plugins;
- _configuration = configuration;
}
///
@@ -63,7 +52,6 @@ namespace Kyoo.Host
{
builder.RegisterModule();
builder.RegisterInstance(_plugins).As().ExternallyOwned();
- builder.RegisterComposite().InstancePerLifetimeScope();
}
///
diff --git a/back/src/Kyoo.Host/PluginsStartup.cs b/back/src/Kyoo.Host/PluginsStartup.cs
index 45c857ab..076e4ff6 100644
--- a/back/src/Kyoo.Host/PluginsStartup.cs
+++ b/back/src/Kyoo.Host/PluginsStartup.cs
@@ -24,7 +24,6 @@ using Autofac;
using Kyoo.Abstractions.Controllers;
using Kyoo.Authentication;
using Kyoo.Core;
-using Kyoo.Core.Models.Options;
using Kyoo.Host.Controllers;
using Kyoo.Postgresql;
using Kyoo.Swagger;
@@ -35,7 +34,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
namespace Kyoo.Host
{
@@ -49,11 +47,6 @@ namespace Kyoo.Host
///
private readonly IPluginManager _plugins;
- ///
- /// The configuration used to register and so on for plugin's specified types.
- ///
- private readonly IConfiguration _configuration;
-
///
/// The plugin that adds controllers and tasks specific to this host.
///
@@ -63,14 +56,10 @@ namespace Kyoo.Host
/// Created from the DI container, those services are needed to load information and instantiate plugins.s
///
/// The plugin manager to use to load new plugins and configure the host.
- ///
- /// The configuration used to register and so on for plugin's specified types.
- ///
- public PluginsStartup(IPluginManager plugins, IConfiguration configuration)
+ public PluginsStartup(IPluginManager plugins)
{
_plugins = plugins;
- _configuration = configuration;
- _hostModule = new HostModule(_plugins, configuration);
+ _hostModule = new HostModule(_plugins);
_plugins.LoadPlugins(
typeof(CoreModule),
typeof(AuthenticationModule),
@@ -94,10 +83,9 @@ namespace Kyoo.Host
HostServiceProvider hostProvider = new(host.HostingEnvironment, host.Configuration, logger);
PluginManager plugins = new(
hostProvider,
- Options.Create(host.Configuration.GetSection(BasicOptions.Path).Get()),
logger.CreateLogger()
);
- return new PluginsStartup(plugins, host.Configuration);
+ return new PluginsStartup(plugins);
}
///
diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs
index 5a49edc1..19303e75 100644
--- a/back/src/Kyoo.Postgresql/DatabaseContext.cs
+++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs
@@ -65,11 +65,6 @@ namespace Kyoo.Postgresql
///
public DbSet Episodes { get; set; }
- ///
- /// All tracks of Kyoo. See .
- ///
- public DbSet Tracks { get; set; }
-
///
/// All genres of Kyoo. See .
///
@@ -268,10 +263,6 @@ namespace Kyoo.Postgresql
.HasMany(x => x.Episodes)
.WithOne(x => x.Season)
.OnDelete(DeleteBehavior.Cascade);
- modelBuilder.Entity()
- .HasMany(x => x.Tracks)
- .WithOne(x => x.Episode)
- .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity()
.HasOne(x => x.Studio)
@@ -307,7 +298,6 @@ namespace Kyoo.Postgresql
modelBuilder.Entity().Property(x => x.Slug).IsRequired();
modelBuilder.Entity().Property(x => x.Slug).IsRequired();
modelBuilder.Entity().Property(x => x.Slug).IsRequired();
- modelBuilder.Entity().Property(x => x.Slug).IsRequired();
modelBuilder.Entity().Property(x => x.Slug).IsRequired();
modelBuilder.Entity().Property(x => x.Slug).IsRequired();
@@ -344,12 +334,6 @@ namespace Kyoo.Postgresql
modelBuilder.Entity()
.HasIndex(x => x.Slug)
.IsUnique();
- modelBuilder.Entity()
- .HasIndex(x => new { x.EpisodeID, x.Type, x.Language, x.TrackIndex, x.IsForced })
- .IsUnique();
- modelBuilder.Entity()
- .HasIndex(x => x.Slug)
- .IsUnique();
modelBuilder.Entity()
.HasIndex(x => x.Slug)
.IsUnique();
diff --git a/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.Designer.cs
deleted file mode 100644
index 02a66b0d..00000000
--- a/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.Designer.cs
+++ /dev/null
@@ -1,1259 +0,0 @@
-//
-using System;
-using System.Collections.Generic;
-using Kyoo.Abstractions.Models;
-using Kyoo.Postgresql;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
-
-namespace Kyoo.Postgresql.Migrations
-{
- [DbContext(typeof(PostgresContext))]
- [Migration("20210801171613_Initial")]
- partial class Initial
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasPostgresEnum(null, "item_type", new[] { "show", "movie", "collection" })
- .HasPostgresEnum(null, "status", new[] { "unknown", "finished", "airing", "planned" })
- .HasPostgresEnum(null, "stream_type", new[] { "unknown", "video", "audio", "subtitle", "attachment" })
- .HasAnnotation("Relational:MaxIdentifierLength", 63)
- .HasAnnotation("ProductVersion", "5.0.8")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- modelBuilder.Entity("Kyoo.Models.Collection", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_collections");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_collections_slug");
-
- b.ToTable("collections");
- });
-
- modelBuilder.Entity("Kyoo.Models.Episode", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("AbsoluteNumber")
- .HasColumnType("integer")
- .HasColumnName("absolute_number");
-
- b.Property("EpisodeNumber")
- .HasColumnType("integer")
- .HasColumnName("episode_number");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Path")
- .HasColumnType("text")
- .HasColumnName("path");
-
- b.Property("ReleaseDate")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("release_date");
-
- b.Property("SeasonID")
- .HasColumnType("integer")
- .HasColumnName("season_id");
-
- b.Property("SeasonNumber")
- .HasColumnType("integer")
- .HasColumnName("season_number");
-
- b.Property("ShowID")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.Property("Slug")
- .ValueGeneratedOnAddOrUpdate()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.HasKey("ID")
- .HasName("pk_episodes");
-
- b.HasIndex("SeasonID")
- .HasDatabaseName("ix_episodes_season_id");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_episodes_slug");
-
- b.HasIndex("ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber")
- .IsUnique()
- .HasDatabaseName("ix_episodes_show_id_season_number_episode_number_absolute_numb");
-
- b.ToTable("episodes");
- });
-
- modelBuilder.Entity("Kyoo.Models.Genre", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_genres");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_genres_slug");
-
- b.ToTable("genres");
- });
-
- modelBuilder.Entity("Kyoo.Models.Library", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Paths")
- .HasColumnType("text[]")
- .HasColumnName("paths");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_libraries");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_libraries_slug");
-
- b.ToTable("libraries");
- });
-
- modelBuilder.Entity("Kyoo.Models.LibraryItem", b =>
- {
- b.Property("ID")
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("EndAir")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("end_air");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Slug")
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("StartAir")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("start_air");
-
- b.Property("Status")
- .HasColumnType("status")
- .HasColumnName("status");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.Property("Type")
- .HasColumnType("item_type")
- .HasColumnName("type");
-
- b.HasKey("ID")
- .HasName("pk_library_items");
-
- b.ToView("library_items");
- });
-
- modelBuilder.Entity("Kyoo.Models.People", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_people");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_people_slug");
-
- b.ToTable("people");
- });
-
- modelBuilder.Entity("Kyoo.Models.PeopleRole", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("PeopleID")
- .HasColumnType("integer")
- .HasColumnName("people_id");
-
- b.Property("Role")
- .HasColumnType("text")
- .HasColumnName("role");
-
- b.Property("ShowID")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.Property("Type")
- .HasColumnType("text")
- .HasColumnName("type");
-
- b.HasKey("ID")
- .HasName("pk_people_roles");
-
- b.HasIndex("PeopleID")
- .HasDatabaseName("ix_people_roles_people_id");
-
- b.HasIndex("ShowID")
- .HasDatabaseName("ix_people_roles_show_id");
-
- b.ToTable("people_roles");
- });
-
- modelBuilder.Entity("Kyoo.Models.Provider", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_providers");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_providers_slug");
-
- b.ToTable("providers");
- });
-
- modelBuilder.Entity("Kyoo.Models.Season", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("EndDate")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("end_date");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("SeasonNumber")
- .HasColumnType("integer")
- .HasColumnName("season_number");
-
- b.Property("ShowID")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.Property("Slug")
- .ValueGeneratedOnAddOrUpdate()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("StartDate")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("start_date");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.HasKey("ID")
- .HasName("pk_seasons");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_seasons_slug");
-
- b.HasIndex("ShowID", "SeasonNumber")
- .IsUnique()
- .HasDatabaseName("ix_seasons_show_id_season_number");
-
- b.ToTable("seasons");
- });
-
- modelBuilder.Entity("Kyoo.Models.Show", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Aliases")
- .HasColumnType("text[]")
- .HasColumnName("aliases");
-
- b.Property("EndAir")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("end_air");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("IsMovie")
- .HasColumnType("boolean")
- .HasColumnName("is_movie");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Path")
- .HasColumnType("text")
- .HasColumnName("path");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("StartAir")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("start_air");
-
- b.Property("Status")
- .HasColumnType("status")
- .HasColumnName("status");
-
- b.Property("StudioID")
- .HasColumnType("integer")
- .HasColumnName("studio_id");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.HasKey("ID")
- .HasName("pk_shows");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_shows_slug");
-
- b.HasIndex("StudioID")
- .HasDatabaseName("ix_shows_studio_id");
-
- b.ToTable("shows");
- });
-
- modelBuilder.Entity("Kyoo.Models.Studio", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_studios");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_studios_slug");
-
- b.ToTable("studios");
- });
-
- modelBuilder.Entity("Kyoo.Models.Track", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Codec")
- .HasColumnType("text")
- .HasColumnName("codec");
-
- b.Property("EpisodeID")
- .HasColumnType("integer")
- .HasColumnName("episode_id");
-
- b.Property("IsDefault")
- .HasColumnType("boolean")
- .HasColumnName("is_default");
-
- b.Property("IsExternal")
- .HasColumnType("boolean")
- .HasColumnName("is_external");
-
- b.Property("IsForced")
- .HasColumnType("boolean")
- .HasColumnName("is_forced");
-
- b.Property("Language")
- .HasColumnType("text")
- .HasColumnName("language");
-
- b.Property("Path")
- .HasColumnType("text")
- .HasColumnName("path");
-
- b.Property("Slug")
- .ValueGeneratedOnAddOrUpdate()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.Property("TrackIndex")
- .HasColumnType("integer")
- .HasColumnName("track_index");
-
- b.Property("Type")
- .HasColumnType("stream_type")
- .HasColumnName("type");
-
- b.HasKey("ID")
- .HasName("pk_tracks");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_tracks_slug");
-
- b.HasIndex("EpisodeID", "Type", "Language", "TrackIndex", "IsForced")
- .IsUnique()
- .HasDatabaseName("ix_tracks_episode_id_type_language_track_index_is_forced");
-
- b.ToTable("tracks");
- });
-
- modelBuilder.Entity("Kyoo.Models.User", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Email")
- .HasColumnType("text")
- .HasColumnName("email");
-
- b.Property>("ExtraData")
- .HasColumnType("jsonb")
- .HasColumnName("extra_data");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Password")
- .HasColumnType("text")
- .HasColumnName("password");
-
- b.Property("Permissions")
- .HasColumnType("text[]")
- .HasColumnName("permissions");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("Username")
- .HasColumnType("text")
- .HasColumnName("username");
-
- b.HasKey("ID")
- .HasName("pk_users");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_users_slug");
-
- b.ToTable("users");
- });
-
- modelBuilder.Entity("Kyoo.Models.WatchedEpisode", b =>
- {
- b.Property("UserID")
- .HasColumnType("integer")
- .HasColumnName("user_id");
-
- b.Property("EpisodeID")
- .HasColumnType("integer")
- .HasColumnName("episode_id");
-
- b.Property("WatchedPercentage")
- .HasColumnType("integer")
- .HasColumnName("watched_percentage");
-
- b.HasKey("UserID", "EpisodeID")
- .HasName("pk_watched_episodes");
-
- b.HasIndex("EpisodeID")
- .HasDatabaseName("ix_watched_episodes_episode_id");
-
- b.ToTable("watched_episodes");
- });
-
- modelBuilder.Entity("ShowUser", b =>
- {
- b.Property("UsersID")
- .HasColumnType("integer")
- .HasColumnName("users_id");
-
- b.Property("WatchedID")
- .HasColumnType("integer")
- .HasColumnName("watched_id");
-
- b.HasKey("UsersID", "WatchedID")
- .HasName("pk_link_user_show");
-
- b.HasIndex("WatchedID")
- .HasDatabaseName("ix_link_user_show_watched_id");
-
- b.ToTable("link_user_show");
- });
-
- modelBuilder.Entity("collection_metadata_id", b =>
- {
- b.Property("ResourceID")
- .HasColumnType("integer")
- .HasColumnName("resource_id");
-
- b.Property("ProviderID")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("ResourceID", "ProviderID")
- .HasName("pk_collection_metadata_id");
-
- b.HasIndex("ProviderID")
- .HasDatabaseName("ix_collection_metadata_id_provider_id");
-
- b.ToTable("collection_metadata_id");
- });
-
- modelBuilder.Entity("episode_metadata_id", b =>
- {
- b.Property("ResourceID")
- .HasColumnType("integer")
- .HasColumnName("resource_id");
-
- b.Property("ProviderID")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("ResourceID", "ProviderID")
- .HasName("pk_episode_metadata_id");
-
- b.HasIndex("ProviderID")
- .HasDatabaseName("ix_episode_metadata_id_provider_id");
-
- b.ToTable("episode_metadata_id");
- });
-
- modelBuilder.Entity("link_collection_show", b =>
- {
- b.Property("collection_id")
- .HasColumnType("integer")
- .HasColumnName("collection_id");
-
- b.Property("show_id")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.HasKey("collection_id", "show_id")
- .HasName("pk_link_collection_show");
-
- b.HasIndex("show_id")
- .HasDatabaseName("ix_link_collection_show_show_id");
-
- b.ToTable("link_collection_show");
- });
-
- modelBuilder.Entity("link_library_collection", b =>
- {
- b.Property("collection_id")
- .HasColumnType("integer")
- .HasColumnName("collection_id");
-
- b.Property("library_id")
- .HasColumnType("integer")
- .HasColumnName("library_id");
-
- b.HasKey("collection_id", "library_id")
- .HasName("pk_link_library_collection");
-
- b.HasIndex("library_id")
- .HasDatabaseName("ix_link_library_collection_library_id");
-
- b.ToTable("link_library_collection");
- });
-
- modelBuilder.Entity("link_library_provider", b =>
- {
- b.Property("library_id")
- .HasColumnType("integer")
- .HasColumnName("library_id");
-
- b.Property("provider_id")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.HasKey("library_id", "provider_id")
- .HasName("pk_link_library_provider");
-
- b.HasIndex("provider_id")
- .HasDatabaseName("ix_link_library_provider_provider_id");
-
- b.ToTable("link_library_provider");
- });
-
- modelBuilder.Entity("link_library_show", b =>
- {
- b.Property("library_id")
- .HasColumnType("integer")
- .HasColumnName("library_id");
-
- b.Property("show_id")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.HasKey("library_id", "show_id")
- .HasName("pk_link_library_show");
-
- b.HasIndex("show_id")
- .HasDatabaseName("ix_link_library_show_show_id");
-
- b.ToTable("link_library_show");
- });
-
- modelBuilder.Entity("link_show_genre", b =>
- {
- b.Property("genre_id")
- .HasColumnType("integer")
- .HasColumnName("genre_id");
-
- b.Property("show_id")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.HasKey("genre_id", "show_id")
- .HasName("pk_link_show_genre");
-
- b.HasIndex("show_id")
- .HasDatabaseName("ix_link_show_genre_show_id");
-
- b.ToTable("link_show_genre");
- });
-
- modelBuilder.Entity("people_metadata_id", b =>
- {
- b.Property("ResourceID")
- .HasColumnType("integer")
- .HasColumnName("resource_id");
-
- b.Property("ProviderID")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("ResourceID", "ProviderID")
- .HasName("pk_people_metadata_id");
-
- b.HasIndex("ProviderID")
- .HasDatabaseName("ix_people_metadata_id_provider_id");
-
- b.ToTable("people_metadata_id");
- });
-
- modelBuilder.Entity("season_metadata_id", b =>
- {
- b.Property("ResourceID")
- .HasColumnType("integer")
- .HasColumnName("resource_id");
-
- b.Property("ProviderID")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("ResourceID", "ProviderID")
- .HasName("pk_season_metadata_id");
-
- b.HasIndex("ProviderID")
- .HasDatabaseName("ix_season_metadata_id_provider_id");
-
- b.ToTable("season_metadata_id");
- });
-
- modelBuilder.Entity("show_metadata_id", b =>
- {
- b.Property("ResourceID")
- .HasColumnType("integer")
- .HasColumnName("resource_id");
-
- b.Property("ProviderID")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("ResourceID", "ProviderID")
- .HasName("pk_show_metadata_id");
-
- b.HasIndex("ProviderID")
- .HasDatabaseName("ix_show_metadata_id_provider_id");
-
- b.ToTable("show_metadata_id");
- });
-
- modelBuilder.Entity("studio_metadata_id", b =>
- {
- b.Property("ResourceID")
- .HasColumnType("integer")
- .HasColumnName("resource_id");
-
- b.Property("ProviderID")
- .HasColumnType("integer")
- .HasColumnName("provider_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("ResourceID", "ProviderID")
- .HasName("pk_studio_metadata_id");
-
- b.HasIndex("ProviderID")
- .HasDatabaseName("ix_studio_metadata_id_provider_id");
-
- b.ToTable("studio_metadata_id");
- });
-
- modelBuilder.Entity("Kyoo.Models.Episode", b =>
- {
- b.HasOne("Kyoo.Models.Season", "Season")
- .WithMany("Episodes")
- .HasForeignKey("SeasonID")
- .HasConstraintName("fk_episodes_seasons_season_id")
- .OnDelete(DeleteBehavior.Cascade);
-
- b.HasOne("Kyoo.Models.Show", "Show")
- .WithMany("Episodes")
- .HasForeignKey("ShowID")
- .HasConstraintName("fk_episodes_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Season");
-
- b.Navigation("Show");
- });
-
- modelBuilder.Entity("Kyoo.Models.PeopleRole", b =>
- {
- b.HasOne("Kyoo.Models.People", "People")
- .WithMany("Roles")
- .HasForeignKey("PeopleID")
- .HasConstraintName("fk_people_roles_people_people_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", "Show")
- .WithMany("People")
- .HasForeignKey("ShowID")
- .HasConstraintName("fk_people_roles_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("People");
-
- b.Navigation("Show");
- });
-
- modelBuilder.Entity("Kyoo.Models.Season", b =>
- {
- b.HasOne("Kyoo.Models.Show", "Show")
- .WithMany("Seasons")
- .HasForeignKey("ShowID")
- .HasConstraintName("fk_seasons_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Show");
- });
-
- modelBuilder.Entity("Kyoo.Models.Show", b =>
- {
- b.HasOne("Kyoo.Models.Studio", "Studio")
- .WithMany("Shows")
- .HasForeignKey("StudioID")
- .HasConstraintName("fk_shows_studios_studio_id")
- .OnDelete(DeleteBehavior.SetNull);
-
- b.Navigation("Studio");
- });
-
- modelBuilder.Entity("Kyoo.Models.Track", b =>
- {
- b.HasOne("Kyoo.Models.Episode", "Episode")
- .WithMany("Tracks")
- .HasForeignKey("EpisodeID")
- .HasConstraintName("fk_tracks_episodes_episode_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Episode");
- });
-
- modelBuilder.Entity("Kyoo.Models.WatchedEpisode", b =>
- {
- b.HasOne("Kyoo.Models.Episode", "Episode")
- .WithMany()
- .HasForeignKey("EpisodeID")
- .HasConstraintName("fk_watched_episodes_episodes_episode_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.User", null)
- .WithMany("CurrentlyWatching")
- .HasForeignKey("UserID")
- .HasConstraintName("fk_watched_episodes_users_user_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Episode");
- });
-
- modelBuilder.Entity("ShowUser", b =>
- {
- b.HasOne("Kyoo.Models.User", null)
- .WithMany()
- .HasForeignKey("UsersID")
- .HasConstraintName("fk_link_user_show_users_users_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", null)
- .WithMany()
- .HasForeignKey("WatchedID")
- .HasConstraintName("fk_link_user_show_shows_watched_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("collection_metadata_id", b =>
- {
- b.HasOne("Kyoo.Models.Provider", "Provider")
- .WithMany()
- .HasForeignKey("ProviderID")
- .HasConstraintName("fk_collection_metadata_id_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Collection", null)
- .WithMany("ExternalIDs")
- .HasForeignKey("ResourceID")
- .HasConstraintName("fk_collection_metadata_id_collections_collection_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Provider");
- });
-
- modelBuilder.Entity("episode_metadata_id", b =>
- {
- b.HasOne("Kyoo.Models.Provider", "Provider")
- .WithMany()
- .HasForeignKey("ProviderID")
- .HasConstraintName("fk_episode_metadata_id_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Episode", null)
- .WithMany("ExternalIDs")
- .HasForeignKey("ResourceID")
- .HasConstraintName("fk_episode_metadata_id_episodes_episode_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Provider");
- });
-
- modelBuilder.Entity("link_collection_show", b =>
- {
- b.HasOne("Kyoo.Models.Collection", null)
- .WithMany()
- .HasForeignKey("collection_id")
- .HasConstraintName("fk_link_collection_show_collections_collection_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", null)
- .WithMany()
- .HasForeignKey("show_id")
- .HasConstraintName("fk_link_collection_show_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("link_library_collection", b =>
- {
- b.HasOne("Kyoo.Models.Collection", null)
- .WithMany()
- .HasForeignKey("collection_id")
- .HasConstraintName("fk_link_library_collection_collections_collection_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Library", null)
- .WithMany()
- .HasForeignKey("library_id")
- .HasConstraintName("fk_link_library_collection_libraries_library_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("link_library_provider", b =>
- {
- b.HasOne("Kyoo.Models.Library", null)
- .WithMany()
- .HasForeignKey("library_id")
- .HasConstraintName("fk_link_library_provider_libraries_library_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Provider", null)
- .WithMany()
- .HasForeignKey("provider_id")
- .HasConstraintName("fk_link_library_provider_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("link_library_show", b =>
- {
- b.HasOne("Kyoo.Models.Library", null)
- .WithMany()
- .HasForeignKey("library_id")
- .HasConstraintName("fk_link_library_show_libraries_library_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", null)
- .WithMany()
- .HasForeignKey("show_id")
- .HasConstraintName("fk_link_library_show_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("link_show_genre", b =>
- {
- b.HasOne("Kyoo.Models.Genre", null)
- .WithMany()
- .HasForeignKey("genre_id")
- .HasConstraintName("fk_link_show_genre_genres_genre_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", null)
- .WithMany()
- .HasForeignKey("show_id")
- .HasConstraintName("fk_link_show_genre_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("people_metadata_id", b =>
- {
- b.HasOne("Kyoo.Models.Provider", "Provider")
- .WithMany()
- .HasForeignKey("ProviderID")
- .HasConstraintName("fk_people_metadata_id_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.People", null)
- .WithMany("ExternalIDs")
- .HasForeignKey("ResourceID")
- .HasConstraintName("fk_people_metadata_id_people_people_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Provider");
- });
-
- modelBuilder.Entity("season_metadata_id", b =>
- {
- b.HasOne("Kyoo.Models.Provider", "Provider")
- .WithMany()
- .HasForeignKey("ProviderID")
- .HasConstraintName("fk_season_metadata_id_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Season", null)
- .WithMany("ExternalIDs")
- .HasForeignKey("ResourceID")
- .HasConstraintName("fk_season_metadata_id_seasons_season_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Provider");
- });
-
- modelBuilder.Entity("show_metadata_id", b =>
- {
- b.HasOne("Kyoo.Models.Provider", "Provider")
- .WithMany()
- .HasForeignKey("ProviderID")
- .HasConstraintName("fk_show_metadata_id_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", null)
- .WithMany("ExternalIDs")
- .HasForeignKey("ResourceID")
- .HasConstraintName("fk_show_metadata_id_shows_show_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Provider");
- });
-
- modelBuilder.Entity("studio_metadata_id", b =>
- {
- b.HasOne("Kyoo.Models.Provider", "Provider")
- .WithMany()
- .HasForeignKey("ProviderID")
- .HasConstraintName("fk_studio_metadata_id_providers_provider_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Studio", null)
- .WithMany("ExternalIDs")
- .HasForeignKey("ResourceID")
- .HasConstraintName("fk_studio_metadata_id_studios_studio_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Provider");
- });
-
- modelBuilder.Entity("Kyoo.Models.Collection", b =>
- {
- b.Navigation("ExternalIDs");
- });
-
- modelBuilder.Entity("Kyoo.Models.Episode", b =>
- {
- b.Navigation("ExternalIDs");
-
- b.Navigation("Tracks");
- });
-
- modelBuilder.Entity("Kyoo.Models.People", b =>
- {
- b.Navigation("ExternalIDs");
-
- b.Navigation("Roles");
- });
-
- modelBuilder.Entity("Kyoo.Models.Season", b =>
- {
- b.Navigation("Episodes");
-
- b.Navigation("ExternalIDs");
- });
-
- modelBuilder.Entity("Kyoo.Models.Show", b =>
- {
- b.Navigation("Episodes");
-
- b.Navigation("ExternalIDs");
-
- b.Navigation("People");
-
- b.Navigation("Seasons");
- });
-
- modelBuilder.Entity("Kyoo.Models.Studio", b =>
- {
- b.Navigation("ExternalIDs");
-
- b.Navigation("Shows");
- });
-
- modelBuilder.Entity("Kyoo.Models.User", b =>
- {
- b.Navigation("CurrentlyWatching");
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs b/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs
index 0724cfd8..5321a0a1 100644
--- a/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs
+++ b/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs
@@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Models;
+using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
@@ -27,6 +28,8 @@ namespace Kyoo.Postgresql.Migrations
///
/// The initial migration that build most of the database.
///
+ [DbContext(typeof(PostgresContext))]
+ [Migration("20210801171613_Initial")]
public partial class Initial : Migration
{
///
@@ -577,7 +580,7 @@ namespace Kyoo.Postgresql.Migrations
is_forced = table.Column(type: "boolean", nullable: false),
is_external = table.Column(type: "boolean", nullable: false),
path = table.Column(type: "text", nullable: true),
- type = table.Column(type: "stream_type", nullable: false),
+ type = table.Column(type: "stream_type", nullable: false),
episode_id = table.Column(type: "integer", nullable: false),
track_index = table.Column(type: "integer", nullable: false)
},
diff --git a/back/src/Kyoo.Postgresql/Migrations/20210801171641_Triggers.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20210801171641_Triggers.Designer.cs
deleted file mode 100644
index de520a04..00000000
--- a/back/src/Kyoo.Postgresql/Migrations/20210801171641_Triggers.Designer.cs
+++ /dev/null
@@ -1,1259 +0,0 @@
-//
-using System;
-using System.Collections.Generic;
-using Kyoo.Abstractions.Models;
-using Kyoo.Postgresql;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
-
-namespace Kyoo.Postgresql.Migrations
-{
- [DbContext(typeof(PostgresContext))]
- [Migration("20210801171641_Triggers")]
- partial class Triggers
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasPostgresEnum(null, "item_type", new[] { "show", "movie", "collection" })
- .HasPostgresEnum(null, "status", new[] { "unknown", "finished", "airing", "planned" })
- .HasPostgresEnum(null, "stream_type", new[] { "unknown", "video", "audio", "subtitle", "attachment" })
- .HasAnnotation("Relational:MaxIdentifierLength", 63)
- .HasAnnotation("ProductVersion", "5.0.8")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- modelBuilder.Entity("Kyoo.Models.Collection", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_collections");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_collections_slug");
-
- b.ToTable("collections");
- });
-
- modelBuilder.Entity("Kyoo.Models.Episode", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("AbsoluteNumber")
- .HasColumnType("integer")
- .HasColumnName("absolute_number");
-
- b.Property("EpisodeNumber")
- .HasColumnType("integer")
- .HasColumnName("episode_number");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Path")
- .HasColumnType("text")
- .HasColumnName("path");
-
- b.Property("ReleaseDate")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("release_date");
-
- b.Property("SeasonID")
- .HasColumnType("integer")
- .HasColumnName("season_id");
-
- b.Property("SeasonNumber")
- .HasColumnType("integer")
- .HasColumnName("season_number");
-
- b.Property("ShowID")
- .HasColumnType("integer")
- .HasColumnName("show_id");
-
- b.Property("Slug")
- .ValueGeneratedOnAddOrUpdate()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.HasKey("ID")
- .HasName("pk_episodes");
-
- b.HasIndex("SeasonID")
- .HasDatabaseName("ix_episodes_season_id");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_episodes_slug");
-
- b.HasIndex("ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber")
- .IsUnique()
- .HasDatabaseName("ix_episodes_show_id_season_number_episode_number_absolute_numb");
-
- b.ToTable("episodes");
- });
-
- modelBuilder.Entity("Kyoo.Models.Genre", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_genres");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_genres_slug");
-
- b.ToTable("genres");
- });
-
- modelBuilder.Entity("Kyoo.Models.Library", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd()
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("Name")
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("Paths")
- .HasColumnType("text[]")
- .HasColumnName("paths");
-
- b.Property("Slug")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.HasKey("ID")
- .HasName("pk_libraries");
-
- b.HasIndex("Slug")
- .IsUnique()
- .HasDatabaseName("ix_libraries_slug");
-
- b.ToTable("libraries");
- });
-
- modelBuilder.Entity("Kyoo.Models.LibraryItem", b =>
- {
- b.Property("ID")
- .HasColumnType("integer")
- .HasColumnName("id")
- .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
-
- b.Property("EndAir")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("end_air");
-
- b.Property>("Images")
- .HasColumnType("jsonb")
- .HasColumnName("images");
-
- b.Property("Overview")
- .HasColumnType("text")
- .HasColumnName("overview");
-
- b.Property("Slug")
- .HasColumnType("text")
- .HasColumnName("slug");
-
- b.Property("StartAir")
- .HasColumnType("timestamp without time zone")
- .HasColumnName("start_air");
-
- b.Property("Status")
- .HasColumnType("status")
- .HasColumnName("status");
-
- b.Property("Title")
- .HasColumnType("text")
- .HasColumnName("title");
-
- b.Property("Type")
- .HasColumnType("item_type")
- .HasColumnName("type");
-
- b.HasKey("ID")
- .HasName("pk_library_items");
-
- b.ToView("library_items");
- });
-
- modelBuilder.Entity("Kyoo.Models.People", b =>
- {
- b.Property