add jellyfin media source (#185)

* wip

* start to add jellyfin tables to db

* code cleanup

* finish adding jellyfin media source

* sync jellyfin libraries

* display list of jellyfin libraries

* toggle jellyfin library sync

* edit jellyfin path replacements

* noop jellyfin scanners

* get jellyfin admin user id on startup

* implement jellyfin disconnect

* add jellyfin libraries to list; start to query jellyfin library items

* code cleanup

* start to project jellyfin movies

* save new jellyfin movies to db

* basic jellyfin movie update

* load jellyfin actor artwork

* load jellyfin movie poster and fan art

* more jellyfin artwork fixes, sync audio streams

* jellyfin playback sort of works

* skip jellyfin movies that are inaccessible

* use ffprobe for jellyfin movie statistics

* code cleanup

* store jellyfin operating system

* more jellyfin movie updates

* update jellyfin movie poster and fan art

* add jellyfin tv types

* sync jellyfin shows

* sync jellyfin seasons

* sync jellyfin episodes

* remove missing jellyfin television items

* delete empty jellyfin seasons and shows

* fix jellyfin updates

* fix indexing jellyfin movie and show languages
This commit is contained in:
Jason Dove
2021-05-15 13:14:17 -05:00
committed by GitHub
parent 27e0a70d93
commit 4d86250630
132 changed files with 17318 additions and 106 deletions
@@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Jellyfin;
using LanguageExt;
namespace ErsatzTV.Core.Interfaces.Jellyfin
{
public interface IJellyfinApiClient
{
Task<Either<BaseError, JellyfinServerInformation>> GetServerInformation(string address, string apiKey);
Task<Either<BaseError, List<JellyfinLibrary>>> GetLibraries(string address, string apiKey);
Task<Either<BaseError, string>> GetAdminUserId(string address, string apiKey);
Task<Either<BaseError, List<JellyfinMovie>>> GetMovieLibraryItems(
string address,
string apiKey,
int mediaSourceId,
string libraryId);
Task<Either<BaseError, List<JellyfinShow>>> GetShowLibraryItems(
string address,
string apiKey,
int mediaSourceId,
string libraryId);
Task<Either<BaseError, List<JellyfinSeason>>> GetSeasonLibraryItems(
string address,
string apiKey,
int mediaSourceId,
string showId);
Task<Either<BaseError, List<JellyfinEpisode>>> GetEpisodeLibraryItems(
string address,
string apiKey,
int mediaSourceId,
string seasonId);
}
}
@@ -0,0 +1,15 @@
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using LanguageExt;
namespace ErsatzTV.Core.Interfaces.Jellyfin
{
public interface IJellyfinMovieLibraryScanner
{
Task<Either<BaseError, Unit>> ScanLibrary(
string address,
string apiKey,
JellyfinLibrary library,
string ffprobePath);
}
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Core.Interfaces.Jellyfin
{
public interface IJellyfinPathReplacementService
{
Task<string> GetReplacementJellyfinPath(int libraryPathId, string path);
string GetReplacementJellyfinPath(List<JellyfinPathReplacement> pathReplacements, string path, bool log = true);
}
}
@@ -0,0 +1,13 @@
using System.Threading.Tasks;
using ErsatzTV.Core.Jellyfin;
using LanguageExt;
namespace ErsatzTV.Core.Interfaces.Jellyfin
{
public interface IJellyfinSecretStore
{
Task<Unit> DeleteAll();
Task<JellyfinSecrets> ReadSecrets();
Task<Unit> SaveSecrets(JellyfinSecrets jellyfinSecrets);
}
}
@@ -0,0 +1,15 @@
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using LanguageExt;
namespace ErsatzTV.Core.Interfaces.Jellyfin
{
public interface IJellyfinTelevisionLibraryScanner
{
Task<Either<BaseError, Unit>> ScanLibrary(
string address,
string apiKey,
JellyfinLibrary library,
string ffprobePath);
}
}