mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Cleaning up
This commit is contained in:
parent
8c8db5e9b6
commit
253b8561bc
@ -3,8 +3,8 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public interface ICrawler
|
public interface ICrawler
|
||||||
{
|
{
|
||||||
Task StartAsync(CancellationToken cancellationToken);
|
Task StartAsync(CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,63 +4,63 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public interface ILibraryManager
|
public interface ILibraryManager
|
||||||
{
|
{
|
||||||
//Read values
|
//Read values
|
||||||
string GetShowExternalIDs(long showID);
|
string GetShowExternalIDs(long showID);
|
||||||
Studio GetStudio(long showID);
|
Studio GetStudio(long showID);
|
||||||
IEnumerable<PeopleLink> GetPeople(long showID);
|
IEnumerable<PeopleLink> GetPeople(long showID);
|
||||||
IEnumerable<Genre> GetGenreForShow(long showID);
|
IEnumerable<Genre> GetGenreForShow(long showID);
|
||||||
IEnumerable<Season> GetSeasons(long showID);
|
IEnumerable<Season> GetSeasons(long showID);
|
||||||
int GetSeasonCount(string showSlug, long seasonNumber);
|
int GetSeasonCount(string showSlug, long seasonNumber);
|
||||||
IEnumerable<Show> GetShowsInCollection(long collectionID);
|
IEnumerable<Show> GetShowsInCollection(long collectionID);
|
||||||
IEnumerable<Show> GetShowsInLibrary(long libraryID);
|
IEnumerable<Show> GetShowsInLibrary(long libraryID);
|
||||||
IEnumerable<Show> GetShowsByPeople(string peopleSlug);
|
IEnumerable<Show> GetShowsByPeople(string peopleSlug);
|
||||||
IEnumerable<string> GetLibrariesPath();
|
IEnumerable<string> GetLibrariesPath();
|
||||||
|
|
||||||
//Internal read
|
//Internal read
|
||||||
(Track video, IEnumerable<Track> audios, IEnumerable<Track> subtitles) GetStreams(long episodeID, string showSlug);
|
(Track video, IEnumerable<Track> audios, IEnumerable<Track> subtitles) GetStreams(long episodeID, string showSlug);
|
||||||
Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, bool forced);
|
Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, bool forced);
|
||||||
|
|
||||||
//Public read
|
//Public read
|
||||||
IEnumerable<Show> GetShows();
|
IEnumerable<Show> GetShows();
|
||||||
IEnumerable<Show> GetShows(string searchQuery);
|
IEnumerable<Show> GetShows(string searchQuery);
|
||||||
Library GetLibrary(string librarySlug);
|
Library GetLibrary(string librarySlug);
|
||||||
IEnumerable<Library> GetLibraries();
|
IEnumerable<Library> GetLibraries();
|
||||||
Show GetShowBySlug(string slug);
|
Show GetShowBySlug(string slug);
|
||||||
Show GetShow(string path);
|
Show GetShow(string path);
|
||||||
Season GetSeason(string showSlug, long seasonNumber);
|
Season GetSeason(string showSlug, long seasonNumber);
|
||||||
IEnumerable<Episode> GetEpisodes(string showSlug);
|
IEnumerable<Episode> GetEpisodes(string showSlug);
|
||||||
IEnumerable<Episode> GetEpisodes(string showSlug, long seasonNumber);
|
IEnumerable<Episode> GetEpisodes(string showSlug, long seasonNumber);
|
||||||
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber);
|
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber);
|
||||||
WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true);
|
WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true);
|
||||||
People GetPeopleBySlug(string slug);
|
People GetPeopleBySlug(string slug);
|
||||||
Genre GetGenreBySlug(string slug);
|
Genre GetGenreBySlug(string slug);
|
||||||
Studio GetStudioBySlug(string slug);
|
Studio GetStudioBySlug(string slug);
|
||||||
Collection GetCollection(string slug);
|
Collection GetCollection(string slug);
|
||||||
IEnumerable<Episode> GetAllEpisodes();
|
IEnumerable<Episode> GetAllEpisodes();
|
||||||
IEnumerable<Episode> SearchEpisodes(string searchQuery);
|
IEnumerable<Episode> SearchEpisodes(string searchQuery);
|
||||||
IEnumerable<People> SearchPeople(string searchQuery);
|
IEnumerable<People> SearchPeople(string searchQuery);
|
||||||
IEnumerable<Genre> SearchGenres(string searchQuery);
|
IEnumerable<Genre> SearchGenres(string searchQuery);
|
||||||
IEnumerable<Studio> SearchStudios(string searchQuery);
|
IEnumerable<Studio> SearchStudios(string searchQuery);
|
||||||
|
|
||||||
//Check if value exists
|
//Check if value exists
|
||||||
bool IsCollectionRegistered(string collectionSlug, out long collectionID);
|
bool IsCollectionRegistered(string collectionSlug, out long collectionID);
|
||||||
bool IsShowRegistered(string showPath, out long showID);
|
bool IsShowRegistered(string showPath, out long showID);
|
||||||
bool IsSeasonRegistered(long showID, long seasonNumber, out long seasonID);
|
bool IsSeasonRegistered(long showID, long seasonNumber, out long seasonID);
|
||||||
bool IsEpisodeRegistered(string episodePath, out long episodeID);
|
bool IsEpisodeRegistered(string episodePath, out long episodeID);
|
||||||
|
|
||||||
//Register values
|
//Register values
|
||||||
long RegisterCollection(Collection collection);
|
long RegisterCollection(Collection collection);
|
||||||
long RegisterShow(Show show);
|
long RegisterShow(Show show);
|
||||||
long RegisterSeason(Season season);
|
long RegisterSeason(Season season);
|
||||||
long RegisterEpisode(Episode episode);
|
long RegisterEpisode(Episode episode);
|
||||||
long RegisterTrack(Track track);
|
long RegisterTrack(Track track);
|
||||||
void RegisterShowLinks(Library library, Collection collection, Show show);
|
void RegisterShowLinks(Library library, Collection collection, Show show);
|
||||||
|
|
||||||
void RemoveShow(long showID);
|
void RemoveShow(long showID);
|
||||||
void RemoveSeason(long seasonID);
|
void RemoveSeason(long seasonID);
|
||||||
void RemoveEpisode(long episodeID);
|
void RemoveEpisode(long episodeID);
|
||||||
void ClearSubtitles(long episodeID);
|
void ClearSubtitles(long episodeID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,22 +4,22 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public interface IMetadataProvider
|
public interface IMetadataProvider
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
//For the collection
|
//For the collection
|
||||||
Task<Collection> GetCollectionFromName(string name);
|
Task<Collection> GetCollectionFromName(string name);
|
||||||
|
|
||||||
//For the show
|
//For the show
|
||||||
Task<Show> GetShowByID(Show show);
|
Task<Show> GetShowByID(Show show);
|
||||||
Task<Show> GetShowFromName(string showName, bool isMovie);
|
Task<Show> GetShowFromName(string showName, bool isMovie);
|
||||||
Task<IEnumerable<PeopleLink>> GetPeople(Show show);
|
Task<IEnumerable<PeopleLink>> GetPeople(Show show);
|
||||||
|
|
||||||
//For the seasons
|
//For the seasons
|
||||||
Task<Season> GetSeason(Show show, long seasonNumber);
|
Task<Season> GetSeason(Show show, long seasonNumber);
|
||||||
|
|
||||||
//For the episodes
|
//For the episodes
|
||||||
Task<Episode> GetEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber);
|
Task<Episode> GetEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public interface IThumbnailsManager
|
public interface IThumbnailsManager
|
||||||
{
|
{
|
||||||
Task<Show> Validate(Show show);
|
Task<Show> Validate(Show show);
|
||||||
Task<IEnumerable<PeopleLink>> Validate(List<PeopleLink> actors);
|
Task<IEnumerable<PeopleLink>> Validate(List<PeopleLink> actors);
|
||||||
Task<Episode> Validate(Episode episode);
|
Task<Episode> Validate(Episode episode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,18 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public interface ITranscoder
|
public interface ITranscoder
|
||||||
{
|
{
|
||||||
// Should transcode to a mp4 container (same video/audio format if possible, no subtitles).
|
// Should transcode to a mp4 container (same video/audio format if possible, no subtitles).
|
||||||
Task<string> Transmux(WatchItem episode);
|
Task<string> Transmux(WatchItem episode);
|
||||||
|
|
||||||
// Should transcode to a mp4 container with a h264 video format and a AAC audio format, no subtitles.
|
// Should transcode to a mp4 container with a h264 video format and a AAC audio format, no subtitles.
|
||||||
Task<string> Transcode(WatchItem episode);
|
Task<string> Transcode(WatchItem episode);
|
||||||
|
|
||||||
// Get video and audio tracks infos (codec, name, language...)
|
// Get video and audio tracks infos (codec, name, language...)
|
||||||
Task<Track[]> GetTrackInfo(string path);
|
Task<Track[]> GetTrackInfo(string path);
|
||||||
|
|
||||||
// Extract all subtitles of a video and save them in the subtitles sub-folder.
|
// Extract all subtitles of a video and save them in the subtitles sub-folder.
|
||||||
Task<Track[]> ExtractSubtitles(string path);
|
Task<Track[]> ExtractSubtitles(string path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Title>Kyoo.Common</Title>
|
<Title>Kyoo.Common</Title>
|
||||||
<Authors>Anonymus Raccoon</Authors>
|
<Authors>Anonymus Raccoon</Authors>
|
||||||
<Description>Base package to create plugins for Kyoo.</Description>
|
<Description>Base package to create plugins for Kyoo.</Description>
|
||||||
<PackageProjectUrl>https://github.com/AnonymusRaccoon/Kyoo</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/AnonymusRaccoon/Kyoo</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
|
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
|
||||||
<Company>SDG</Company>
|
<Company>SDG</Company>
|
||||||
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<PackageVersion>1.0.11</PackageVersion>
|
<PackageVersion>1.0.11</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -4,55 +4,55 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Collection : IMergable<Collection>
|
public class Collection : IMergable<Collection>
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Poster { get; set; }
|
public string Poster { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||||
public IEnumerable<Show> Shows;
|
public IEnumerable<Show> Shows;
|
||||||
|
|
||||||
public Collection() { }
|
public Collection() { }
|
||||||
|
|
||||||
public Collection(string slug, string name, string overview, string imgPrimary)
|
public Collection(string slug, string name, string overview, string imgPrimary)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
ImgPrimary = imgPrimary;
|
ImgPrimary = imgPrimary;
|
||||||
}
|
|
||||||
|
|
||||||
public Show AsShow()
|
|
||||||
{
|
|
||||||
return new Show(Slug, Name, null, null, Overview, null, null, null, null, null, null)
|
|
||||||
{
|
|
||||||
IsCollection = true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection Merge(Collection collection)
|
|
||||||
{
|
|
||||||
if (collection == null)
|
|
||||||
return this;
|
|
||||||
if (ID == -1)
|
|
||||||
ID = collection.ID;
|
|
||||||
if (Slug == null)
|
|
||||||
Slug = collection.Slug;
|
|
||||||
if (Name == null)
|
|
||||||
Name = collection.Name;
|
|
||||||
if (Poster == null)
|
|
||||||
Poster = collection.Poster;
|
|
||||||
if (Overview == null)
|
|
||||||
Overview = collection.Overview;
|
|
||||||
if (ImgPrimary == null)
|
|
||||||
ImgPrimary = collection.ImgPrimary;
|
|
||||||
if (Shows == null)
|
|
||||||
Shows = collection.Shows;
|
|
||||||
else
|
|
||||||
Shows = Shows.Concat(collection.Shows);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public Show AsShow()
|
||||||
|
{
|
||||||
|
return new Show(Slug, Name, null, null, Overview, null, null, null, null, null, null)
|
||||||
|
{
|
||||||
|
IsCollection = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection Merge(Collection collection)
|
||||||
|
{
|
||||||
|
if (collection == null)
|
||||||
|
return this;
|
||||||
|
if (ID == -1)
|
||||||
|
ID = collection.ID;
|
||||||
|
if (Slug == null)
|
||||||
|
Slug = collection.Slug;
|
||||||
|
if (Name == null)
|
||||||
|
Name = collection.Name;
|
||||||
|
if (Poster == null)
|
||||||
|
Poster = collection.Poster;
|
||||||
|
if (Overview == null)
|
||||||
|
Overview = collection.Overview;
|
||||||
|
if (ImgPrimary == null)
|
||||||
|
ImgPrimary = collection.ImgPrimary;
|
||||||
|
if (Shows == null)
|
||||||
|
Shows = collection.Shows;
|
||||||
|
else
|
||||||
|
Shows = Shows.Concat(collection.Shows);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,112 +4,107 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Episode : IMergable<Episode>
|
public class Episode : IMergable<Episode>
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
[JsonIgnore] public long ShowID { get; set; }
|
[JsonIgnore] public long ShowID { get; set; }
|
||||||
[JsonIgnore] public virtual Show Show { get; set; }
|
[JsonIgnore] public virtual Show Show { get; set; }
|
||||||
[JsonIgnore] public long SeasonID { get; set; }
|
[JsonIgnore] public long SeasonID { get; set; }
|
||||||
[JsonIgnore] public virtual Season Season { get; set; }
|
[JsonIgnore] public virtual Season Season { get; set; }
|
||||||
|
|
||||||
public long SeasonNumber { get; set; }
|
public long SeasonNumber { get; set; }
|
||||||
public long EpisodeNumber { get; set; }
|
public long EpisodeNumber { get; set; }
|
||||||
public long AbsoluteNumber { get; set; }
|
public long AbsoluteNumber { get; set; }
|
||||||
[JsonIgnore] public string Path { get; set; }
|
[JsonIgnore] public string Path { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
public DateTime? ReleaseDate { get; set; }
|
public DateTime? ReleaseDate { get; set; }
|
||||||
|
|
||||||
public long Runtime { get; set; } //This runtime variable should be in minutes
|
public long Runtime { get; set; } //This runtime variable should be in minutes
|
||||||
|
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||||
public string ExternalIDs { get; set; }
|
public string ExternalIDs { get; set; }
|
||||||
|
|
||||||
[JsonIgnore] public virtual IEnumerable<Track> Tracks { get; set; }
|
[JsonIgnore] public virtual IEnumerable<Track> Tracks { get; set; }
|
||||||
|
|
||||||
public string ShowTitle; //Used in the API response only
|
public string ShowTitle; //Used in the API response only
|
||||||
public string Link; //Used in the API response only
|
public string Link; //Used in the API response only
|
||||||
public string Thumb; //Used in the API response only
|
public string Thumb; //Used in the API response only
|
||||||
|
|
||||||
|
|
||||||
public Episode()
|
public Episode()
|
||||||
{
|
{
|
||||||
SeasonNumber = -1;
|
SeasonNumber = -1;
|
||||||
EpisodeNumber = -1;
|
EpisodeNumber = -1;
|
||||||
AbsoluteNumber = -1;
|
AbsoluteNumber = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Episode(long seasonNumber, long episodeNumber, long absoluteNumber, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
|
public Episode(long seasonNumber, long episodeNumber, long absoluteNumber, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
|
||||||
{
|
{
|
||||||
SeasonNumber = seasonNumber;
|
SeasonNumber = seasonNumber;
|
||||||
EpisodeNumber = episodeNumber;
|
EpisodeNumber = episodeNumber;
|
||||||
AbsoluteNumber = absoluteNumber;
|
AbsoluteNumber = absoluteNumber;
|
||||||
Title = title;
|
Title = title;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
ReleaseDate = releaseDate;
|
ReleaseDate = releaseDate;
|
||||||
Runtime = runtime;
|
Runtime = runtime;
|
||||||
ImgPrimary = imgPrimary;
|
ImgPrimary = imgPrimary;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Episode(long showID, long seasonID, long seasonNumber, long episodeNumber, long absoluteNumber, string path, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
|
public Episode(long showID, long seasonID, long seasonNumber, long episodeNumber, long absoluteNumber, string path, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
|
||||||
{
|
{
|
||||||
ShowID = showID;
|
ShowID = showID;
|
||||||
SeasonID = seasonID;
|
SeasonID = seasonID;
|
||||||
SeasonNumber = seasonNumber;
|
SeasonNumber = seasonNumber;
|
||||||
EpisodeNumber = episodeNumber;
|
EpisodeNumber = episodeNumber;
|
||||||
AbsoluteNumber = absoluteNumber;
|
AbsoluteNumber = absoluteNumber;
|
||||||
Path = path;
|
Path = path;
|
||||||
Title = title;
|
Title = title;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
ReleaseDate = releaseDate;
|
ReleaseDate = releaseDate;
|
||||||
Runtime = runtime;
|
Runtime = runtime;
|
||||||
ImgPrimary = imgPrimary;
|
ImgPrimary = imgPrimary;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetSlug(string showSlug, long seasonNumber, long episodeNumber)
|
public static string GetSlug(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
return showSlug + "-s" + seasonNumber + "e" + episodeNumber;
|
return showSlug + "-s" + seasonNumber + "e" + episodeNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Episode SetLink(string showSlug)
|
public Episode SetLink(string showSlug)
|
||||||
{
|
{
|
||||||
Link = GetSlug(showSlug, SeasonNumber, EpisodeNumber);
|
Link = GetSlug(showSlug, SeasonNumber, EpisodeNumber);
|
||||||
Thumb = "thumb/" + Link;
|
Thumb = "thumb/" + Link;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Episode Merge(Episode other)
|
public Episode Merge(Episode other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
return this;
|
return this;
|
||||||
if (ID == -1)
|
if (ID == -1)
|
||||||
ID = other.ID;
|
ID = other.ID;
|
||||||
if (ShowID == -1)
|
if (ShowID == -1)
|
||||||
ShowID = other.ShowID;
|
ShowID = other.ShowID;
|
||||||
if (SeasonID == -1)
|
if (SeasonID == -1)
|
||||||
SeasonID = other.SeasonID;
|
SeasonID = other.SeasonID;
|
||||||
if (SeasonNumber == -1)
|
if (SeasonNumber == -1)
|
||||||
SeasonNumber = other.SeasonNumber;
|
SeasonNumber = other.SeasonNumber;
|
||||||
if (EpisodeNumber == -1)
|
if (EpisodeNumber == -1)
|
||||||
EpisodeNumber = other.EpisodeNumber;
|
EpisodeNumber = other.EpisodeNumber;
|
||||||
if (AbsoluteNumber == -1)
|
if (AbsoluteNumber == -1)
|
||||||
AbsoluteNumber = other.AbsoluteNumber;
|
AbsoluteNumber = other.AbsoluteNumber;
|
||||||
if (Path == null)
|
Path ??= other.Path;
|
||||||
Path = other.Path;
|
Title ??= other.Title;
|
||||||
if (Title == null)
|
Overview ??= other.Overview;
|
||||||
Title = other.Title;
|
ReleaseDate ??= other.ReleaseDate;
|
||||||
if (Overview == null)
|
if (Runtime == -1)
|
||||||
Overview = other.Overview;
|
Runtime = other.Runtime;
|
||||||
if (ReleaseDate == null)
|
ImgPrimary ??= other.ImgPrimary;
|
||||||
ReleaseDate = other.ReleaseDate;
|
ExternalIDs += '|' + other.ExternalIDs;
|
||||||
if (Runtime == -1)
|
return this;
|
||||||
Runtime = other.Runtime;
|
}
|
||||||
if (ImgPrimary == null)
|
}
|
||||||
ImgPrimary = other.ImgPrimary;
|
|
||||||
ExternalIDs += '|' + other.ExternalIDs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,25 +3,25 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Genre
|
public class Genre
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
// public IEnumerable<Show> Shows { get; set; }
|
// public IEnumerable<Show> Shows { get; set; }
|
||||||
|
|
||||||
public Genre(string slug, string name)
|
public Genre(string slug, string name)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Genre(long id, string slug, string name)
|
public Genre(long id, string slug, string name)
|
||||||
{
|
{
|
||||||
ID = id;
|
ID = id;
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,22 +2,22 @@
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Library
|
public class Library
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string[] Paths { get; set; }
|
public string[] Paths { get; set; }
|
||||||
public string[] Providers { get; set; }
|
public string[] Providers { get; set; }
|
||||||
|
|
||||||
public Library() { }
|
public Library() { }
|
||||||
|
|
||||||
public Library(string slug, string name, string[] paths, string[] providers)
|
public Library(string slug, string name, string[] paths, string[] providers)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
Paths = paths;
|
Paths = paths;
|
||||||
Providers = providers;
|
Providers = providers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,37 +3,34 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class People : IMergable<People>
|
public class People : IMergable<People>
|
||||||
{
|
{
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||||
public string ExternalIDs { get; set; }
|
public string ExternalIDs { get; set; }
|
||||||
|
|
||||||
[JsonIgnore] public virtual IEnumerable<PeopleLink> Roles { get; set; }
|
[JsonIgnore] public virtual IEnumerable<PeopleLink> Roles { get; set; }
|
||||||
|
|
||||||
public People() {}
|
public People() {}
|
||||||
|
|
||||||
public People(string slug, string name, string imgPrimary, string externalIDs)
|
public People(string slug, string name, string imgPrimary, string externalIDs)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
ImgPrimary = imgPrimary;
|
ImgPrimary = imgPrimary;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public People Merge(People other)
|
public People Merge(People other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
return this;
|
return this;
|
||||||
if (Slug == null)
|
Slug ??= other.Slug;
|
||||||
Slug = other.Slug;
|
Name ??= other.Name;
|
||||||
if (Name == null)
|
ImgPrimary ??= other.ImgPrimary;
|
||||||
Name = other.Name;
|
ExternalIDs += '|' + other.ExternalIDs;
|
||||||
if (ImgPrimary == null)
|
return this;
|
||||||
ImgPrimary = other.ImgPrimary;
|
}
|
||||||
ExternalIDs += '|' + other.ExternalIDs;
|
}
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,36 +2,36 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class PeopleLink
|
public class PeopleLink
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
[JsonIgnore] public string PeopleID { get; set; }
|
[JsonIgnore] public string PeopleID { get; set; }
|
||||||
[JsonIgnore] public virtual People People { get; set; }
|
[JsonIgnore] public virtual People People { get; set; }
|
||||||
|
|
||||||
public string Slug => People.Slug;
|
public string Slug => People.Slug;
|
||||||
public string Name => People.Name;
|
public string Name => People.Name;
|
||||||
public string ExternalIDs => People.ExternalIDs;
|
public string ExternalIDs => People.ExternalIDs;
|
||||||
|
|
||||||
[JsonIgnore] public long ShowID { get; set; }
|
[JsonIgnore] public long ShowID { get; set; }
|
||||||
[JsonIgnore] public virtual Show Show { get; set; }
|
[JsonIgnore] public virtual Show Show { get; set; }
|
||||||
public string Role { get; set; }
|
public string Role { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
|
|
||||||
public PeopleLink() {}
|
public PeopleLink() {}
|
||||||
|
|
||||||
public PeopleLink(People people, Show show, string role, string type)
|
public PeopleLink(People people, Show show, string role, string type)
|
||||||
{
|
{
|
||||||
People = people;
|
People = people;
|
||||||
Show = show;
|
Show = show;
|
||||||
Role = role;
|
Role = role;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeopleLink(string slug, string name, string role, string type, string imgPrimary, string externalIDs)
|
public PeopleLink(string slug, string name, string role, string type, string imgPrimary, string externalIDs)
|
||||||
{
|
{
|
||||||
People = new People(slug, name, imgPrimary, externalIDs);
|
People = new People(slug, name, imgPrimary, externalIDs);
|
||||||
Role = role;
|
Role = role;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class SearchResult
|
public class SearchResult
|
||||||
{
|
{
|
||||||
public string Query;
|
public string Query;
|
||||||
public IEnumerable<Show> Shows;
|
public IEnumerable<Show> Shows;
|
||||||
public IEnumerable<Episode> Episodes;
|
public IEnumerable<Episode> Episodes;
|
||||||
public IEnumerable<People> People;
|
public IEnumerable<People> People;
|
||||||
public IEnumerable<Genre> Genres;
|
public IEnumerable<Genre> Genres;
|
||||||
public IEnumerable<Studio> Studios;
|
public IEnumerable<Studio> Studios;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,53 +3,49 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Season : IMergable<Season>
|
public class Season : IMergable<Season>
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
[JsonIgnore] public long ShowID { get; set; }
|
[JsonIgnore] public long ShowID { get; set; }
|
||||||
|
|
||||||
public long SeasonNumber { get; set; } = -1;
|
public long SeasonNumber { get; set; } = -1;
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
public long? Year { get; set; }
|
public long? Year { get; set; }
|
||||||
|
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||||
public string ExternalIDs { get; set; }
|
public string ExternalIDs { get; set; }
|
||||||
|
|
||||||
[JsonIgnore] public virtual Show Show { get; set; }
|
[JsonIgnore] public virtual Show Show { get; set; }
|
||||||
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
||||||
|
|
||||||
public Season() { }
|
public Season() { }
|
||||||
|
|
||||||
public Season(long showID, long seasonNumber, string title, string overview, long? year, string imgPrimary, string externalIDs)
|
public Season(long showID, long seasonNumber, string title, string overview, long? year, string imgPrimary, string externalIDs)
|
||||||
{
|
{
|
||||||
ShowID = showID;
|
ShowID = showID;
|
||||||
SeasonNumber = seasonNumber;
|
SeasonNumber = seasonNumber;
|
||||||
Title = title;
|
Title = title;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
Year = year;
|
Year = year;
|
||||||
ImgPrimary = imgPrimary;
|
ImgPrimary = imgPrimary;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Season Merge(Season other)
|
public Season Merge(Season other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
return this;
|
return this;
|
||||||
if (ShowID == -1)
|
if (ShowID == -1)
|
||||||
ShowID = other.ShowID;
|
ShowID = other.ShowID;
|
||||||
if (SeasonNumber == -1)
|
if (SeasonNumber == -1)
|
||||||
SeasonNumber = other.SeasonNumber;
|
SeasonNumber = other.SeasonNumber;
|
||||||
if (Title == null)
|
Title ??= other.Title;
|
||||||
Title = other.Title;
|
Overview ??= other.Overview;
|
||||||
if (Overview == null)
|
Year ??= other.Year;
|
||||||
Overview = other.Overview;
|
ImgPrimary ??= other.ImgPrimary;
|
||||||
if (Year == null)
|
ExternalIDs += '|' + other.ExternalIDs;
|
||||||
Year = other.Year;
|
return this;
|
||||||
if (ImgPrimary == null)
|
}
|
||||||
ImgPrimary = other.ImgPrimary;
|
}
|
||||||
ExternalIDs += '|' + other.ExternalIDs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,144 +5,126 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Show : IMergable<Show>
|
public class Show : IMergable<Show>
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
|
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string[] Aliases { get; set; }
|
public string[] Aliases { get; set; }
|
||||||
[JsonIgnore] public string Path { get; set; }
|
[JsonIgnore] public string Path { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
public Status? Status { get; set; }
|
public Status? Status { get; set; }
|
||||||
public string TrailerUrl { get; set; }
|
public string TrailerUrl { get; set; }
|
||||||
|
|
||||||
public long? StartYear { get; set; }
|
public long? StartYear { get; set; }
|
||||||
public long? EndYear { get; set; }
|
public long? EndYear { get; set; }
|
||||||
|
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||||
[JsonIgnore] public string ImgThumb { get; set; }
|
[JsonIgnore] public string ImgThumb { get; set; }
|
||||||
[JsonIgnore] public string ImgLogo { get; set; }
|
[JsonIgnore] public string ImgLogo { get; set; }
|
||||||
[JsonIgnore] public string ImgBackdrop { get; set; }
|
[JsonIgnore] public string ImgBackdrop { get; set; }
|
||||||
|
|
||||||
public string ExternalIDs { get; set; }
|
public string ExternalIDs { get; set; }
|
||||||
|
|
||||||
public bool IsMovie { get; set; }
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
public bool IsCollection;
|
public bool IsCollection;
|
||||||
|
|
||||||
[JsonIgnore] public virtual IEnumerable<Genre> Genres
|
[JsonIgnore] public virtual IEnumerable<Genre> Genres
|
||||||
{
|
{
|
||||||
get { return GenreLinks?.Select(x => x.Genre).OrderBy(x => x.Name); }
|
get { return GenreLinks?.Select(x => x.Genre).OrderBy(x => x.Name); }
|
||||||
set { GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList(); }
|
set { GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList(); }
|
||||||
}
|
}
|
||||||
[JsonIgnore] public virtual List<GenreLink> GenreLinks { get; set; }
|
[JsonIgnore] public virtual List<GenreLink> GenreLinks { get; set; }
|
||||||
[JsonIgnore] public virtual Studio Studio { get; set; }
|
[JsonIgnore] public virtual Studio Studio { get; set; }
|
||||||
[JsonIgnore] public virtual IEnumerable<PeopleLink> People { get; set; }
|
[JsonIgnore] public virtual IEnumerable<PeopleLink> People { get; set; }
|
||||||
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
|
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
|
||||||
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public string GetAliases()
|
public string GetAliases()
|
||||||
{
|
{
|
||||||
return Aliases == null ? null : string.Join('|', Aliases);
|
return Aliases == null ? null : string.Join('|', Aliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetGenres()
|
public string GetGenres()
|
||||||
{
|
{
|
||||||
return Genres == null ? null : string.Join('|', Genres);
|
return Genres == null ? null : string.Join('|', Genres);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Show() { }
|
public Show() { }
|
||||||
|
|
||||||
public Show(string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, IEnumerable<Genre> genres, Status? status, long? startYear, long? endYear, string externalIDs)
|
public Show(string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, IEnumerable<Genre> genres, Status? status, long? startYear, long? endYear, string externalIDs)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Title = title;
|
Title = title;
|
||||||
Aliases = aliases.ToArray();
|
Aliases = aliases.ToArray();
|
||||||
Path = path;
|
Path = path;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
TrailerUrl = trailerUrl;
|
TrailerUrl = trailerUrl;
|
||||||
Genres = genres;
|
Genres = genres;
|
||||||
Status = status;
|
Status = status;
|
||||||
StartYear = startYear;
|
StartYear = startYear;
|
||||||
EndYear = endYear;
|
EndYear = endYear;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
IsCollection = false;
|
IsCollection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Show(string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgLogo, string imgBackdrop, string externalIDs)
|
public Show(string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgLogo, string imgBackdrop, string externalIDs)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Title = title;
|
Title = title;
|
||||||
Aliases = aliases.ToArray();
|
Aliases = aliases.ToArray();
|
||||||
Path = path;
|
Path = path;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
TrailerUrl = trailerUrl;
|
TrailerUrl = trailerUrl;
|
||||||
Status = status;
|
Status = status;
|
||||||
StartYear = startYear;
|
StartYear = startYear;
|
||||||
EndYear = endYear;
|
EndYear = endYear;
|
||||||
ImgPrimary = imgPrimary;
|
ImgPrimary = imgPrimary;
|
||||||
ImgThumb = imgThumb;
|
ImgThumb = imgThumb;
|
||||||
ImgLogo = imgLogo;
|
ImgLogo = imgLogo;
|
||||||
ImgBackdrop = imgBackdrop;
|
ImgBackdrop = imgBackdrop;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
IsCollection = false;
|
IsCollection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetID(string provider)
|
public string GetID(string provider)
|
||||||
{
|
{
|
||||||
if (ExternalIDs?.Contains(provider) != true)
|
if (ExternalIDs?.Contains(provider) != true)
|
||||||
return null;
|
return null;
|
||||||
int startIndex = ExternalIDs.IndexOf(provider, StringComparison.Ordinal) + provider.Length + 1; //The + 1 is for the '='
|
int startIndex = ExternalIDs.IndexOf(provider, StringComparison.Ordinal) + provider.Length + 1; //The + 1 is for the '='
|
||||||
if (ExternalIDs.IndexOf('|', startIndex) == -1)
|
if (ExternalIDs.IndexOf('|', startIndex) == -1)
|
||||||
return ExternalIDs.Substring(startIndex);
|
return ExternalIDs.Substring(startIndex);
|
||||||
return ExternalIDs.Substring(startIndex, ExternalIDs.IndexOf('|', startIndex) - startIndex);
|
return ExternalIDs.Substring(startIndex, ExternalIDs.IndexOf('|', startIndex) - startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Show Merge(Show other)
|
public Show Merge(Show other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
return this;
|
return this;
|
||||||
if (ID == -1)
|
if (ID == -1)
|
||||||
ID = other.ID;
|
ID = other.ID;
|
||||||
if (Slug == null)
|
Slug ??= other.Slug;
|
||||||
Slug = other.Slug;
|
Title ??= other.Title;
|
||||||
if (Title == null)
|
Aliases = Aliases == null ? other.Aliases : Aliases.Concat(other.Aliases).ToArray();
|
||||||
Title = other.Title;
|
Genres = Genres == null ? other.Genres : Genres.Concat(other.Genres);
|
||||||
if (Aliases == null)
|
Path ??= other.Path;
|
||||||
Aliases = other.Aliases;
|
Overview ??= other.Overview;
|
||||||
else
|
TrailerUrl ??= other.TrailerUrl;
|
||||||
Aliases = Aliases.Concat(other.Aliases).ToArray();
|
Status ??= other.Status;
|
||||||
if (Genres == null)
|
StartYear ??= other.StartYear;
|
||||||
Genres = other.Genres;
|
EndYear ??= other.EndYear;
|
||||||
else
|
ImgPrimary ??= other.ImgPrimary;
|
||||||
Genres = Genres.Concat(other.Genres);
|
ImgThumb ??= other.ImgThumb;
|
||||||
if (Path == null)
|
ImgLogo ??= other.ImgLogo;
|
||||||
Path = other.Path;
|
ImgBackdrop ??= other.ImgBackdrop;
|
||||||
if (Overview == null)
|
ExternalIDs += '|' + other.ExternalIDs;
|
||||||
Overview = other.Overview;
|
return this;
|
||||||
if (TrailerUrl == null)
|
}
|
||||||
TrailerUrl = other.TrailerUrl;
|
}
|
||||||
if (Status == null)
|
|
||||||
Status = other.Status;
|
|
||||||
if (StartYear == null)
|
|
||||||
StartYear = other.StartYear;
|
|
||||||
if (EndYear == null)
|
|
||||||
EndYear = other.EndYear;
|
|
||||||
if (ImgPrimary == null)
|
|
||||||
ImgPrimary = other.ImgPrimary;
|
|
||||||
if (ImgThumb == null)
|
|
||||||
ImgThumb = other.ImgThumb;
|
|
||||||
if (ImgLogo == null)
|
|
||||||
ImgLogo = other.ImgLogo;
|
|
||||||
if (ImgBackdrop == null)
|
|
||||||
ImgBackdrop = other.ImgBackdrop;
|
|
||||||
ExternalIDs += '|' + other.ExternalIDs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Status { Finished, Airing }
|
public enum Status { Finished, Airing }
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,23 @@
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Studio
|
public class Studio
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public Studio() { }
|
public Studio() { }
|
||||||
|
|
||||||
public Studio(string slug, string name)
|
public Studio(string slug, string name)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Studio Default()
|
public static Studio Default()
|
||||||
{
|
{
|
||||||
return new Studio("unknow", "Unknow Studio");
|
return new Studio("unknow", "Unknow Studio");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,121 +7,121 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
namespace Watch
|
namespace Watch
|
||||||
{
|
{
|
||||||
public enum StreamType
|
public enum StreamType
|
||||||
{
|
{
|
||||||
Unknow = 0,
|
Unknow = 0,
|
||||||
Video = 1,
|
Video = 1,
|
||||||
Audio = 2,
|
Audio = 2,
|
||||||
Subtitle = 3
|
Subtitle = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||||
public class Stream
|
public class Stream
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Language { get; set; }
|
public string Language { get; set; }
|
||||||
public string Codec { get; set; }
|
public string Codec { get; set; }
|
||||||
[MarshalAs(UnmanagedType.I1)] public bool isDefault;
|
[MarshalAs(UnmanagedType.I1)] public bool isDefault;
|
||||||
[MarshalAs(UnmanagedType.I1)] public bool isForced;
|
[MarshalAs(UnmanagedType.I1)] public bool isForced;
|
||||||
[JsonIgnore] public string Path { get; set; }
|
[JsonIgnore] public string Path { get; set; }
|
||||||
[JsonIgnore] public StreamType Type { get; set; }
|
[JsonIgnore] public StreamType Type { get; set; }
|
||||||
|
|
||||||
public Stream() {}
|
public Stream() {}
|
||||||
|
|
||||||
public Stream(string title, string language, string codec, bool isDefault, bool isForced, string path, StreamType type)
|
public Stream(string title, string language, string codec, bool isDefault, bool isForced, string path, StreamType type)
|
||||||
{
|
{
|
||||||
Title = title;
|
Title = title;
|
||||||
Language = language;
|
Language = language;
|
||||||
Codec = codec;
|
Codec = codec;
|
||||||
this.isDefault = isDefault;
|
this.isDefault = isDefault;
|
||||||
this.isForced = isForced;
|
this.isForced = isForced;
|
||||||
Path = path;
|
Path = path;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream(Stream stream)
|
public Stream(Stream stream)
|
||||||
{
|
{
|
||||||
Title = stream.Title;
|
Title = stream.Title;
|
||||||
Language = stream.Language;
|
Language = stream.Language;
|
||||||
isDefault = stream.isDefault;
|
isDefault = stream.isDefault;
|
||||||
isForced = stream.isForced;
|
isForced = stream.isForced;
|
||||||
Codec = stream.Codec;
|
Codec = stream.Codec;
|
||||||
Path = stream.Path;
|
Path = stream.Path;
|
||||||
Type = stream.Type;
|
Type = stream.Type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Track : Stream
|
public class Track : Stream
|
||||||
{
|
{
|
||||||
[JsonIgnore] public long ID { get; set; }
|
[JsonIgnore] public long ID { get; set; }
|
||||||
[JsonIgnore] public long EpisodeID { get; set; }
|
[JsonIgnore] public long EpisodeID { get; set; }
|
||||||
public bool IsDefault
|
public bool IsDefault
|
||||||
{
|
{
|
||||||
get => isDefault;
|
get => isDefault;
|
||||||
set => isDefault = value;
|
set => isDefault = value;
|
||||||
}
|
}
|
||||||
public bool IsForced
|
public bool IsForced
|
||||||
{
|
{
|
||||||
get => isForced;
|
get => isForced;
|
||||||
set => isForced = value;
|
set => isForced = value;
|
||||||
}
|
}
|
||||||
public string DisplayName;
|
public string DisplayName;
|
||||||
public string Link;
|
public string Link;
|
||||||
|
|
||||||
[JsonIgnore] public bool IsExternal { get; set; }
|
[JsonIgnore] public bool IsExternal { get; set; }
|
||||||
[JsonIgnore] public virtual Episode Episode { get; set; }
|
[JsonIgnore] public virtual Episode Episode { get; set; }
|
||||||
|
|
||||||
public Track() { }
|
public Track() { }
|
||||||
|
|
||||||
public Track(StreamType type, string title, string language, bool isDefault, bool isForced, string codec, bool isExternal, string path)
|
public Track(StreamType type, string title, string language, bool isDefault, bool isForced, string codec, bool isExternal, string path)
|
||||||
: base(title, language, codec, isDefault, isForced, path, type)
|
: base(title, language, codec, isDefault, isForced, path, type)
|
||||||
{
|
{
|
||||||
IsExternal = isExternal;
|
IsExternal = isExternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Track(Stream stream)
|
public Track(Stream stream)
|
||||||
: base(stream)
|
: base(stream)
|
||||||
{
|
{
|
||||||
IsExternal = false;
|
IsExternal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Track SetLink(string episodeSlug)
|
public Track SetLink(string episodeSlug)
|
||||||
{
|
{
|
||||||
if (Type == StreamType.Subtitle)
|
if (Type == StreamType.Subtitle)
|
||||||
{
|
{
|
||||||
string language = Language;
|
string language = Language;
|
||||||
//Converting mkv track language to c# system language tag.
|
//Converting mkv track language to c# system language tag.
|
||||||
if (language == "fre")
|
if (language == "fre")
|
||||||
language = "fra";
|
language = "fra";
|
||||||
|
|
||||||
DisplayName = CultureInfo.GetCultures(CultureTypes.NeutralCultures).FirstOrDefault(x => x.ThreeLetterISOLanguageName == language)?.EnglishName ?? language;
|
DisplayName = CultureInfo.GetCultures(CultureTypes.NeutralCultures).FirstOrDefault(x => x.ThreeLetterISOLanguageName == language)?.EnglishName ?? language;
|
||||||
Link = "/subtitle/" + episodeSlug + "." + Language;
|
Link = "/subtitle/" + episodeSlug + "." + Language;
|
||||||
|
|
||||||
if (IsForced)
|
if (IsForced)
|
||||||
{
|
{
|
||||||
DisplayName += " Forced";
|
DisplayName += " Forced";
|
||||||
Link += "-forced";
|
Link += "-forced";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Title != null && Title.Length > 1)
|
if (Title != null && Title.Length > 1)
|
||||||
DisplayName += " - " + Title;
|
DisplayName += " - " + Title;
|
||||||
|
|
||||||
switch (Codec)
|
switch (Codec)
|
||||||
{
|
{
|
||||||
case "ass":
|
case "ass":
|
||||||
Link += ".ass";
|
Link += ".ass";
|
||||||
break;
|
break;
|
||||||
case "subrip":
|
case "subrip":
|
||||||
Link += ".srt";
|
Link += ".srt";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Link = null;
|
Link = null;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,48 +4,48 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class WatchItem
|
public class WatchItem
|
||||||
{
|
{
|
||||||
[JsonIgnore] public readonly long EpisodeID = -1;
|
[JsonIgnore] public readonly long EpisodeID = -1;
|
||||||
|
|
||||||
public string ShowTitle;
|
public string ShowTitle;
|
||||||
public string ShowSlug;
|
public string ShowSlug;
|
||||||
public long SeasonNumber;
|
public long SeasonNumber;
|
||||||
public long EpisodeNumber;
|
public long EpisodeNumber;
|
||||||
public string Title;
|
public string Title;
|
||||||
public string Link;
|
public string Link;
|
||||||
public DateTime? ReleaseDate;
|
public DateTime? ReleaseDate;
|
||||||
[JsonIgnore] public string Path;
|
[JsonIgnore] public string Path;
|
||||||
public string PreviousEpisode;
|
public string PreviousEpisode;
|
||||||
public Episode NextEpisode;
|
public Episode NextEpisode;
|
||||||
|
|
||||||
public string Container;
|
public string Container;
|
||||||
public Track Video;
|
public Track Video;
|
||||||
public IEnumerable<Track> Audios;
|
public IEnumerable<Track> Audios;
|
||||||
public IEnumerable<Track> Subtitles;
|
public IEnumerable<Track> Subtitles;
|
||||||
|
|
||||||
public WatchItem() { }
|
public WatchItem() { }
|
||||||
|
|
||||||
public WatchItem(long episodeID, string showTitle, string showSlug, long seasonNumber, long episodeNumber, string title, DateTime? releaseDate, string path)
|
public WatchItem(long episodeID, string showTitle, string showSlug, long seasonNumber, long episodeNumber, string title, DateTime? releaseDate, string path)
|
||||||
{
|
{
|
||||||
EpisodeID = episodeID;
|
EpisodeID = episodeID;
|
||||||
ShowTitle = showTitle;
|
ShowTitle = showTitle;
|
||||||
ShowSlug = showSlug;
|
ShowSlug = showSlug;
|
||||||
SeasonNumber = seasonNumber;
|
SeasonNumber = seasonNumber;
|
||||||
EpisodeNumber = episodeNumber;
|
EpisodeNumber = episodeNumber;
|
||||||
Title = title;
|
Title = title;
|
||||||
ReleaseDate = releaseDate;
|
ReleaseDate = releaseDate;
|
||||||
Path = path;
|
Path = path;
|
||||||
|
|
||||||
Container = Path.Substring(Path.LastIndexOf('.') + 1);
|
Container = Path.Substring(Path.LastIndexOf('.') + 1);
|
||||||
Link = Episode.GetSlug(ShowSlug, seasonNumber, episodeNumber);
|
Link = Episode.GetSlug(ShowSlug, seasonNumber, episodeNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WatchItem(long episodeID, string showTitle, string showSlug, long seasonNumber, long episodeNumber, string title, DateTime? releaseDate, string path, Track[] audios, Track[] subtitles)
|
public WatchItem(long episodeID, string showTitle, string showSlug, long seasonNumber, long episodeNumber, string title, DateTime? releaseDate, string path, Track[] audios, Track[] subtitles)
|
||||||
: this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path)
|
: this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path)
|
||||||
{
|
{
|
||||||
Audios = audios;
|
Audios = audios;
|
||||||
Subtitles = subtitles;
|
Subtitles = subtitles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,39 +3,39 @@ using Kyoo.Models;
|
|||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
public interface IMergable<T>
|
public interface IMergable<T>
|
||||||
{
|
{
|
||||||
public T Merge(T other);
|
public T Merge(T other);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Utility
|
public static class Utility
|
||||||
{
|
{
|
||||||
public static string ToSlug(string name)
|
public static string ToSlug(string name)
|
||||||
{
|
{
|
||||||
if (name == null)
|
if (name == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
//First to lower case
|
//First to lower case
|
||||||
name = name.ToLowerInvariant();
|
name = name.ToLowerInvariant();
|
||||||
|
|
||||||
//Remove all accents
|
//Remove all accents
|
||||||
//var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(showTitle);
|
//var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(showTitle);
|
||||||
//showTitle = Encoding.ASCII.GetString(bytes);
|
//showTitle = Encoding.ASCII.GetString(bytes);
|
||||||
|
|
||||||
//Replace spaces
|
//Replace spaces
|
||||||
name = Regex.Replace(name, @"\s", "-", RegexOptions.Compiled);
|
name = Regex.Replace(name, @"\s", "-", RegexOptions.Compiled);
|
||||||
|
|
||||||
//Remove invalid chars
|
//Remove invalid chars
|
||||||
name = Regex.Replace(name, @"[^\w\s\p{Pd}]", "", RegexOptions.Compiled);
|
name = Regex.Replace(name, @"[^\w\s\p{Pd}]", "", RegexOptions.Compiled);
|
||||||
|
|
||||||
//Trim dashes from end
|
//Trim dashes from end
|
||||||
name = name.Trim('-', '_');
|
name = name.Trim('-', '_');
|
||||||
|
|
||||||
//Replace double occurences of - or \_
|
//Replace double occurences of - or \_
|
||||||
name = Regex.Replace(name, @"([-_]){2,}", "$1", RegexOptions.Compiled);
|
name = Regex.Replace(name, @"([-_]){2,}", "$1", RegexOptions.Compiled);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void SetImage(Show show, string imgUrl, ImageType type)
|
public static void SetImage(Show show, string imgUrl, ImageType type)
|
||||||
|
@ -11,173 +11,173 @@ using Kyoo.Models.Watch;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class Crawler : ICrawler
|
public class Crawler : ICrawler
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IProviderManager _metadataProvider;
|
private readonly IProviderManager _metadataProvider;
|
||||||
private readonly ITranscoder _transcoder;
|
private readonly ITranscoder _transcoder;
|
||||||
private readonly IConfiguration _config;
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
public Crawler(ILibraryManager libraryManager, IProviderManager metadataProvider, ITranscoder transcoder, IConfiguration configuration)
|
public Crawler(ILibraryManager libraryManager, IProviderManager metadataProvider, ITranscoder transcoder, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_metadataProvider = metadataProvider;
|
_metadataProvider = metadataProvider;
|
||||||
_transcoder = transcoder;
|
_transcoder = transcoder;
|
||||||
_config = configuration;
|
_config = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IEnumerable<Episode> episodes = _libraryManager.GetAllEpisodes();
|
IEnumerable<Episode> episodes = _libraryManager.GetAllEpisodes();
|
||||||
IEnumerable<Library> libraries = _libraryManager.GetLibraries();
|
IEnumerable<Library> libraries = _libraryManager.GetLibraries();
|
||||||
|
|
||||||
foreach (Episode episode in episodes)
|
foreach (Episode episode in episodes)
|
||||||
{
|
{
|
||||||
if (!File.Exists(episode.Path))
|
if (!File.Exists(episode.Path))
|
||||||
_libraryManager.RemoveEpisode(episode.ID);
|
_libraryManager.RemoveEpisode(episode.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Library library in libraries)
|
foreach (Library library in libraries)
|
||||||
await Scan(library, cancellationToken);
|
await Scan(library, cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"Unknown exception thrown durring libraries scan.\nException: {ex.Message}");
|
Console.Error.WriteLine($"Unknown exception thrown durring libraries scan.\nException: {ex.Message}");
|
||||||
}
|
}
|
||||||
Console.WriteLine("Scan finished!");
|
Console.WriteLine("Scan finished!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Scan(Library library, CancellationToken cancellationToken)
|
private async Task Scan(Library library, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Scanning library {library.Name} at {string.Concat(library.Paths)}");
|
Console.WriteLine($"Scanning library {library.Name} at {string.Concat(library.Paths)}");
|
||||||
foreach (string path in library.Paths)
|
foreach (string path in library.Paths)
|
||||||
{
|
{
|
||||||
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
|
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
if (!IsVideo(file) || _libraryManager.IsEpisodeRegistered(file, out long _))
|
if (!IsVideo(file) || _libraryManager.IsEpisodeRegistered(file, out long _))
|
||||||
continue;
|
continue;
|
||||||
string relativePath = file.Substring(path.Length);
|
string relativePath = file.Substring(path.Length);
|
||||||
await RegisterFile(file, relativePath, library);
|
await RegisterFile(file, relativePath, library);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RegisterFile(string path, string relativePath, Library library)
|
private async Task RegisterFile(string path, string relativePath, Library library)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Registering episode at: " + path);
|
Console.WriteLine("Registering episode at: " + path);
|
||||||
string patern = _config.GetValue<string>("regex");
|
string patern = _config.GetValue<string>("regex");
|
||||||
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
|
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
|
||||||
Match match = regex.Match(relativePath);
|
Match match = regex.Match(relativePath);
|
||||||
|
|
||||||
string showPath = Path.GetDirectoryName(path);
|
string showPath = Path.GetDirectoryName(path);
|
||||||
string collectionName = match.Groups["Collection"]?.Value;
|
string collectionName = match.Groups["Collection"]?.Value;
|
||||||
string showName = match.Groups["ShowTitle"].Value;
|
string showName = match.Groups["ShowTitle"].Value;
|
||||||
long seasonNumber = long.TryParse(match.Groups["Season"].Value, out long tmp) ? tmp : -1;
|
long seasonNumber = long.TryParse(match.Groups["Season"].Value, out long tmp) ? tmp : -1;
|
||||||
long episodeNumber = long.TryParse(match.Groups["Episode"].Value, out tmp) ? tmp : -1;
|
long episodeNumber = long.TryParse(match.Groups["Episode"].Value, out tmp) ? tmp : -1;
|
||||||
long absoluteNumber = long.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1;
|
long absoluteNumber = long.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1;
|
||||||
|
|
||||||
Collection collection = await GetCollection(collectionName, library);
|
Collection collection = await GetCollection(collectionName, library);
|
||||||
bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1;
|
bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1;
|
||||||
Show show = await GetShow(showName, showPath, isMovie, library);
|
Show show = await GetShow(showName, showPath, isMovie, library);
|
||||||
if (isMovie)
|
if (isMovie)
|
||||||
_libraryManager.RegisterShow(show);
|
_libraryManager.RegisterShow(show);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Season season = await GetSeason(show, seasonNumber, library);
|
Season season = await GetSeason(show, seasonNumber, library);
|
||||||
Episode episode = await GetEpisode(show, season, episodeNumber, absoluteNumber, path, library);
|
Episode episode = await GetEpisode(show, season, episodeNumber, absoluteNumber, path, library);
|
||||||
_libraryManager.RegisterEpisode(episode);
|
_libraryManager.RegisterEpisode(episode);
|
||||||
}
|
}
|
||||||
_libraryManager.RegisterShowLinks(library, collection, show);
|
_libraryManager.RegisterShowLinks(library, collection, show);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Collection> GetCollection(string collectionName, Library library)
|
private async Task<Collection> GetCollection(string collectionName, Library library)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(collectionName))
|
if (string.IsNullOrEmpty(collectionName))
|
||||||
return await Task.FromResult<Collection>(null);
|
return await Task.FromResult<Collection>(null);
|
||||||
return _libraryManager.GetCollection(Utility.ToSlug(collectionName)) ?? await _metadataProvider.GetCollectionFromName(collectionName, library);
|
return _libraryManager.GetCollection(Utility.ToSlug(collectionName)) ?? await _metadataProvider.GetCollectionFromName(collectionName, library);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Show> GetShow(string showTitle, string showPath, bool isMovie, Library library)
|
private async Task<Show> GetShow(string showTitle, string showPath, bool isMovie, Library library)
|
||||||
{
|
{
|
||||||
Show show = _libraryManager.GetShow(showPath);
|
Show show = _libraryManager.GetShow(showPath);
|
||||||
if (show != null)
|
if (show != null)
|
||||||
return show;
|
return show;
|
||||||
show = await _metadataProvider.GetShowFromName(showTitle, showPath, isMovie, library);
|
show = await _metadataProvider.GetShowFromName(showTitle, showPath, isMovie, library);
|
||||||
show.People = (await _metadataProvider.GetPeople(show, library)).GroupBy(x => x.Slug).Select(x => x.First())
|
show.People = (await _metadataProvider.GetPeople(show, library)).GroupBy(x => x.Slug).Select(x => x.First())
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
{
|
{
|
||||||
People existing = _libraryManager.GetPeopleBySlug(x.Slug);
|
People existing = _libraryManager.GetPeopleBySlug(x.Slug);
|
||||||
return existing != null ? new PeopleLink(existing, show, x.Role, x.Type) : x;
|
return existing != null ? new PeopleLink(existing, show, x.Role, x.Type) : x;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
return show;
|
return show;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Season> GetSeason(Show show, long seasonNumber, Library library)
|
private async Task<Season> GetSeason(Show show, long seasonNumber, Library library)
|
||||||
{
|
{
|
||||||
if (seasonNumber == -1)
|
if (seasonNumber == -1)
|
||||||
return null;
|
return null;
|
||||||
Season season = _libraryManager.GetSeason(show.Slug, seasonNumber);
|
Season season = _libraryManager.GetSeason(show.Slug, seasonNumber);
|
||||||
if (season != null)
|
if (season != null)
|
||||||
return await Task.FromResult(season);
|
return await Task.FromResult(season);
|
||||||
season = await _metadataProvider.GetSeason(show, seasonNumber, library);
|
season = await _metadataProvider.GetSeason(show, seasonNumber, library);
|
||||||
season.Show = show;
|
season.Show = show;
|
||||||
return season;
|
return season;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Episode> GetEpisode(Show show, Season season, long episodeNumber, long absoluteNumber, string episodePath, Library library)
|
private async Task<Episode> GetEpisode(Show show, Season season, long episodeNumber, long absoluteNumber, string episodePath, Library library)
|
||||||
{
|
{
|
||||||
Episode episode = await _metadataProvider.GetEpisode(show, episodePath, season?.SeasonNumber ?? -1, episodeNumber, absoluteNumber, library);
|
Episode episode = await _metadataProvider.GetEpisode(show, episodePath, season?.SeasonNumber ?? -1, episodeNumber, absoluteNumber, library);
|
||||||
episode.Show = show;
|
episode.Show = show;
|
||||||
if (season == null)
|
if (season == null)
|
||||||
season = await GetSeason(show, episode.SeasonNumber, library);
|
season = await GetSeason(show, episode.SeasonNumber, library);
|
||||||
episode.Season = season;
|
episode.Season = season;
|
||||||
|
|
||||||
IEnumerable<Track> tracks = await _transcoder.GetTrackInfo(episode.Path);
|
IEnumerable<Track> tracks = await _transcoder.GetTrackInfo(episode.Path);
|
||||||
List<Track> epTracks = tracks.Where(x => x.Type != StreamType.Subtitle).Concat(GetExtractedSubtitles(episode)).ToList();
|
List<Track> epTracks = tracks.Where(x => x.Type != StreamType.Subtitle).Concat(GetExtractedSubtitles(episode)).ToList();
|
||||||
if (epTracks.Count(x => !x.IsExternal) < tracks.Count())
|
if (epTracks.Count(x => !x.IsExternal) < tracks.Count())
|
||||||
epTracks.AddRange(await _transcoder.ExtractSubtitles(episode.Path));
|
epTracks.AddRange(await _transcoder.ExtractSubtitles(episode.Path));
|
||||||
episode.Tracks = epTracks;
|
episode.Tracks = epTracks;
|
||||||
return episode;
|
return episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Track> GetExtractedSubtitles(Episode episode)
|
private static IEnumerable<Track> GetExtractedSubtitles(Episode episode)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(Path.GetDirectoryName(episode.Path), "Subtitles");
|
string path = Path.Combine(Path.GetDirectoryName(episode.Path), "Subtitles");
|
||||||
List<Track> tracks = new List<Track>();
|
List<Track> tracks = new List<Track>();
|
||||||
|
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
return tracks;
|
return tracks;
|
||||||
foreach (string sub in Directory.EnumerateFiles(path, "", SearchOption.AllDirectories))
|
foreach (string sub in Directory.EnumerateFiles(path, "", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
string episodeLink = Path.GetFileNameWithoutExtension(episode.Path);
|
string episodeLink = Path.GetFileNameWithoutExtension(episode.Path);
|
||||||
|
|
||||||
if (!sub.Contains(episodeLink))
|
if (!sub.Contains(episodeLink))
|
||||||
continue;
|
continue;
|
||||||
string language = sub.Substring(Path.GetDirectoryName(sub).Length + episodeLink.Length + 2, 3);
|
string language = sub.Substring(Path.GetDirectoryName(sub).Length + episodeLink.Length + 2, 3);
|
||||||
bool isDefault = sub.Contains("default");
|
bool isDefault = sub.Contains("default");
|
||||||
bool isForced = sub.Contains("forced");
|
bool isForced = sub.Contains("forced");
|
||||||
Track track = new Track(StreamType.Subtitle, null, language, isDefault, isForced, null, false, sub) { EpisodeID = episode.ID };
|
Track track = new Track(StreamType.Subtitle, null, language, isDefault, isForced, null, false, sub) { EpisodeID = episode.ID };
|
||||||
|
|
||||||
if (Path.GetExtension(sub) == ".ass")
|
if (Path.GetExtension(sub) == ".ass")
|
||||||
track.Codec = "ass";
|
track.Codec = "ass";
|
||||||
else if (Path.GetExtension(sub) == ".srt")
|
else if (Path.GetExtension(sub) == ".srt")
|
||||||
track.Codec = "subrip";
|
track.Codec = "subrip";
|
||||||
else
|
else
|
||||||
track.Codec = null;
|
track.Codec = null;
|
||||||
tracks.Add(track);
|
tracks.Add(track);
|
||||||
}
|
}
|
||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] VideoExtensions = { ".webm", ".mkv", ".flv", ".vob", ".ogg", ".ogv", ".avi", ".mts", ".m2ts", ".ts", ".mov", ".qt", ".asf", ".mp4", ".m4p", ".m4v", ".mpg", ".mp2", ".mpeg", ".mpe", ".mpv", ".m2v", ".3gp", ".3g2" };
|
private static readonly string[] VideoExtensions = { ".webm", ".mkv", ".flv", ".vob", ".ogg", ".ogv", ".avi", ".mts", ".m2ts", ".ts", ".mov", ".qt", ".asf", ".mp4", ".m4p", ".m4v", ".mpg", ".mp2", ".mpeg", ".mpe", ".mpv", ".m2v", ".3gp", ".3g2" };
|
||||||
|
|
||||||
private static bool IsVideo(string filePath)
|
private static bool IsVideo(string filePath)
|
||||||
{
|
{
|
||||||
return VideoExtensions.Contains(Path.GetExtension(filePath));
|
return VideoExtensions.Contains(Path.GetExtension(filePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,9 @@ namespace Kyoo.Controllers
|
|||||||
if (showID == null)
|
if (showID == null)
|
||||||
return null;
|
return null;
|
||||||
return (from track in _database.Tracks where track.Episode.ShowID == showID
|
return (from track in _database.Tracks where track.Episode.ShowID == showID
|
||||||
&& track.Episode.SeasonNumber == seasonNumber
|
&& track.Episode.SeasonNumber == seasonNumber
|
||||||
&& track.Episode.EpisodeNumber == episodeNumber
|
&& track.Episode.EpisodeNumber == episodeNumber
|
||||||
&& track.Language == languageTag select track).FirstOrDefault();
|
&& track.Language == languageTag select track).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ namespace Kyoo.Controllers
|
|||||||
where l.CollectionID == null select show).AsEnumerable().Union(
|
where l.CollectionID == null select show).AsEnumerable().Union(
|
||||||
from collection in _database.Collections select collection.AsShow())
|
from collection in _database.Collections select collection.AsShow())
|
||||||
.Where(x => EF.Functions.Like(x.Title, $"%{searchQuery}%")
|
.Where(x => EF.Functions.Like(x.Title, $"%{searchQuery}%")
|
||||||
|| EF.Functions.Like(x.GetAliases(), $"%{searchQuery}%"))
|
|| EF.Functions.Like(x.GetAliases(), $"%{searchQuery}%"))
|
||||||
.Take(20).OrderBy(x => x.Title);
|
.Take(20).OrderBy(x => x.Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
return (from season in _database.Seasons
|
return (from season in _database.Seasons
|
||||||
where season.SeasonNumber == seasonNumber
|
where season.SeasonNumber == seasonNumber
|
||||||
&& season.Show.Slug == showSlug
|
&& season.Show.Slug == showSlug
|
||||||
select season).FirstOrDefault();
|
select season).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
return (from season in _database.Seasons
|
return (from season in _database.Seasons
|
||||||
where season.SeasonNumber == seasonNumber
|
where season.SeasonNumber == seasonNumber
|
||||||
&& season.Show.Slug == showSlug
|
&& season.Show.Slug == showSlug
|
||||||
select season).FirstOrDefault()?.Episodes.Count() ?? 0;
|
select season).FirstOrDefault()?.Episodes.Count() ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ namespace Kyoo.Controllers
|
|||||||
public IEnumerable<Episode> GetEpisodes(string showSlug, long seasonNumber)
|
public IEnumerable<Episode> GetEpisodes(string showSlug, long seasonNumber)
|
||||||
{
|
{
|
||||||
return (from episode in _database.Episodes where episode.SeasonNumber == seasonNumber
|
return (from episode in _database.Episodes where episode.SeasonNumber == seasonNumber
|
||||||
&& episode.Show.Slug == showSlug select episode)
|
&& episode.Show.Slug == showSlug select episode)
|
||||||
.OrderBy(x => x.EpisodeNumber)
|
.OrderBy(x => x.EpisodeNumber)
|
||||||
.Select(x => x.SetLink(showSlug));
|
.Select(x => x.SetLink(showSlug));
|
||||||
}
|
}
|
||||||
@ -127,20 +127,20 @@ namespace Kyoo.Controllers
|
|||||||
public IEnumerable<Episode> GetEpisodes(long showID, long seasonNumber)
|
public IEnumerable<Episode> GetEpisodes(long showID, long seasonNumber)
|
||||||
{
|
{
|
||||||
return from episode in _database.Episodes where episode.ShowID == showID
|
return from episode in _database.Episodes where episode.ShowID == showID
|
||||||
&& episode.SeasonNumber == seasonNumber select episode.SetLink(episode.Show.Slug);
|
&& episode.SeasonNumber == seasonNumber select episode.SetLink(episode.Show.Slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
|
public Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
return (from episode in _database.Episodes where episode.EpisodeNumber == episodeNumber
|
return (from episode in _database.Episodes where episode.EpisodeNumber == episodeNumber
|
||||||
&& episode.SeasonNumber == seasonNumber
|
&& episode.SeasonNumber == seasonNumber
|
||||||
&& episode.Show.Slug == showSlug select episode.SetLink(showSlug)).FirstOrDefault();
|
&& episode.Show.Slug == showSlug select episode.SetLink(showSlug)).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true)
|
public WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true)
|
||||||
{
|
{
|
||||||
WatchItem item = (from episode in _database.Episodes where episode.SeasonNumber == seasonNumber
|
WatchItem item = (from episode in _database.Episodes where episode.SeasonNumber == seasonNumber
|
||||||
&& episode.EpisodeNumber == episodeNumber && episode.Show.Slug == showSlug
|
&& episode.EpisodeNumber == episodeNumber && episode.Show.Slug == showSlug
|
||||||
select new WatchItem(episode.ID,
|
select new WatchItem(episode.ID,
|
||||||
episode.Show.Title,
|
episode.Show.Title,
|
||||||
episode.Show.Slug,
|
episode.Show.Slug,
|
||||||
|
@ -49,16 +49,16 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
public T GetPlugin<T>(string name)
|
public T GetPlugin<T>(string name)
|
||||||
{
|
{
|
||||||
if (_plugins == null)
|
if (_plugins == null)
|
||||||
return default;
|
return default;
|
||||||
return (T)(from plugin in _plugins where plugin.Name == name && plugin is T select plugin).FirstOrDefault();
|
return (T)(from plugin in _plugins where plugin.Name == name && plugin is T select plugin).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<T> GetPlugins<T>()
|
public IEnumerable<T> GetPlugins<T>()
|
||||||
{
|
{
|
||||||
if (_plugins == null)
|
if (_plugins == null)
|
||||||
return new List<T>();
|
return new List<T>();
|
||||||
return from plugin in _plugins where plugin is T select (T)plugin;
|
return from plugin in _plugins where plugin is T select (T)plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,20 +72,20 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
_plugins = pluginsPaths.Select(path =>
|
_plugins = pluginsPaths.Select(path =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PluginDependencyLoader loader = new PluginDependencyLoader(Path.GetFullPath(path));
|
PluginDependencyLoader loader = new PluginDependencyLoader(Path.GetFullPath(path));
|
||||||
Assembly ass = loader.LoadFromAssemblyPath(Path.GetFullPath(path));
|
Assembly ass = loader.LoadFromAssemblyPath(Path.GetFullPath(path));
|
||||||
return (from type in ass.GetTypes()
|
return (from type in ass.GetTypes()
|
||||||
where typeof(IPlugin).IsAssignableFrom(type)
|
where typeof(IPlugin).IsAssignableFrom(type)
|
||||||
select (IPlugin) ActivatorUtilities.CreateInstance(_provider, type)).FirstOrDefault();
|
select (IPlugin) ActivatorUtilities.CreateInstance(_provider, type)).FirstOrDefault();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"Error loading the plugin at {path}.\nException: {ex.Message}");
|
Console.Error.WriteLine($"Error loading the plugin at {path}.\nException: {ex.Message}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).Where(x => x != null).ToList();
|
}).Where(x => x != null).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,96 +6,96 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class ProviderManager : IProviderManager
|
public class ProviderManager : IProviderManager
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<IMetadataProvider> _providers;
|
private readonly IEnumerable<IMetadataProvider> _providers;
|
||||||
private readonly IThumbnailsManager _thumbnailsManager;
|
private readonly IThumbnailsManager _thumbnailsManager;
|
||||||
|
|
||||||
public ProviderManager(IThumbnailsManager thumbnailsManager, IPluginManager pluginManager)
|
public ProviderManager(IThumbnailsManager thumbnailsManager, IPluginManager pluginManager)
|
||||||
{
|
{
|
||||||
_thumbnailsManager = thumbnailsManager;
|
_thumbnailsManager = thumbnailsManager;
|
||||||
_providers = pluginManager.GetPlugins<IMetadataProvider>();
|
_providers = pluginManager.GetPlugins<IMetadataProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<T> GetMetadata<T>(Func<IMetadataProvider, Task<T>> providerCall, Library library, string what) where T : IMergable<T>, new()
|
public async Task<T> GetMetadata<T>(Func<IMetadataProvider, Task<T>> providerCall, Library library, string what) where T : IMergable<T>, new()
|
||||||
{
|
{
|
||||||
T ret = new T();
|
T ret = new T();
|
||||||
|
|
||||||
foreach (IMetadataProvider provider in _providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name)))
|
foreach (IMetadataProvider provider in _providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (library.Providers.Contains(provider.Name))
|
if (library.Providers.Contains(provider.Name))
|
||||||
ret = ret.Merge(await providerCall(provider));
|
ret = ret.Merge(await providerCall(provider));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. Exception: {ex.Message}");
|
Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. Exception: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<T>> GetMetadata<T>(Func<IMetadataProvider, Task<IEnumerable<T>>> providerCall, Library library, string what)
|
public async Task<IEnumerable<T>> GetMetadata<T>(Func<IMetadataProvider, Task<IEnumerable<T>>> providerCall, Library library, string what)
|
||||||
{
|
{
|
||||||
List<T> ret = new List<T>();
|
List<T> ret = new List<T>();
|
||||||
|
|
||||||
foreach (IMetadataProvider provider in _providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name)))
|
foreach (IMetadataProvider provider in _providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (library.Providers.Contains(provider.Name))
|
if (library.Providers.Contains(provider.Name))
|
||||||
ret.AddRange(await providerCall(provider));
|
ret.AddRange(await providerCall(provider));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. Exception: {ex.Message}");
|
Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. Exception: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Collection> GetCollectionFromName(string name, Library library)
|
public async Task<Collection> GetCollectionFromName(string name, Library library)
|
||||||
{
|
{
|
||||||
Collection collection = await GetMetadata(provider => provider.GetCollectionFromName(name), library, $"the collection {name}");
|
Collection collection = await GetMetadata(provider => provider.GetCollectionFromName(name), library, $"the collection {name}");
|
||||||
collection.Name ??= name;
|
collection.Name ??= name;
|
||||||
collection.Slug ??= Utility.ToSlug(name);
|
collection.Slug ??= Utility.ToSlug(name);
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Show> GetShowFromName(string showName, string showPath, bool isMovie, Library library)
|
public async Task<Show> GetShowFromName(string showName, string showPath, bool isMovie, Library library)
|
||||||
{
|
{
|
||||||
Show show = await GetMetadata(provider => provider.GetShowFromName(showName, isMovie), library, $"the show {showName}");
|
Show show = await GetMetadata(provider => provider.GetShowFromName(showName, isMovie), library, $"the show {showName}");
|
||||||
show.Path = showPath;
|
show.Path = showPath;
|
||||||
show.Slug = Utility.ToSlug(showName);
|
show.Slug = Utility.ToSlug(showName);
|
||||||
show.Title ??= showName;
|
show.Title ??= showName;
|
||||||
show.IsMovie = isMovie;
|
show.IsMovie = isMovie;
|
||||||
await _thumbnailsManager.Validate(show);
|
await _thumbnailsManager.Validate(show);
|
||||||
return show;
|
return show;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Season> GetSeason(Show show, long seasonNumber, Library library)
|
public async Task<Season> GetSeason(Show show, long seasonNumber, Library library)
|
||||||
{
|
{
|
||||||
Season season = await GetMetadata(provider => provider.GetSeason(show, seasonNumber), library, $"the season {seasonNumber} of {show.Title}");
|
Season season = await GetMetadata(provider => provider.GetSeason(show, seasonNumber), library, $"the season {seasonNumber} of {show.Title}");
|
||||||
season.ShowID = show.ID;
|
season.ShowID = show.ID;
|
||||||
season.SeasonNumber = season.SeasonNumber == -1 ? seasonNumber : season.SeasonNumber;
|
season.SeasonNumber = season.SeasonNumber == -1 ? seasonNumber : season.SeasonNumber;
|
||||||
season.Title ??= $"Season {season.SeasonNumber}";
|
season.Title ??= $"Season {season.SeasonNumber}";
|
||||||
return season;
|
return season;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Episode> GetEpisode(Show show, string episodePath, long seasonNumber, long episodeNumber, long absoluteNumber, Library library)
|
public async Task<Episode> GetEpisode(Show show, string episodePath, long seasonNumber, long episodeNumber, long absoluteNumber, Library library)
|
||||||
{
|
{
|
||||||
Episode episode = await GetMetadata(provider => provider.GetEpisode(show, seasonNumber, episodeNumber, absoluteNumber), library, "an episode");
|
Episode episode = await GetMetadata(provider => provider.GetEpisode(show, seasonNumber, episodeNumber, absoluteNumber), library, "an episode");
|
||||||
episode.ShowID = show.ID;
|
episode.ShowID = show.ID;
|
||||||
episode.Path = episodePath;
|
episode.Path = episodePath;
|
||||||
episode.SeasonNumber = episode.SeasonNumber != -1 ? episode.SeasonNumber : seasonNumber;
|
episode.SeasonNumber = episode.SeasonNumber != -1 ? episode.SeasonNumber : seasonNumber;
|
||||||
episode.EpisodeNumber = episode.EpisodeNumber != -1 ? episode.EpisodeNumber : episodeNumber;
|
episode.EpisodeNumber = episode.EpisodeNumber != -1 ? episode.EpisodeNumber : episodeNumber;
|
||||||
episode.AbsoluteNumber = episode.AbsoluteNumber != -1 ? episode.AbsoluteNumber : absoluteNumber;
|
episode.AbsoluteNumber = episode.AbsoluteNumber != -1 ? episode.AbsoluteNumber : absoluteNumber;
|
||||||
await _thumbnailsManager.Validate(episode);
|
await _thumbnailsManager.Validate(episode);
|
||||||
return episode;
|
return episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<PeopleLink>> GetPeople(Show show, Library library)
|
public async Task<IEnumerable<PeopleLink>> GetPeople(Show show, Library library)
|
||||||
{
|
{
|
||||||
IEnumerable<PeopleLink> people = await GetMetadata(provider => provider.GetPeople(show), library, "unknown data");
|
IEnumerable<PeopleLink> people = await GetMetadata(provider => provider.GetPeople(show), library, "unknown data");
|
||||||
people = await _thumbnailsManager.Validate(people.ToList());
|
people = await _thumbnailsManager.Validate(people.ToList());
|
||||||
return people;
|
return people;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,110 +8,110 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class ThumbnailsManager : IThumbnailsManager
|
public class ThumbnailsManager : IThumbnailsManager
|
||||||
{
|
{
|
||||||
private readonly IConfiguration _config;
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
public ThumbnailsManager(IConfiguration configuration)
|
public ThumbnailsManager(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_config = configuration;
|
_config = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Show> Validate(Show show)
|
public async Task<Show> Validate(Show show)
|
||||||
{
|
{
|
||||||
if (show?.Path == null)
|
if (show?.Path == null)
|
||||||
return null;
|
return null;
|
||||||
string localThumb = Path.Combine(show.Path, "poster.jpg");
|
string localThumb = Path.Combine(show.Path, "poster.jpg");
|
||||||
string localLogo = Path.Combine(show.Path, "logo.png");
|
string localLogo = Path.Combine(show.Path, "logo.png");
|
||||||
string localBackdrop = Path.Combine(show.Path, "backdrop.jpg");
|
string localBackdrop = Path.Combine(show.Path, "backdrop.jpg");
|
||||||
|
|
||||||
|
|
||||||
if (show.ImgPrimary != null && !File.Exists(localThumb))
|
if (show.ImgPrimary != null && !File.Exists(localThumb))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using WebClient client = new WebClient();
|
using WebClient client = new WebClient();
|
||||||
await client.DownloadFileTaskAsync(new Uri(show.ImgPrimary), localThumb);
|
await client.DownloadFileTaskAsync(new Uri(show.ImgPrimary), localThumb);
|
||||||
}
|
}
|
||||||
catch (WebException exception)
|
catch (WebException exception)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"\tThe poster of {show.Title} could not be downloaded.\n\tError: {exception.Message}. ");
|
Console.Error.WriteLine($"\tThe poster of {show.Title} could not be downloaded.\n\tError: {exception.Message}. ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show.ImgLogo != null && !File.Exists(localLogo))
|
if (show.ImgLogo != null && !File.Exists(localLogo))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using WebClient client = new WebClient();
|
using WebClient client = new WebClient();
|
||||||
await client.DownloadFileTaskAsync(new Uri(show.ImgLogo), localLogo);
|
await client.DownloadFileTaskAsync(new Uri(show.ImgLogo), localLogo);
|
||||||
}
|
}
|
||||||
catch (WebException exception)
|
catch (WebException exception)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"\tThe logo of {show.Title} could not be downloaded.\n\tError: {exception.Message}. ");
|
Console.Error.WriteLine($"\tThe logo of {show.Title} could not be downloaded.\n\tError: {exception.Message}. ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show.ImgBackdrop != null && !File.Exists(localBackdrop))
|
if (show.ImgBackdrop != null && !File.Exists(localBackdrop))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using WebClient client = new WebClient();
|
using WebClient client = new WebClient();
|
||||||
await client.DownloadFileTaskAsync(new Uri(show.ImgBackdrop), localBackdrop);
|
await client.DownloadFileTaskAsync(new Uri(show.ImgBackdrop), localBackdrop);
|
||||||
}
|
}
|
||||||
catch (WebException exception)
|
catch (WebException exception)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"\tThe backdrop of {show.Title} could not be downloaded.\n\tError: {exception.Message}. ");
|
Console.Error.WriteLine($"\tThe backdrop of {show.Title} could not be downloaded.\n\tError: {exception.Message}. ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return show;
|
return show;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<PeopleLink>> Validate(List<PeopleLink> people)
|
public async Task<IEnumerable<PeopleLink>> Validate(List<PeopleLink> people)
|
||||||
{
|
{
|
||||||
if (people == null)
|
if (people == null)
|
||||||
return null;
|
return null;
|
||||||
foreach (PeopleLink peop in people)
|
foreach (PeopleLink peop in people)
|
||||||
{
|
{
|
||||||
string root = _config.GetValue<string>("peoplePath");
|
string root = _config.GetValue<string>("peoplePath");
|
||||||
Directory.CreateDirectory(root);
|
Directory.CreateDirectory(root);
|
||||||
|
|
||||||
string localThumb = root + "/" + peop.People.Slug + ".jpg";
|
string localThumb = root + "/" + peop.People.Slug + ".jpg";
|
||||||
if (peop.People.ImgPrimary == null || File.Exists(localThumb))
|
if (peop.People.ImgPrimary == null || File.Exists(localThumb))
|
||||||
continue;
|
continue;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using WebClient client = new WebClient();
|
using WebClient client = new WebClient();
|
||||||
await client.DownloadFileTaskAsync(new Uri(peop.People.ImgPrimary), localThumb);
|
await client.DownloadFileTaskAsync(new Uri(peop.People.ImgPrimary), localThumb);
|
||||||
}
|
}
|
||||||
catch (WebException exception)
|
catch (WebException exception)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"\tThe profile picture of {peop.People.Name} could not be downloaded.\n\tError: {exception.Message}. ");
|
Console.Error.WriteLine($"\tThe profile picture of {peop.People.Name} could not be downloaded.\n\tError: {exception.Message}. ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return people;
|
return people;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Episode> Validate(Episode episode)
|
public async Task<Episode> Validate(Episode episode)
|
||||||
{
|
{
|
||||||
if (episode == null || episode.Path == null)
|
if (episode == null || episode.Path == null)
|
||||||
return null;
|
return null;
|
||||||
string localThumb = Path.ChangeExtension(episode.Path, "jpg");
|
string localThumb = Path.ChangeExtension(episode.Path, "jpg");
|
||||||
if (episode.ImgPrimary == null || File.Exists(localThumb))
|
if (episode.ImgPrimary == null || File.Exists(localThumb))
|
||||||
return episode;
|
return episode;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using WebClient client = new WebClient();
|
using WebClient client = new WebClient();
|
||||||
await client.DownloadFileTaskAsync(new Uri(episode.ImgPrimary), localThumb);
|
await client.DownloadFileTaskAsync(new Uri(episode.ImgPrimary), localThumb);
|
||||||
}
|
}
|
||||||
catch (WebException exception)
|
catch (WebException exception)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"\tThe thumbnail of {episode.Show.Title} s{episode.SeasonNumber}e{episode.EpisodeNumber} could not be downloaded.\n\tError: {exception.Message}. ");
|
Console.Error.WriteLine($"\tThe thumbnail of {episode.Show.Title} s{episode.SeasonNumber}e{episode.EpisodeNumber} could not be downloaded.\n\tError: {exception.Message}. ");
|
||||||
}
|
}
|
||||||
|
|
||||||
return episode;
|
return episode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,97 +13,97 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
public class BadTranscoderException : Exception {}
|
public class BadTranscoderException : Exception {}
|
||||||
|
|
||||||
public class Transcoder : ITranscoder
|
public class Transcoder : ITranscoder
|
||||||
{
|
{
|
||||||
private readonly string _transmuxPath;
|
private readonly string _transmuxPath;
|
||||||
private readonly string _transcodePath;
|
private readonly string _transcodePath;
|
||||||
|
|
||||||
public Transcoder(IConfiguration config)
|
public Transcoder(IConfiguration config)
|
||||||
{
|
{
|
||||||
_transmuxPath = config.GetValue<string>("transmuxTempPath");
|
_transmuxPath = config.GetValue<string>("transmuxTempPath");
|
||||||
_transcodePath = config.GetValue<string>("transcodeTempPath");
|
_transcodePath = config.GetValue<string>("transcodeTempPath");
|
||||||
|
|
||||||
if (TranscoderAPI.init() != Marshal.SizeOf<Models.Watch.Stream>())
|
if (TranscoderAPI.init() != Marshal.SizeOf<Models.Watch.Stream>())
|
||||||
throw new BadTranscoderException();
|
throw new BadTranscoderException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Track[]> GetTrackInfo(string path)
|
public async Task<Track[]> GetTrackInfo(string path)
|
||||||
{
|
{
|
||||||
return await Task.Run(() =>
|
return await Task.Run(() =>
|
||||||
{
|
{
|
||||||
TranscoderAPI.GetTrackInfo(path, out Track[] tracks);
|
TranscoderAPI.GetTrackInfo(path, out Track[] tracks);
|
||||||
return tracks;
|
return tracks;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Track[]> ExtractSubtitles(string path)
|
public async Task<Track[]> ExtractSubtitles(string path)
|
||||||
{
|
{
|
||||||
string output = Path.Combine(Path.GetDirectoryName(path), "Subtitles");
|
string output = Path.Combine(Path.GetDirectoryName(path), "Subtitles");
|
||||||
Directory.CreateDirectory(output);
|
Directory.CreateDirectory(output);
|
||||||
return await Task.Run(() =>
|
return await Task.Run(() =>
|
||||||
{
|
{
|
||||||
TranscoderAPI.ExtractSubtitles(path, output, out Track[] tracks);
|
TranscoderAPI.ExtractSubtitles(path, output, out Track[] tracks);
|
||||||
return tracks;
|
return tracks;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> Transmux(WatchItem episode)
|
public async Task<string> Transmux(WatchItem episode)
|
||||||
{
|
{
|
||||||
string folder = Path.Combine(_transmuxPath, episode.Link);
|
string folder = Path.Combine(_transmuxPath, episode.Link);
|
||||||
string manifest = Path.Combine(folder, episode.Link + ".m3u8");
|
string manifest = Path.Combine(folder, episode.Link + ".m3u8");
|
||||||
float playableDuration = 0;
|
float playableDuration = 0;
|
||||||
bool transmuxFailed = false;
|
bool transmuxFailed = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(folder);
|
Directory.CreateDirectory(folder);
|
||||||
Debug.WriteLine("&Transmuxing " + episode.Link + " at " + episode.Path + ", outputPath: " + folder);
|
Debug.WriteLine("&Transmuxing " + episode.Link + " at " + episode.Path + ", outputPath: " + folder);
|
||||||
|
|
||||||
if (File.Exists(manifest))
|
if (File.Exists(manifest))
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
Console.Error.WriteLine($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
transmuxFailed = TranscoderAPI.transmux(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0;
|
transmuxFailed = TranscoderAPI.transmux(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0;
|
||||||
});
|
});
|
||||||
while (playableDuration < 10 || (!File.Exists(manifest) && !transmuxFailed))
|
while (playableDuration < 10 || (!File.Exists(manifest) && !transmuxFailed))
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
return transmuxFailed ? null : manifest;
|
return transmuxFailed ? null : manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> Transcode(WatchItem episode)
|
public async Task<string> Transcode(WatchItem episode)
|
||||||
{
|
{
|
||||||
string folder = Path.Combine(_transcodePath, episode.Link);
|
string folder = Path.Combine(_transcodePath, episode.Link);
|
||||||
string manifest = Path.Combine(folder, episode.Link + ".m3u8");
|
string manifest = Path.Combine(folder, episode.Link + ".m3u8");
|
||||||
float playableDuration = 0;
|
float playableDuration = 0;
|
||||||
bool transmuxFailed = false;
|
bool transmuxFailed = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(folder);
|
Directory.CreateDirectory(folder);
|
||||||
Debug.WriteLine("&Transcoding " + episode.Link + " at " + episode.Path + ", outputPath: " + folder);
|
Debug.WriteLine("&Transcoding " + episode.Link + " at " + episode.Path + ", outputPath: " + folder);
|
||||||
|
|
||||||
if (File.Exists(manifest))
|
if (File.Exists(manifest))
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
Console.Error.WriteLine($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
transmuxFailed = TranscoderAPI.transcode(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0;
|
transmuxFailed = TranscoderAPI.transcode(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0;
|
||||||
});
|
});
|
||||||
while (playableDuration < 10 || (!File.Exists(manifest) && !transmuxFailed))
|
while (playableDuration < 10 || (!File.Exists(manifest) && !transmuxFailed))
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
return transmuxFailed ? null : manifest;
|
return transmuxFailed ? null : manifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,88 +8,88 @@ using Kyoo.Models.Watch;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers.TranscoderLink
|
namespace Kyoo.Controllers.TranscoderLink
|
||||||
{
|
{
|
||||||
public static class TranscoderAPI
|
public static class TranscoderAPI
|
||||||
{
|
{
|
||||||
private const string TranscoderPath = "libtranscoder.so";
|
private const string TranscoderPath = "libtranscoder.so";
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int init();
|
public static extern int init();
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int transmux(string path, string out_path, out float playableDuration);
|
public static extern int transmux(string path, string out_path, out float playableDuration);
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int transcode(string path, string out_path, out float playableDuration);
|
public static extern int transcode(string path, string out_path, out float playableDuration);
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern IntPtr get_track_info(string path, out int array_length, out int track_count);
|
private static extern IntPtr get_track_info(string path, out int array_length, out int track_count);
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern IntPtr extract_subtitles(string path, string out_path, out int array_length, out int track_count);
|
private static extern IntPtr extract_subtitles(string path, string out_path, out int array_length, out int track_count);
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void free_streams(IntPtr stream_ptr);
|
private static extern void free_streams(IntPtr stream_ptr);
|
||||||
|
|
||||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void free(IntPtr ptr);
|
private static extern void free(IntPtr ptr);
|
||||||
|
|
||||||
|
|
||||||
public static void GetTrackInfo(string path, out Track[] tracks)
|
public static void GetTrackInfo(string path, out Track[] tracks)
|
||||||
{
|
{
|
||||||
int size = Marshal.SizeOf<Stream>();
|
int size = Marshal.SizeOf<Stream>();
|
||||||
IntPtr ptr = get_track_info(path, out int arrayLength, out int trackCount);
|
IntPtr ptr = get_track_info(path, out int arrayLength, out int trackCount);
|
||||||
IntPtr streamsPtr = ptr;
|
IntPtr streamsPtr = ptr;
|
||||||
|
|
||||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
tracks = new Track[trackCount];
|
tracks = new Track[trackCount];
|
||||||
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < arrayLength; i++)
|
for (int i = 0; i < arrayLength; i++)
|
||||||
{
|
{
|
||||||
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
||||||
if (stream.Type != StreamType.Unknow)
|
if (stream.Type != StreamType.Unknow)
|
||||||
{
|
{
|
||||||
tracks[j] = new Track(stream);
|
tracks[j] = new Track(stream);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
streamsPtr += size;
|
streamsPtr += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tracks = new Track[0];
|
tracks = new Track[0];
|
||||||
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
Console.WriteLine($"\t{tracks.Length} tracks got at: {path}");
|
Console.WriteLine($"\t{tracks.Length} tracks got at: {path}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ExtractSubtitles(string path, string outPath, out Track[] tracks)
|
public static void ExtractSubtitles(string path, string outPath, out Track[] tracks)
|
||||||
{
|
{
|
||||||
int size = Marshal.SizeOf<Stream>();
|
int size = Marshal.SizeOf<Stream>();
|
||||||
IntPtr ptr = extract_subtitles(path, outPath, out int arrayLength, out int trackCount);
|
IntPtr ptr = extract_subtitles(path, outPath, out int arrayLength, out int trackCount);
|
||||||
IntPtr streamsPtr = ptr;
|
IntPtr streamsPtr = ptr;
|
||||||
|
|
||||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
tracks = new Track[trackCount];
|
tracks = new Track[trackCount];
|
||||||
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < arrayLength; i++)
|
for (int i = 0; i < arrayLength; i++)
|
||||||
{
|
{
|
||||||
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
||||||
if (stream.Type != StreamType.Unknow)
|
if (stream.Type != StreamType.Unknow)
|
||||||
{
|
{
|
||||||
tracks[j] = new Track(stream);
|
tracks[j] = new Track(stream);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
streamsPtr += size;
|
streamsPtr += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tracks = new Track[0];
|
tracks = new Track[0];
|
||||||
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
Console.WriteLine($"\t{tracks.Count(x => x.Type == StreamType.Subtitle)} subtitles got at: {path}");
|
Console.WriteLine($"\t{tracks.Count(x => x.Type == StreamType.Subtitle)} subtitles got at: {path}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,65 +7,65 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
public class DatabaseContext : DbContext
|
public class DatabaseContext : DbContext
|
||||||
{
|
{
|
||||||
public DatabaseContext(DbContextOptions options) : base(options) { }
|
public DatabaseContext(DbContextOptions options) : base(options) { }
|
||||||
|
|
||||||
public DbSet<Library> Libraries { get; set; }
|
public DbSet<Library> Libraries { get; set; }
|
||||||
public DbSet<Collection> Collections { get; set; }
|
public DbSet<Collection> Collections { get; set; }
|
||||||
public DbSet<Show> Shows { get; set; }
|
public DbSet<Show> Shows { get; set; }
|
||||||
public DbSet<Season> Seasons { get; set; }
|
public DbSet<Season> Seasons { get; set; }
|
||||||
public DbSet<Episode> Episodes { get; set; }
|
public DbSet<Episode> Episodes { get; set; }
|
||||||
public DbSet<Track> Tracks { get; set; }
|
public DbSet<Track> Tracks { get; set; }
|
||||||
public DbSet<Genre> Genres { get; set; }
|
public DbSet<Genre> Genres { get; set; }
|
||||||
public DbSet<People> Peoples { get; set; }
|
public DbSet<People> Peoples { get; set; }
|
||||||
public DbSet<Studio> Studios { get; set; }
|
public DbSet<Studio> Studios { get; set; }
|
||||||
|
|
||||||
public DbSet<LibraryLink> LibraryLinks { get; set; }
|
public DbSet<LibraryLink> LibraryLinks { get; set; }
|
||||||
public DbSet<CollectionLink> CollectionLinks { get; set; }
|
public DbSet<CollectionLink> CollectionLinks { get; set; }
|
||||||
public DbSet<PeopleLink> PeopleLinks { get; set; }
|
public DbSet<PeopleLink> PeopleLinks { get; set; }
|
||||||
|
|
||||||
// This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this.
|
// This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this.
|
||||||
public DbSet<GenreLink> GenreLinks { get; set; }
|
public DbSet<GenreLink> GenreLinks { get; set; }
|
||||||
|
|
||||||
|
|
||||||
private ValueConverter<string[], string> stringArrayConverter = new ValueConverter<string[], string>(
|
private ValueConverter<string[], string> stringArrayConverter = new ValueConverter<string[], string>(
|
||||||
arr => string.Join("|", arr),
|
arr => string.Join("|", arr),
|
||||||
str => str.Split("|", StringSplitOptions.None));
|
str => str.Split("|", StringSplitOptions.None));
|
||||||
|
|
||||||
private ValueComparer<string[]> stringArrayComparer = new ValueComparer<string[]>(
|
private ValueComparer<string[]> stringArrayComparer = new ValueComparer<string[]>(
|
||||||
(l1, l2) => l1.SequenceEqual(l2),
|
(l1, l2) => l1.SequenceEqual(l2),
|
||||||
arr => arr.Aggregate(0, (i, s) => s.GetHashCode()));
|
arr => arr.Aggregate(0, (i, s) => s.GetHashCode()));
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity<Library>().Property(e => e.Paths).HasConversion(stringArrayConverter).Metadata.SetValueComparer(stringArrayComparer);
|
modelBuilder.Entity<Library>().Property(e => e.Paths).HasConversion(stringArrayConverter).Metadata.SetValueComparer(stringArrayComparer);
|
||||||
modelBuilder.Entity<Library>().Property(e => e.Providers).HasConversion(stringArrayConverter).Metadata.SetValueComparer(stringArrayComparer);
|
modelBuilder.Entity<Library>().Property(e => e.Providers).HasConversion(stringArrayConverter).Metadata.SetValueComparer(stringArrayComparer);
|
||||||
modelBuilder.Entity<Show>().Property(e => e.Aliases).HasConversion(stringArrayConverter).Metadata.SetValueComparer(stringArrayComparer);
|
modelBuilder.Entity<Show>().Property(e => e.Aliases).HasConversion(stringArrayConverter).Metadata.SetValueComparer(stringArrayComparer);
|
||||||
|
|
||||||
modelBuilder.Entity<Track>()
|
modelBuilder.Entity<Track>()
|
||||||
.Property(t => t.IsDefault)
|
.Property(t => t.IsDefault)
|
||||||
.ValueGeneratedNever();
|
.ValueGeneratedNever();
|
||||||
|
|
||||||
modelBuilder.Entity<Track>()
|
modelBuilder.Entity<Track>()
|
||||||
.Property(t => t.IsForced)
|
.Property(t => t.IsForced)
|
||||||
.ValueGeneratedNever();
|
.ValueGeneratedNever();
|
||||||
|
|
||||||
modelBuilder.Entity<People>()
|
modelBuilder.Entity<People>()
|
||||||
.HasKey(x => x.Slug);
|
.HasKey(x => x.Slug);
|
||||||
|
|
||||||
modelBuilder.Entity<GenreLink>()
|
modelBuilder.Entity<GenreLink>()
|
||||||
.HasKey(x => new {x.ShowID, x.GenreID});
|
.HasKey(x => new {x.ShowID, x.GenreID});
|
||||||
|
|
||||||
modelBuilder.Entity<Show>()
|
modelBuilder.Entity<Show>()
|
||||||
.Ignore(x => x.Genres);
|
.Ignore(x => x.Genres);
|
||||||
|
|
||||||
// modelBuilder.Entity<Genre>()
|
// modelBuilder.Entity<Genre>()
|
||||||
// .Ignore(x => x.Shows);
|
// .Ignore(x => x.Shows);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DbSetExtension
|
public static class DbSetExtension
|
||||||
|
@ -4,17 +4,17 @@ using Kyoo.Controllers;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class AdminController : ControllerBase
|
public class AdminController : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("scan")]
|
[HttpGet("scan")]
|
||||||
public IActionResult ScanLibrary([FromServices] ICrawler crawler)
|
public IActionResult ScanLibrary([FromServices] ICrawler crawler)
|
||||||
{
|
{
|
||||||
// The crawler is destroyed before the completion of this task.
|
// The crawler is destroyed before the completion of this task.
|
||||||
// TODO implement an hosted service that can queue tasks from the controller.
|
// TODO implement an hosted service that can queue tasks from the controller.
|
||||||
crawler.StartAsync(new CancellationToken());
|
crawler.StartAsync(new CancellationToken());
|
||||||
return Ok("Scanning");
|
return Ok("Scanning");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
public class AuthentificationAPI : Controller
|
public class AuthentificationAPI : Controller
|
||||||
{
|
{
|
||||||
// [Authorize, HttpGet("/connect/authorize")]
|
// [Authorize, HttpGet("/connect/authorize")]
|
||||||
// public async Task<IActionResult> Authorize(CancellationToken token)
|
// public async Task<IActionResult> Authorize(CancellationToken token)
|
||||||
// {
|
// {
|
||||||
// //HttpContext.GetOpenIdConnectResponse()
|
// //HttpContext.GetOpenIdConnectResponse()
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,26 +5,26 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class CollectionController : ControllerBase
|
public class CollectionController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public CollectionController(ILibraryManager libraryManager)
|
public CollectionController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{collectionSlug}")]
|
[HttpGet("{collectionSlug}")]
|
||||||
public ActionResult<Collection> GetShows(string collectionSlug)
|
public ActionResult<Collection> GetShows(string collectionSlug)
|
||||||
{
|
{
|
||||||
Collection collection = _libraryManager.GetCollection(collectionSlug);
|
Collection collection = _libraryManager.GetCollection(collectionSlug);
|
||||||
|
|
||||||
if (collection == null)
|
if (collection == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,38 +6,38 @@ using Kyoo.Controllers;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class EpisodesController : ControllerBase
|
public class EpisodesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public EpisodesController(ILibraryManager libraryManager)
|
public EpisodesController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{showSlug}/season/{seasonNumber}")]
|
[HttpGet("{showSlug}/season/{seasonNumber}")]
|
||||||
public ActionResult<IEnumerable<Episode>> GetEpisodesForSeason(string showSlug, long seasonNumber)
|
public ActionResult<IEnumerable<Episode>> GetEpisodesForSeason(string showSlug, long seasonNumber)
|
||||||
{
|
{
|
||||||
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug, seasonNumber);
|
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug, seasonNumber);
|
||||||
|
|
||||||
if(episodes == null)
|
if(episodes == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return episodes.ToList();
|
return episodes.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")]
|
[HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")]
|
||||||
[JsonDetailed]
|
[JsonDetailed]
|
||||||
public ActionResult<Episode> GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
|
public ActionResult<Episode> GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||||
|
|
||||||
if (episode == null)
|
if (episode == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return episode;
|
return episode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,32 +6,32 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/libraries")]
|
[Route("api/libraries")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class LibrariesController : ControllerBase
|
public class LibrariesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public LibrariesController(ILibraryManager libraryManager)
|
public LibrariesController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IEnumerable<Library> GetLibraries()
|
public IEnumerable<Library> GetLibraries()
|
||||||
{
|
{
|
||||||
return _libraryManager.GetLibraries();
|
return _libraryManager.GetLibraries();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{librarySlug}")]
|
[HttpGet("{librarySlug}")]
|
||||||
public ActionResult<IEnumerable<Show>> GetShows(string librarySlug)
|
public ActionResult<IEnumerable<Show>> GetShows(string librarySlug)
|
||||||
{
|
{
|
||||||
Library library = _libraryManager.GetLibrary(librarySlug);
|
Library library = _libraryManager.GetLibrary(librarySlug);
|
||||||
|
|
||||||
if (library == null)
|
if (library == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return _libraryManager.GetShowsInLibrary(library.ID).ToList();
|
return _libraryManager.GetShowsInLibrary(library.ID).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,30 +4,30 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class PeopleController : ControllerBase
|
public class PeopleController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public PeopleController(ILibraryManager libraryManager)
|
public PeopleController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{peopleSlug}")]
|
[HttpGet("{peopleSlug}")]
|
||||||
public ActionResult<Collection> GetPeople(string peopleSlug)
|
public ActionResult<Collection> GetPeople(string peopleSlug)
|
||||||
{
|
{
|
||||||
People people = _libraryManager.GetPeopleBySlug(peopleSlug);
|
People people = _libraryManager.GetPeopleBySlug(peopleSlug);
|
||||||
|
|
||||||
if (people == null)
|
if (people == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
Collection collection = new Collection(people.Slug, people.Name, null, null)
|
Collection collection = new Collection(people.Slug, people.Name, null, null)
|
||||||
{
|
{
|
||||||
Shows = _libraryManager.GetShowsByPeople(people.Slug),
|
Shows = _libraryManager.GetShowsByPeople(people.Slug),
|
||||||
Poster = "peopleimg/" + people.Slug
|
Poster = "peopleimg/" + people.Slug
|
||||||
};
|
};
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,30 +4,30 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class SearchController : ControllerBase
|
public class SearchController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public SearchController(ILibraryManager libraryManager)
|
public SearchController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{query}")]
|
[HttpGet("{query}")]
|
||||||
public ActionResult<SearchResult> Search(string query)
|
public ActionResult<SearchResult> Search(string query)
|
||||||
{
|
{
|
||||||
SearchResult result = new SearchResult
|
SearchResult result = new SearchResult
|
||||||
{
|
{
|
||||||
Query = query,
|
Query = query,
|
||||||
Shows = _libraryManager.GetShows(query),
|
Shows = _libraryManager.GetShows(query),
|
||||||
Episodes = _libraryManager.SearchEpisodes(query),
|
Episodes = _libraryManager.SearchEpisodes(query),
|
||||||
People = _libraryManager.SearchPeople(query),
|
People = _libraryManager.SearchPeople(query),
|
||||||
Genres = _libraryManager.SearchGenres(query),
|
Genres = _libraryManager.SearchGenres(query),
|
||||||
Studios = _libraryManager.SearchStudios(query)
|
Studios = _libraryManager.SearchStudios(query)
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,34 +5,34 @@ using Kyoo.Controllers;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/shows")]
|
[Route("api/shows")]
|
||||||
[Route("api/show")]
|
[Route("api/show")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class ShowsController : ControllerBase
|
public class ShowsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public ShowsController(ILibraryManager libraryManager)
|
public ShowsController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IEnumerable<Show> GetShows()
|
public IEnumerable<Show> GetShows()
|
||||||
{
|
{
|
||||||
return _libraryManager.GetShows();
|
return _libraryManager.GetShows();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}")]
|
[HttpGet("{slug}")]
|
||||||
[JsonDetailed]
|
[JsonDetailed]
|
||||||
public ActionResult<Show> GetShow(string slug)
|
public ActionResult<Show> GetShow(string slug)
|
||||||
{
|
{
|
||||||
Show show = _libraryManager.GetShowBySlug(slug);
|
Show show = _libraryManager.GetShowBySlug(slug);
|
||||||
|
|
||||||
if (show == null)
|
if (show == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return show;
|
return show;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,171 +7,171 @@ using Kyoo.Controllers;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class SubtitleController : ControllerBase
|
public class SubtitleController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ITranscoder _transcoder;
|
private readonly ITranscoder _transcoder;
|
||||||
|
|
||||||
public SubtitleController(ILibraryManager libraryManager, ITranscoder transcoder)
|
public SubtitleController(ILibraryManager libraryManager, ITranscoder transcoder)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_transcoder = transcoder;
|
_transcoder = transcoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")]
|
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")]
|
||||||
public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string extension)
|
public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string extension)
|
||||||
{
|
{
|
||||||
string languageTag = identifier.Substring(0, 3);
|
string languageTag = identifier.Substring(0, 3);
|
||||||
bool forced = identifier.Length > 3 && identifier.Substring(4) == "forced";
|
bool forced = identifier.Length > 3 && identifier.Substring(4) == "forced";
|
||||||
|
|
||||||
Track subtitle = _libraryManager.GetSubtitle(showSlug, seasonNumber, episodeNumber, languageTag, forced);
|
Track subtitle = _libraryManager.GetSubtitle(showSlug, seasonNumber, episodeNumber, languageTag, forced);
|
||||||
|
|
||||||
if (subtitle == null)
|
if (subtitle == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
|
|
||||||
if (subtitle.Codec == "subrip" && extension == "vtt") //The request wants a WebVTT from a Subrip subtitle, convert it on the fly and send it.
|
if (subtitle.Codec == "subrip" && extension == "vtt") //The request wants a WebVTT from a Subrip subtitle, convert it on the fly and send it.
|
||||||
{
|
{
|
||||||
return new ConvertSubripToVtt(subtitle.Path);
|
return new ConvertSubripToVtt(subtitle.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
string mime;
|
string mime;
|
||||||
if (subtitle.Codec == "ass")
|
if (subtitle.Codec == "ass")
|
||||||
mime = "text/x-ssa";
|
mime = "text/x-ssa";
|
||||||
else
|
else
|
||||||
mime = "application/x-subrip";
|
mime = "application/x-subrip";
|
||||||
|
|
||||||
//Should use appropriate mime type here
|
//Should use appropriate mime type here
|
||||||
return PhysicalFile(subtitle.Path, mime);
|
return PhysicalFile(subtitle.Path, mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
|
public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||||
_libraryManager.ClearSubtitles(episode.ID);
|
_libraryManager.ClearSubtitles(episode.ID);
|
||||||
|
|
||||||
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
||||||
foreach (Track track in tracks)
|
foreach (Track track in tracks)
|
||||||
{
|
{
|
||||||
track.EpisodeID = episode.ID;
|
track.EpisodeID = episode.ID;
|
||||||
_libraryManager.RegisterTrack(track);
|
_libraryManager.RegisterTrack(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Done. " + tracks.Length + " track(s) extracted.";
|
return "Done. " + tracks.Length + " track(s) extracted.";
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("extract/{showSlug}")]
|
[HttpGet("extract/{showSlug}")]
|
||||||
public async Task<string> ExtractSubtitle(string showSlug)
|
public async Task<string> ExtractSubtitle(string showSlug)
|
||||||
{
|
{
|
||||||
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug);
|
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug);
|
||||||
foreach (Episode episode in episodes)
|
foreach (Episode episode in episodes)
|
||||||
{
|
{
|
||||||
_libraryManager.ClearSubtitles(episode.ID);
|
_libraryManager.ClearSubtitles(episode.ID);
|
||||||
|
|
||||||
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
||||||
foreach (Track track in tracks)
|
foreach (Track track in tracks)
|
||||||
{
|
{
|
||||||
track.EpisodeID = episode.ID;
|
track.EpisodeID = episode.ID;
|
||||||
_libraryManager.RegisterTrack(track);
|
_libraryManager.RegisterTrack(track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Done.";
|
return "Done.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ConvertSubripToVtt : IActionResult
|
public class ConvertSubripToVtt : IActionResult
|
||||||
{
|
{
|
||||||
private readonly string _path;
|
private readonly string _path;
|
||||||
|
|
||||||
public ConvertSubripToVtt(string subtitlePath)
|
public ConvertSubripToVtt(string subtitlePath)
|
||||||
{
|
{
|
||||||
_path = subtitlePath;
|
_path = subtitlePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExecuteResultAsync(ActionContext context)
|
public async Task ExecuteResultAsync(ActionContext context)
|
||||||
{
|
{
|
||||||
string line;
|
string line;
|
||||||
List<string> lines = new List<string>();
|
List<string> lines = new List<string>();
|
||||||
|
|
||||||
context.HttpContext.Response.StatusCode = 200;
|
context.HttpContext.Response.StatusCode = 200;
|
||||||
context.HttpContext.Response.Headers.Add("Content-Type", "text/vtt");
|
context.HttpContext.Response.Headers.Add("Content-Type", "text/vtt");
|
||||||
|
|
||||||
await using (StreamWriter writer = new StreamWriter(context.HttpContext.Response.Body))
|
await using (StreamWriter writer = new StreamWriter(context.HttpContext.Response.Body))
|
||||||
{
|
{
|
||||||
await writer.WriteLineAsync("WEBVTT");
|
await writer.WriteLineAsync("WEBVTT");
|
||||||
await writer.WriteLineAsync("");
|
await writer.WriteLineAsync("");
|
||||||
await writer.WriteLineAsync("");
|
await writer.WriteLineAsync("");
|
||||||
|
|
||||||
using (StreamReader reader = new StreamReader(_path))
|
using (StreamReader reader = new StreamReader(_path))
|
||||||
{
|
{
|
||||||
while ((line = await reader.ReadLineAsync()) != null)
|
while ((line = await reader.ReadLineAsync()) != null)
|
||||||
{
|
{
|
||||||
if (line == "")
|
if (line == "")
|
||||||
{
|
{
|
||||||
lines.Add("");
|
lines.Add("");
|
||||||
List<string> processedBlock = ConvertBlock(lines);
|
List<string> processedBlock = ConvertBlock(lines);
|
||||||
for (int i = 0; i < processedBlock.Count; i++)
|
for (int i = 0; i < processedBlock.Count; i++)
|
||||||
await writer.WriteLineAsync(processedBlock[i]);
|
await writer.WriteLineAsync(processedBlock[i]);
|
||||||
lines.Clear();
|
lines.Clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lines.Add(line);
|
lines.Add(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.HttpContext.Response.Body.FlushAsync();
|
await context.HttpContext.Response.Body.FlushAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> ConvertBlock(List<string> lines)
|
private static List<string> ConvertBlock(List<string> lines)
|
||||||
{
|
{
|
||||||
lines[1] = lines[1].Replace(',', '.');
|
lines[1] = lines[1].Replace(',', '.');
|
||||||
if (lines[2].Length > 5)
|
if (lines[2].Length > 5)
|
||||||
{
|
{
|
||||||
switch (lines[2].Substring(0, 6))
|
switch (lines[2].Substring(0, 6))
|
||||||
{
|
{
|
||||||
case "{\\an1}":
|
case "{\\an1}":
|
||||||
lines[1] += " line:93% position:15%";
|
lines[1] += " line:93% position:15%";
|
||||||
break;
|
break;
|
||||||
case "{\\an2}":
|
case "{\\an2}":
|
||||||
lines[1] += " line:93%";
|
lines[1] += " line:93%";
|
||||||
break;
|
break;
|
||||||
case "{\\an3}":
|
case "{\\an3}":
|
||||||
lines[1] += " line:93% position:85%";
|
lines[1] += " line:93% position:85%";
|
||||||
break;
|
break;
|
||||||
case "{\\an4}":
|
case "{\\an4}":
|
||||||
lines[1] += " line:50% position:15%";
|
lines[1] += " line:50% position:15%";
|
||||||
break;
|
break;
|
||||||
case "{\\an5}":
|
case "{\\an5}":
|
||||||
lines[1] += " line:50%";
|
lines[1] += " line:50%";
|
||||||
break;
|
break;
|
||||||
case "{\\an6}":
|
case "{\\an6}":
|
||||||
lines[1] += " line:50% position:85%";
|
lines[1] += " line:50% position:85%";
|
||||||
break;
|
break;
|
||||||
case "{\\an7}":
|
case "{\\an7}":
|
||||||
lines[1] += " line:7% position:15%";
|
lines[1] += " line:7% position:15%";
|
||||||
break;
|
break;
|
||||||
case "{\\an8}":
|
case "{\\an8}":
|
||||||
lines[1] += " line:7%";
|
lines[1] += " line:7%";
|
||||||
break;
|
break;
|
||||||
case "{\\an9}":
|
case "{\\an9}":
|
||||||
lines[1] += " line:7% position:85%";
|
lines[1] += " line:7% position:85%";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lines[1] += " line:93%";
|
lines[1] += " line:93%";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lines[2].StartsWith("{\\an"))
|
if (lines[2].StartsWith("{\\an"))
|
||||||
lines[2] = lines[2].Substring(6);
|
lines[2] = lines[2].Substring(6);
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,82 +5,82 @@ using Kyoo.Controllers;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
public class ThumbnailController : ControllerBase
|
public class ThumbnailController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly string _peoplePath;
|
private readonly string _peoplePath;
|
||||||
|
|
||||||
|
|
||||||
public ThumbnailController(ILibraryManager libraryManager, IConfiguration config)
|
public ThumbnailController(ILibraryManager libraryManager, IConfiguration config)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_peoplePath = config.GetValue<string>("peoplePath");
|
_peoplePath = config.GetValue<string>("peoplePath");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("poster/{showSlug}")]
|
[HttpGet("poster/{showSlug}")]
|
||||||
public IActionResult GetShowThumb(string showSlug)
|
public IActionResult GetShowThumb(string showSlug)
|
||||||
{
|
{
|
||||||
string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
|
string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
string thumb = Path.Combine(path, "poster.jpg");
|
string thumb = Path.Combine(path, "poster.jpg");
|
||||||
|
|
||||||
if (System.IO.File.Exists(thumb))
|
if (System.IO.File.Exists(thumb))
|
||||||
return new PhysicalFileResult(thumb, "image/jpg");
|
return new PhysicalFileResult(thumb, "image/jpg");
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("logo/{showSlug}")]
|
[HttpGet("logo/{showSlug}")]
|
||||||
public IActionResult GetShowLogo(string showSlug)
|
public IActionResult GetShowLogo(string showSlug)
|
||||||
{
|
{
|
||||||
string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
|
string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
string thumb = Path.Combine(path, "logo.png");
|
string thumb = Path.Combine(path, "logo.png");
|
||||||
|
|
||||||
if (System.IO.File.Exists(thumb))
|
if (System.IO.File.Exists(thumb))
|
||||||
return new PhysicalFileResult(thumb, "image/jpg");
|
return new PhysicalFileResult(thumb, "image/jpg");
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("backdrop/{showSlug}")]
|
[HttpGet("backdrop/{showSlug}")]
|
||||||
public IActionResult GetShowBackdrop(string showSlug)
|
public IActionResult GetShowBackdrop(string showSlug)
|
||||||
{
|
{
|
||||||
string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
|
string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
string thumb = Path.Combine(path, "backdrop.jpg");
|
string thumb = Path.Combine(path, "backdrop.jpg");
|
||||||
|
|
||||||
if (System.IO.File.Exists(thumb))
|
if (System.IO.File.Exists(thumb))
|
||||||
return new PhysicalFileResult(thumb, "image/jpg");
|
return new PhysicalFileResult(thumb, "image/jpg");
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("peopleimg/{peopleSlug}")]
|
[HttpGet("peopleimg/{peopleSlug}")]
|
||||||
public IActionResult GetPeopleIcon(string peopleSlug)
|
public IActionResult GetPeopleIcon(string peopleSlug)
|
||||||
{
|
{
|
||||||
string thumbPath = Path.Combine(_peoplePath, peopleSlug + ".jpg");
|
string thumbPath = Path.Combine(_peoplePath, peopleSlug + ".jpg");
|
||||||
if (!System.IO.File.Exists(thumbPath))
|
if (!System.IO.File.Exists(thumbPath))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return new PhysicalFileResult(thumbPath, "image/jpg");
|
return new PhysicalFileResult(thumbPath, "image/jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public IActionResult GetEpisodeThumb(string showSlug, long seasonNumber, long episodeNumber)
|
public IActionResult GetEpisodeThumb(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
string path = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber)?.Path;
|
string path = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber)?.Path;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
string thumb = Path.ChangeExtension(path, "jpg");
|
string thumb = Path.ChangeExtension(path, "jpg");
|
||||||
|
|
||||||
if (System.IO.File.Exists(thumb))
|
if (System.IO.File.Exists(thumb))
|
||||||
return new PhysicalFileResult(thumb, "image/jpg");
|
return new PhysicalFileResult(thumb, "image/jpg");
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,64 +7,64 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class VideoController : ControllerBase
|
public class VideoController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ITranscoder _transcoder;
|
private readonly ITranscoder _transcoder;
|
||||||
private readonly string _transmuxPath;
|
private readonly string _transmuxPath;
|
||||||
|
|
||||||
public VideoController(ILibraryManager libraryManager, ITranscoder transcoder, IConfiguration config)
|
public VideoController(ILibraryManager libraryManager, ITranscoder transcoder, IConfiguration config)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_transcoder = transcoder;
|
_transcoder = transcoder;
|
||||||
_transmuxPath = config.GetValue<string>("transmuxTempPath");
|
_transmuxPath = config.GetValue<string>("transmuxTempPath");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public IActionResult Index(string showSlug, long seasonNumber, long episodeNumber)
|
public IActionResult Index(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||||
|
|
||||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||||
return PhysicalFile(episode.Path, "video/x-matroska", true);
|
return PhysicalFile(episode.Path, "video/x-matroska", true);
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||||
|
|
||||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = await _transcoder.Transmux(episode);
|
string path = await _transcoder.Transmux(episode);
|
||||||
if (path != null)
|
if (path != null)
|
||||||
return PhysicalFile(path, "application/x-mpegURL ", true);
|
return PhysicalFile(path, "application/x-mpegURL ", true);
|
||||||
return StatusCode(500);
|
return StatusCode(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("transmux/{episodeLink}/segment/{chunk}")]
|
[HttpGet("transmux/{episodeLink}/segment/{chunk}")]
|
||||||
public IActionResult GetTransmuxedChunk(string episodeLink, string chunk)
|
public IActionResult GetTransmuxedChunk(string episodeLink, string chunk)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(_transmuxPath, episodeLink);
|
string path = Path.Combine(_transmuxPath, episodeLink);
|
||||||
path = Path.Combine(path, "segments" + Path.DirectorySeparatorChar + chunk);
|
path = Path.Combine(path, "segments" + Path.DirectorySeparatorChar + chunk);
|
||||||
|
|
||||||
return PhysicalFile(path, "video/MP2T");
|
return PhysicalFile(path, "video/MP2T");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public async Task<IActionResult> Transcode(string showSlug, long seasonNumber, long episodeNumber)
|
public async Task<IActionResult> Transcode(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||||
|
|
||||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = await _transcoder.Transcode(episode);
|
string path = await _transcoder.Transcode(episode);
|
||||||
if (path != null)
|
if (path != null)
|
||||||
return PhysicalFile(path, "application/x-mpegURL ", true);
|
return PhysicalFile(path, "application/x-mpegURL ", true);
|
||||||
return StatusCode(500);
|
return StatusCode(500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,26 +4,26 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class WatchController : ControllerBase
|
public class WatchController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public WatchController(ILibraryManager libraryManager)
|
public WatchController(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public ActionResult<WatchItem> Index(string showSlug, long seasonNumber, long episodeNumber)
|
public ActionResult<WatchItem> Index(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
WatchItem item = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
WatchItem item = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||||
|
|
||||||
if(item == null)
|
if(item == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,18 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static async Task Main(string[] args)
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Running as: {Environment.UserName}");
|
Console.WriteLine($"Running as: {Environment.UserName}");
|
||||||
await CreateWebHostBuilder(args).Build().RunAsync();
|
await CreateWebHostBuilder(args).Build().RunAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseKestrel((config) => { config.AddServerHeader = false; })
|
.UseKestrel((config) => { config.AddServerHeader = false; })
|
||||||
.UseUrls("http://*:5000")
|
.UseUrls("http://*:5000")
|
||||||
.UseStartup<Startup>();
|
.UseStartup<Startup>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
146
Kyoo/Startup.cs
146
Kyoo/Startup.cs
@ -12,91 +12,91 @@ using Microsoft.Extensions.Hosting;
|
|||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
// In production, the Angular files will be served from this directory
|
// In production, the Angular files will be served from this directory
|
||||||
services.AddSpaStaticFiles(configuration =>
|
services.AddSpaStaticFiles(configuration =>
|
||||||
{
|
{
|
||||||
configuration.RootPath = "ClientApp/dist";
|
configuration.RootPath = "ClientApp/dist";
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddControllers().AddNewtonsoftJson();
|
services.AddControllers().AddNewtonsoftJson();
|
||||||
services.AddHttpClient();
|
services.AddHttpClient();
|
||||||
|
|
||||||
services.AddDbContext<DatabaseContext>(options => options.UseLazyLoadingProxies()
|
services.AddDbContext<DatabaseContext>(options => options.UseLazyLoadingProxies()
|
||||||
.UseSqlite(Configuration.GetConnectionString("Database")));
|
.UseSqlite(Configuration.GetConnectionString("Database")));
|
||||||
|
|
||||||
// services.AddIdentity<ApplicationUser, IdentityRole>()
|
// services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||||
// .AddEntityFrameworkStores()
|
// .AddEntityFrameworkStores()
|
||||||
// services.AddIdentityServer();
|
// services.AddIdentityServer();
|
||||||
|
|
||||||
services.AddScoped<ILibraryManager, LibraryManager>();
|
services.AddScoped<ILibraryManager, LibraryManager>();
|
||||||
services.AddScoped<ICrawler, Crawler>();
|
services.AddScoped<ICrawler, Crawler>();
|
||||||
services.AddSingleton<ITranscoder, Transcoder>();
|
services.AddSingleton<ITranscoder, Transcoder>();
|
||||||
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
|
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
|
||||||
services.AddSingleton<IProviderManager, ProviderManager>();
|
services.AddSingleton<IProviderManager, ProviderManager>();
|
||||||
services.AddSingleton<IPluginManager, PluginManager>();
|
services.AddSingleton<IPluginManager, PluginManager>();
|
||||||
|
|
||||||
services.AddHostedService<StartupCode>();
|
services.AddHostedService<StartupCode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
{
|
{
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
app.UseExceptionHandler("/Error");
|
app.UseExceptionHandler("/Error");
|
||||||
app.UseHsts();
|
app.UseHsts();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Use((ctx, next) =>
|
app.Use((ctx, next) =>
|
||||||
{
|
{
|
||||||
ctx.Response.Headers.Remove("X-Powered-By");
|
ctx.Response.Headers.Remove("X-Powered-By");
|
||||||
ctx.Response.Headers.Remove("Server");
|
ctx.Response.Headers.Remove("Server");
|
||||||
ctx.Response.Headers.Add("Feature-Policy", "autoplay 'self'; fullscreen");
|
ctx.Response.Headers.Add("Feature-Policy", "autoplay 'self'; fullscreen");
|
||||||
ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:; style-src 'self' 'unsafe-inline'");
|
ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:; style-src 'self' 'unsafe-inline'");
|
||||||
ctx.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
|
ctx.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
|
||||||
ctx.Response.Headers.Add("Referrer-Policy", "no-referrer");
|
ctx.Response.Headers.Add("Referrer-Policy", "no-referrer");
|
||||||
ctx.Response.Headers.Add("Access-Control-Allow-Origin", "null");
|
ctx.Response.Headers.Add("Access-Control-Allow-Origin", "null");
|
||||||
ctx.Response.Headers.Add("X-Content-Type-Options", "nosniff");
|
ctx.Response.Headers.Add("X-Content-Type-Options", "nosniff");
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
//app.UseHttpsRedirection();
|
//app.UseHttpsRedirection();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
if (!env.IsDevelopment())
|
if (!env.IsDevelopment())
|
||||||
app.UseSpaStaticFiles();
|
app.UseSpaStaticFiles();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllerRoute("API Route", "api/{controller=Home}/{action=Index}/{id?}");
|
endpoints.MapControllerRoute("API Route", "api/{controller=Home}/{action=Index}/{id?}");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.UseSpa(spa =>
|
app.UseSpa(spa =>
|
||||||
{
|
{
|
||||||
spa.Options.SourcePath = "ClientApp";
|
spa.Options.SourcePath = "ClientApp";
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
spa.UseAngularCliServer(npmScript: "start");
|
spa.UseAngularCliServer(npmScript: "start");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user