mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-23 15:30:34 -04:00
Adding collection support, only need to make the component for the visual interface.
This commit is contained in:
parent
725c6c4b88
commit
5940ccfc9d
@ -21,7 +21,7 @@
|
||||
</mat-menu>
|
||||
|
||||
<div class="container-fluid justify-content-center">
|
||||
<a class="show" *ngFor="let show of this.shows" routerLink="/show/{{show.slug}}">
|
||||
<a class="show" *ngFor="let show of this.shows" [href]="getLink(show)" [routerLink]="getLink(show)">
|
||||
<img [style.background-image]="getThumb(show.slug)" />
|
||||
<p class="title">{{show.title}}</p>
|
||||
<p class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
|
||||
|
@ -28,6 +28,14 @@ export class BrowseComponent implements OnInit
|
||||
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
|
||||
}
|
||||
|
||||
getLink(show: Show)
|
||||
{
|
||||
if (show.isCollection)
|
||||
return "/collection/" + show.slug;
|
||||
else
|
||||
return "/show/" + show.slug;
|
||||
}
|
||||
|
||||
sort(type: string, order: boolean)
|
||||
{
|
||||
this.sortType = type;
|
||||
|
@ -16,10 +16,10 @@ export interface Show
|
||||
people: People[];
|
||||
seasons: Season[];
|
||||
trailerUrl: string;
|
||||
isCollection: boolean;
|
||||
|
||||
startYear: number;
|
||||
endYear : number;
|
||||
|
||||
externalIDs: string;
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Kyoo.Models;
|
||||
using Kyoo.InternalAPI.Utility;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.Collections.Generic;
|
||||
@ -15,17 +16,17 @@ namespace Kyoo.InternalAPI
|
||||
{
|
||||
private readonly CancellationTokenSource cancellation;
|
||||
|
||||
private readonly IConfiguration config;
|
||||
private readonly ILibraryManager libraryManager;
|
||||
private readonly IMetadataProvider metadataProvider;
|
||||
private readonly ITranscoder transcoder;
|
||||
private readonly IConfiguration config;
|
||||
|
||||
public Crawler(IConfiguration configuration, ILibraryManager libraryManager, IMetadataProvider metadataProvider, ITranscoder transcoder)
|
||||
public Crawler(ILibraryManager libraryManager, IMetadataProvider metadataProvider, ITranscoder transcoder, IConfiguration configuration)
|
||||
{
|
||||
config = configuration;
|
||||
this.libraryManager = libraryManager;
|
||||
this.metadataProvider = metadataProvider;
|
||||
this.transcoder = transcoder;
|
||||
config = configuration;
|
||||
|
||||
cancellation = new CancellationTokenSource();
|
||||
}
|
||||
@ -129,12 +130,13 @@ namespace Kyoo.InternalAPI
|
||||
Match match = regex.Match(path);
|
||||
|
||||
string showPath = Path.GetDirectoryName(path);
|
||||
string collectionName = match.Groups["Collection"]?.Value;
|
||||
string showName = match.Groups["ShowTitle"].Value;
|
||||
bool seasonSuccess = long.TryParse(match.Groups["Season"].Value, out long seasonNumber);
|
||||
bool episodeSucess = long.TryParse(match.Groups["Episode"].Value, out long episodeNumber);
|
||||
long absoluteNumber = -1;
|
||||
|
||||
if(!seasonSuccess || !episodeSucess)
|
||||
if (!seasonSuccess || !episodeSucess)
|
||||
{
|
||||
//Considering that the episode is using absolute path.
|
||||
seasonNumber = -1;
|
||||
@ -160,6 +162,16 @@ namespace Kyoo.InternalAPI
|
||||
showProviderIDs = show.ExternalIDs;
|
||||
showID = libraryManager.RegisterShow(show);
|
||||
|
||||
if (collectionName != null)
|
||||
{
|
||||
if (!libraryManager.IsCollectionRegistered(Slugifier.ToSlug(collectionName), out long collectionID))
|
||||
{
|
||||
Collection collection = await metadataProvider.GetCollectionFromName(collectionName);
|
||||
collectionID = libraryManager.RegisterCollection(collection);
|
||||
}
|
||||
libraryManager.AddShowToCollection(showID, collectionID);
|
||||
}
|
||||
|
||||
List<People> actors = await metadataProvider.GetPeople(show.ExternalIDs);
|
||||
libraryManager.RegisterShowPeople(showID, actors);
|
||||
}
|
||||
@ -180,7 +192,7 @@ namespace Kyoo.InternalAPI
|
||||
Episode episode = await metadataProvider.GetEpisode(showProviderIDs, seasonNumber, episodeNumber, absoluteNumber, path);
|
||||
episode.ShowID = showID;
|
||||
|
||||
if(seasonID == -1)
|
||||
if (seasonID == -1)
|
||||
{
|
||||
if (!libraryManager.IsSeasonRegistered(showID, episode.seasonNumber, out seasonID))
|
||||
{
|
||||
|
@ -35,6 +35,8 @@ namespace Kyoo.InternalAPI
|
||||
Collection GetCollection(string slug);
|
||||
|
||||
//Check if value exists
|
||||
bool IsCollectionRegistered(string collectionSlug);
|
||||
bool IsCollectionRegistered(string collectionSlug, out long collectionID);
|
||||
bool IsShowRegistered(string showPath);
|
||||
bool IsShowRegistered(string showPath, out long showID);
|
||||
bool IsSeasonRegistered(long showID, long seasonNumber);
|
||||
@ -52,6 +54,7 @@ namespace Kyoo.InternalAPI
|
||||
long GetOrCreateStudio(Studio studio);
|
||||
|
||||
void RegisterShowPeople(long showID, List<People> actors);
|
||||
void AddShowToCollection(long showID, long collectionID);
|
||||
|
||||
void ClearSubtitles(long episodeID);
|
||||
}
|
||||
|
@ -102,6 +102,8 @@ namespace Kyoo.InternalAPI
|
||||
slug TEXT UNIQUE,
|
||||
name TEXT,
|
||||
overview TEXT,
|
||||
starYear INTEGER,
|
||||
endYear INTEGER,
|
||||
imgPrimary TEXT
|
||||
);
|
||||
CREATE TABLE collectionsLinks(
|
||||
@ -253,19 +255,17 @@ namespace Kyoo.InternalAPI
|
||||
|
||||
public IEnumerable<Show> QueryShows(string selection)
|
||||
{
|
||||
string query = "SELECT * FROM shows ORDER BY title;";
|
||||
List<Show> shows = new List<Show>();
|
||||
SQLiteDataReader reader;
|
||||
string query = "SELECT slug, title, startYear, endYear, '0' FROM shows LEFT JOIN collectionsLinks l ON l.showID = shows.id WHERE l.showID IS NULL UNION SELECT slug, name, startYear, endYear, '1' FROM collections ORDER BY title;";
|
||||
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||
{
|
||||
SQLiteDataReader reader = cmd.ExecuteReader();
|
||||
|
||||
List<Show> shows = new List<Show>();
|
||||
|
||||
reader = cmd.ExecuteReader();
|
||||
while (reader.Read())
|
||||
shows.Add(Show.FromReader(reader));
|
||||
|
||||
return shows;
|
||||
shows.Add(Show.FromQueryReader(reader));
|
||||
}
|
||||
return shows;
|
||||
}
|
||||
|
||||
public Show GetShowBySlug(string slug)
|
||||
@ -564,6 +564,31 @@ namespace Kyoo.InternalAPI
|
||||
#endregion
|
||||
|
||||
#region Check if items exists
|
||||
public bool IsCollectionRegistered(string collectionSlug)
|
||||
{
|
||||
string query = "SELECT (id) FROM collections WHERE slug = $slug;";
|
||||
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$slug", collectionSlug);
|
||||
|
||||
return cmd.ExecuteScalar() != null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCollectionRegistered(string collectionSlug, out long collectionID)
|
||||
{
|
||||
string query = "SELECT (id) FROM collections WHERE slug = $slug;";
|
||||
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$slug", collectionSlug);
|
||||
collectionID = cmd.ExecuteScalar() as long? ?? -1;
|
||||
|
||||
return collectionID != -1;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsShowRegistered(string showPath)
|
||||
{
|
||||
string query = "SELECT (id) FROM shows WHERE path = $path;";
|
||||
@ -831,6 +856,18 @@ namespace Kyoo.InternalAPI
|
||||
}
|
||||
}
|
||||
|
||||
public void AddShowToCollection(long showID, long collectionID)
|
||||
{
|
||||
string linkQuery = "INSERT INTO collectionsLinks (collectionID, showID) VALUES($collectionID, $showID);";
|
||||
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(linkQuery, sqlConnection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$collectionID", collectionID);
|
||||
cmd.Parameters.AddWithValue("$showID", showID);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSubtitles(long episodeID)
|
||||
{
|
||||
string query = "DELETE FROM tracks WHERE episodeID = $episodeID;";
|
||||
|
@ -6,6 +6,9 @@ namespace Kyoo.InternalAPI
|
||||
{
|
||||
public interface IMetadataProvider
|
||||
{
|
||||
//For the collection
|
||||
Task<Collection> GetCollectionFromName(string name);
|
||||
|
||||
//For the show
|
||||
Task<Show> GetShowByID(string id);
|
||||
Task<Show> GetShowFromName(string showName, string showPath);
|
||||
|
@ -1,10 +1,8 @@
|
||||
using Kyoo.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -1,6 +1,8 @@
|
||||
using Kyoo.InternalAPI.MetadataProvider.TheTvDB;
|
||||
using Kyoo.InternalAPI.Utility;
|
||||
using Kyoo.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -16,74 +18,13 @@ namespace Kyoo.InternalAPI.MetadataProvider
|
||||
[MetaProvider]
|
||||
public class ProviderTheTvDB : HelperTvDB, IMetadataProvider
|
||||
{
|
||||
private struct SearchTbDB
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
public async Task<Collection> GetCollectionFromName(string name)
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
{
|
||||
public string seriesName;
|
||||
public string overview;
|
||||
public string slug;
|
||||
public string network;
|
||||
public string status;
|
||||
public int id;
|
||||
public string firstAired;
|
||||
public string banner;
|
||||
public string[] aliases;
|
||||
return new Collection(-1, Slugifier.ToSlug(name), name, null, null);
|
||||
}
|
||||
|
||||
private struct DataTvDb
|
||||
{
|
||||
public string seriesName;
|
||||
public string overview;
|
||||
public string slug;
|
||||
public string network;
|
||||
public string status;
|
||||
|
||||
public int id;
|
||||
public string seriesId;
|
||||
public string imdbId;
|
||||
public string zap2itId;
|
||||
|
||||
public string firstAired;
|
||||
public string banner;
|
||||
public string[] aliases;
|
||||
public string[] genre;
|
||||
|
||||
public string added;
|
||||
public string airsDayOfWeek;
|
||||
public string airsTime;
|
||||
public string lastUpdated;
|
||||
public string runtime;
|
||||
|
||||
public string networkId;
|
||||
public string rating;
|
||||
public float siteRating;
|
||||
public int siteRatingCount;
|
||||
}
|
||||
|
||||
private struct RatingInfo
|
||||
{
|
||||
public float average;
|
||||
public int count;
|
||||
}
|
||||
private struct ImageTvDb
|
||||
{
|
||||
public string fileName;
|
||||
public int id;
|
||||
public string keyType;
|
||||
public int languageId;
|
||||
public RatingInfo ratingsInfo;
|
||||
public string resolution;
|
||||
public string subKey;
|
||||
public string thumbnail;
|
||||
}
|
||||
|
||||
private struct ErrorsTvDB
|
||||
{
|
||||
public string[] invalidFilters;
|
||||
public string invalidLanguage;
|
||||
public string[] invalidQueryParams;
|
||||
}
|
||||
|
||||
|
||||
public async Task<Show> GetShowFromName(string showName, string showPath)
|
||||
{
|
||||
string token = await Authentificate();
|
||||
@ -109,21 +50,21 @@ namespace Kyoo.InternalAPI.MetadataProvider
|
||||
stream.Close();
|
||||
response.Close();
|
||||
|
||||
var model = new { data = new SearchTbDB[0] };
|
||||
SearchTbDB data = JsonConvert.DeserializeAnonymousType(content, model).data[0];
|
||||
dynamic obj = JsonConvert.DeserializeObject(content);
|
||||
dynamic data = obj.data[0];
|
||||
|
||||
Show show = new Show(-1,
|
||||
ToSlug(showName),
|
||||
data.seriesName,
|
||||
data.aliases,
|
||||
(string)data.seriesName,
|
||||
((JArray)data.aliases).ToObject<IEnumerable<string>>(),
|
||||
showPath,
|
||||
data.overview,
|
||||
(string)data.overview,
|
||||
null, //trailer
|
||||
null, //genres (no info with this request)
|
||||
GetStatus(data.status),
|
||||
GetYear(data.firstAired),
|
||||
GetStatus((string)data.status),
|
||||
GetYear((string)data.firstAired),
|
||||
null, //endYear
|
||||
string.Format("{0}={1}|", Provider, data.id));
|
||||
string.Format("{0}={1}|", Provider, (string)data.id));
|
||||
return (await GetShowByID(GetID(show.ExternalIDs))).Set(show.Slug, show.Path) ?? show;
|
||||
}
|
||||
}
|
||||
@ -168,19 +109,19 @@ namespace Kyoo.InternalAPI.MetadataProvider
|
||||
stream.Close();
|
||||
response.Close();
|
||||
|
||||
var model = new { data = new DataTvDb(), errors = new ErrorsTvDB() };
|
||||
DataTvDb data = JsonConvert.DeserializeAnonymousType(content, model).data;
|
||||
dynamic model = JsonConvert.DeserializeObject(content);
|
||||
dynamic data = model.data;
|
||||
|
||||
Show show = new Show(-1,
|
||||
null, //Slug
|
||||
data.seriesName,
|
||||
data.aliases,
|
||||
(string)data.seriesName,
|
||||
((JArray)data.aliases).ToObject<IEnumerable<string>>(),
|
||||
null, //Path
|
||||
data.overview,
|
||||
(string)data.overview,
|
||||
null, //Trailer
|
||||
GetGenres(data.genre),
|
||||
GetStatus(data.status),
|
||||
GetYear(data.firstAired),
|
||||
GetGenres(((JArray)data.genre).ToObject<string[]>()),
|
||||
GetStatus((string)data.status),
|
||||
GetYear((string)data.firstAired),
|
||||
null, //endYear
|
||||
string.Format("TvDB={0}|", id));
|
||||
await GetImages(show);
|
||||
@ -237,10 +178,9 @@ namespace Kyoo.InternalAPI.MetadataProvider
|
||||
stream.Close();
|
||||
response.Close();
|
||||
|
||||
var model = new { data = new ImageTvDb[0], error = new ErrorsTvDB() };
|
||||
dynamic model = JsonConvert.DeserializeObject(content);
|
||||
//Should implement language selection here
|
||||
ImageTvDb data = JsonConvert.DeserializeAnonymousType(content, model).data.OrderByDescending(x => x.ratingsInfo.average).ThenByDescending(x => x.ratingsInfo.count).FirstOrDefault();
|
||||
IEnumerable<ImageTvDb> datas = JsonConvert.DeserializeAnonymousType(content, model).data.OrderByDescending(x => x.ratingsInfo.average).ThenByDescending(x => x.ratingsInfo.count);
|
||||
dynamic data = ((IEnumerable<dynamic>)model.data).OrderByDescending(x => x.ratingsInfo.average).ThenByDescending(x => x.ratingsInfo.count).FirstOrDefault();
|
||||
SetImage(show, "https://www.thetvdb.com/banners/" + data.fileName, type.Key);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Kyoo.Models;
|
||||
using Kyoo.InternalAPI.Utility;
|
||||
using Kyoo.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Kyoo.InternalAPI.MetadataProvider
|
||||
{
|
||||
@ -22,29 +21,7 @@ namespace Kyoo.InternalAPI.MetadataProvider
|
||||
|
||||
public string ToSlug(string showTitle)
|
||||
{
|
||||
if (showTitle == null)
|
||||
return null;
|
||||
|
||||
//First to lower case
|
||||
showTitle = showTitle.ToLowerInvariant();
|
||||
|
||||
//Remove all accents
|
||||
//var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(showTitle);
|
||||
//showTitle = Encoding.ASCII.GetString(bytes);
|
||||
|
||||
//Replace spaces
|
||||
showTitle = Regex.Replace(showTitle, @"\s", "-", RegexOptions.Compiled);
|
||||
|
||||
//Remove invalid chars
|
||||
showTitle = Regex.Replace(showTitle, @"[^\w\s\p{Pd}]", "", RegexOptions.Compiled);
|
||||
|
||||
//Trim dashes from end
|
||||
showTitle = showTitle.Trim('-', '_');
|
||||
|
||||
//Replace double occurences of - or \_
|
||||
showTitle = Regex.Replace(showTitle, @"([-_]){2,}", "$1", RegexOptions.Compiled);
|
||||
|
||||
return showTitle;
|
||||
return Slugifier.ToSlug(showTitle);
|
||||
}
|
||||
|
||||
public enum ImageType { Poster, Background, Thumbnail, Logo }
|
||||
|
@ -79,6 +79,11 @@ namespace Kyoo.InternalAPI
|
||||
|
||||
//For all the following methods, it should use all providers and merge the data.
|
||||
|
||||
public Task<Collection> GetCollectionFromName(string name)
|
||||
{
|
||||
return providers[0].GetCollectionFromName(name);
|
||||
}
|
||||
|
||||
public Task<Show> GetImages(Show show)
|
||||
{
|
||||
return providers[0].GetImages(show);
|
||||
|
34
Kyoo/InternalAPI/Utility/Slugifier.cs
Normal file
34
Kyoo/InternalAPI/Utility/Slugifier.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Kyoo.InternalAPI.Utility
|
||||
{
|
||||
public class Slugifier
|
||||
{
|
||||
public static string ToSlug(string showTitle)
|
||||
{
|
||||
if (showTitle == null)
|
||||
return null;
|
||||
|
||||
//First to lower case
|
||||
showTitle = showTitle.ToLowerInvariant();
|
||||
|
||||
//Remove all accents
|
||||
//var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(showTitle);
|
||||
//showTitle = Encoding.ASCII.GetString(bytes);
|
||||
|
||||
//Replace spaces
|
||||
showTitle = Regex.Replace(showTitle, @"\s", "-", RegexOptions.Compiled);
|
||||
|
||||
//Remove invalid chars
|
||||
showTitle = Regex.Replace(showTitle, @"[^\w\s\p{Pd}]", "", RegexOptions.Compiled);
|
||||
|
||||
//Trim dashes from end
|
||||
showTitle = showTitle.Trim('-', '_');
|
||||
|
||||
//Replace double occurences of - or \_
|
||||
showTitle = Regex.Replace(showTitle, @"([-_]){2,}", "$1", RegexOptions.Compiled);
|
||||
|
||||
return showTitle;
|
||||
}
|
||||
}
|
||||
}
|
@ -33,6 +33,11 @@ namespace Kyoo.Models
|
||||
reader["imgPrimary"] as string);
|
||||
}
|
||||
|
||||
public Show AsShow()
|
||||
{
|
||||
return new Show(-1, Slug, Name, null, null, Overview, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public Collection SetShows(ILibraryManager libraryManager)
|
||||
{
|
||||
Shows = libraryManager.GetShowsInCollection(id);
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Kyoo.InternalAPI;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
@ -33,6 +32,7 @@ namespace Kyoo.Models
|
||||
public IEnumerable<People> directors;
|
||||
public IEnumerable<People> people;
|
||||
public IEnumerable<Season> seasons;
|
||||
public bool IsCollection;
|
||||
|
||||
|
||||
public string GetAliases()
|
||||
@ -68,6 +68,7 @@ namespace Kyoo.Models
|
||||
StartYear = startYear;
|
||||
EndYear = endYear;
|
||||
ExternalIDs = externalIDs;
|
||||
IsCollection = false;
|
||||
}
|
||||
|
||||
public Show(long id, 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)
|
||||
@ -87,6 +88,19 @@ namespace Kyoo.Models
|
||||
ImgLogo = imgLogo;
|
||||
ImgBackdrop = imgBackdrop;
|
||||
ExternalIDs = externalIDs;
|
||||
IsCollection = false;
|
||||
}
|
||||
|
||||
public static Show FromQueryReader(System.Data.SQLite.SQLiteDataReader reader)
|
||||
{
|
||||
return new Show()
|
||||
{
|
||||
Slug = reader["slug"] as string,
|
||||
Title = reader["title"] as string,
|
||||
StartYear = reader["startYear"] as long?,
|
||||
EndYear = reader["endYear"] as long?,
|
||||
IsCollection = reader[4] as string == "1"
|
||||
};
|
||||
}
|
||||
|
||||
public static Show FromReader(System.Data.SQLite.SQLiteDataReader reader)
|
||||
|
@ -16,6 +16,6 @@
|
||||
"libraryPaths": [
|
||||
"\\\\sdg\\video\\Anime"
|
||||
],
|
||||
"regex": ".*\\\\(?<ShowTitle>.+?) S(?<Season>\\d+)E(?<Episode>\\d+)",
|
||||
"regex": ".*\\\\(?<Collection>.+?)?\\\\.*\\\\(?<ShowTitle>.+?) S(?<Season>\\d+)E(?<Episode>\\d+)",
|
||||
"absoluteRegex": ".*\\\\(?<ShowTitle>.+?) (?<AbsoluteNumber>\\d+)"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user