Merge branch 'master' of github.com:jellyfin/jellyfin into nfo-watched

This commit is contained in:
David Ullmer 2021-02-11 13:48:58 +01:00
commit ab5fb1b1f2
75 changed files with 850 additions and 486 deletions

View File

@ -7,7 +7,7 @@ parameters:
default: "ubuntu-latest"
- name: DotNetSdkVersion
type: string
default: 5.0.100
default: 5.0.103
jobs:
- job: CompatibilityCheck

View File

@ -4,7 +4,7 @@
default: "ubuntu-latest"
- name: GeneratorVersion
type: string
default: "5.0.0-beta2"
default: "5.0.1"
jobs:
- job: GenerateApiClients

View File

@ -1,7 +1,7 @@
parameters:
LinuxImage: 'ubuntu-latest'
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
DotNetSdkVersion: 5.0.100
DotNetSdkVersion: 5.0.103
jobs:
- job: Build

View File

@ -10,7 +10,7 @@ parameters:
default: "tests/**/*Tests.csproj"
- name: DotNetSdkVersion
type: string
default: 5.0.100
default: 5.0.103
jobs:
- job: Test

View File

@ -6,7 +6,7 @@ variables:
- name: RestoreBuildProjects
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
- name: DotNetSdkVersion
value: 5.0.100
value: 5.0.103
pr:
autoCancel: true

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}[EHLNPB]X\d[01]\d.*",
FriendlyName = @"KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Manufacturer = "Sony",
Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[EHLNPB]X\d[01]\d.*",
Value = @".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Match = HeaderMatchType.Regex
}
}

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}([A-Z]X\d2\d|CX400).*",
FriendlyName = @"KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Manufacturer = "Sony",
Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}([A-Z]X\d2\d|CX400).*",
Value = @".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Match = HeaderMatchType.Regex
}
}

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}[A-Z]X\d5(\d|G).*",
FriendlyName = @"KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Manufacturer = "Sony",
Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[A-Z]X\d5(\d|G).*",
Value = @".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Match = HeaderMatchType.Regex
}
}

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}[WR][5689]\d{2}A.*",
FriendlyName = @"KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Manufacturer = "Sony",
Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[WR][5689]\d{2}A.*",
Value = @".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Match = HeaderMatchType.Regex
}
}

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
FriendlyName = @"(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*",
FriendlyName = @"(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*",
Manufacturer = "Sony",
Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*",
Value = @".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*",
Match = HeaderMatchType.Regex
}
}

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2010)</Name>
<Identification>
<FriendlyName>KDL-\d{2}[EHLNPB]X\d[01]\d.*</FriendlyName>
<FriendlyName>KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[EHLNPB]X\d[01]\d.*" match="Regex" />
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2011)</Name>
<Identification>
<FriendlyName>KDL-\d{2}([A-Z]X\d2\d|CX400).*</FriendlyName>
<FriendlyName>KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}([A-Z]X\d2\d|CX400).*" match="Regex" />
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2012)</Name>
<Identification>
<FriendlyName>KDL-\d{2}[A-Z]X\d5(\d|G).*</FriendlyName>
<FriendlyName>KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[A-Z]X\d5(\d|G).*" match="Regex" />
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2013)</Name>
<Identification>
<FriendlyName>KDL-\d{2}[WR][5689]\d{2}A.*</FriendlyName>
<FriendlyName>KDL-[0-9]{2}[WR][5689][0-9]{2}A.*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[WR][5689]\d{2}A.*" match="Regex" />
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2014)</Name>
<Identification>
<FriendlyName>(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*</FriendlyName>
<FriendlyName>(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*" match="Regex" />
<HttpHeaderInfo name="X-AV-Client-Info" value=".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -284,7 +284,7 @@ namespace Emby.Naming.Common
// Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
// [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the series name
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[\s_]*-[\s_]*(?<epnumber>\d+).*$")
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+).*$")
{
IsNamed = true
},
@ -588,7 +588,7 @@ namespace Emby.Naming.Common
AudioBookNamesExpressions = new[]
{
// Detect year usually in brackets after name Batman (2020)
@"^(?<name>.+?)\s*\(\s*(?<year>\d{4})\s*\)\s*$",
@"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
@"^\s*(?<name>[^ ].*?)\s*$"
};

View File

@ -33,7 +33,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.7.0</VersionPrefix>
<VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@ -5,6 +5,7 @@ using System.Buffers;
using System.IO.Pipelines;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@ -138,7 +139,7 @@ namespace Emby.Server.Implementations.HttpServer
writer.Advance(bytesRead);
// Make the data available to the PipeReader
FlushResult flushResult = await writer.FlushAsync().ConfigureAwait(false);
FlushResult flushResult = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
if (flushResult.IsCompleted)
{
// The PipeReader stopped reading
@ -181,32 +182,16 @@ namespace Emby.Server.Implementations.HttpServer
}
WebSocketMessage<object>? stub;
long bytesConsumed = 0;
try
{
if (buffer.IsSingleSegment)
{
stub = JsonSerializer.Deserialize<WebSocketMessage<object>>(buffer.FirstSpan, _jsonOptions);
}
else
{
var buf = ArrayPool<byte>.Shared.Rent(Convert.ToInt32(buffer.Length));
try
{
buffer.CopyTo(buf);
stub = JsonSerializer.Deserialize<WebSocketMessage<object>>(buf, _jsonOptions);
}
finally
{
ArrayPool<byte>.Shared.Return(buf);
}
}
stub = DeserializeWebSocketMessage(buffer, out bytesConsumed);
}
catch (JsonException ex)
{
// Tell the PipeReader how much of the buffer we have consumed
reader.AdvanceTo(buffer.End);
_logger.LogError(ex, "Error processing web socket message");
_logger.LogError(ex, "Error processing web socket message: {Data}", Encoding.UTF8.GetString(buffer));
return;
}
@ -217,27 +202,34 @@ namespace Emby.Server.Implementations.HttpServer
}
// Tell the PipeReader how much of the buffer we have consumed
reader.AdvanceTo(buffer.End);
reader.AdvanceTo(buffer.GetPosition(bytesConsumed));
_logger.LogDebug("WS {IP} received message: {@Message}", RemoteEndPoint, stub);
var info = new WebSocketMessageInfo
{
MessageType = stub.MessageType,
Data = stub.Data?.ToString(), // Data can be null
Connection = this
};
if (info.MessageType == SessionMessageType.KeepAlive)
if (stub.MessageType == SessionMessageType.KeepAlive)
{
await SendKeepAliveResponse().ConfigureAwait(false);
}
else
{
await OnReceive(info).ConfigureAwait(false);
await OnReceive(
new WebSocketMessageInfo
{
MessageType = stub.MessageType,
Data = stub.Data?.ToString(), // Data can be null
Connection = this
}).ConfigureAwait(false);
}
}
internal WebSocketMessage<object>? DeserializeWebSocketMessage(ReadOnlySequence<byte> bytes, out long bytesConsumed)
{
var jsonReader = new Utf8JsonReader(bytes);
var ret = JsonSerializer.Deserialize<WebSocketMessage<object>>(ref jsonReader, _jsonOptions);
bytesConsumed = jsonReader.BytesConsumed;
return ret;
}
private Task SendKeepAliveResponse()
{
LastKeepAliveDate = DateTime.UtcNow;

View File

@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public LegacyHdHomerunChannelCommands(string url)
{
// parse url for channel and program
var regExp = new Regex(@"\/ch(\d+)-?(\d*)");
var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)");
var match = regExp.Match(url);
if (match.Success)
{

View File

@ -0,0 +1,26 @@
{
"NotificationOptionInstallationFailed": "Instalada fiasko",
"NotificationOptionAudioPlaybackStopped": "Sono de ludado haltis",
"NotificationOptionAudioPlayback": "Ludado de sono startis",
"NameSeasonUnknown": "Sezono Nekonata",
"NameSeasonNumber": "Sezono {0}",
"NameInstallFailed": "{0} instalado fiaskis",
"Music": "Muziko",
"Movies": "Filmoj",
"ItemRemovedWithName": "{0} forigis el la biblioteko",
"ItemAddedWithName": "{0} aldonis al la biblioteko",
"HeaderLiveTV": "Viva Televido",
"HeaderContinueWatching": "Daŭrigi Spektado",
"HeaderAlbumArtists": "Artistoj de Albumo",
"Folders": "Dosierujoj",
"DeviceOnlineWithName": "{0} estas konektita",
"Default": "Defaŭlte",
"Collections": "Kolektoj",
"ChapterNameValue": "Ĉapitro {0}",
"Channels": "Kanaloj",
"Books": "Libroj",
"Artists": "Artistoj",
"Application": "Aplikaĵo",
"AppDeviceValues": "Aplikaĵo: {0}, Aparato: {1}",
"Albums": "Albumoj"
}

View File

@ -1,121 +1,121 @@
{
"HeaderLiveTV": "Live-TV",
"NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
"HeaderLiveTV": "Live TV",
"NewVersionIsAvailable": "Uusi versio Jellyfin-palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon kausi",
"NameSeasonNumber": "Kausi {0}",
"NameInstallFailed": "{0} asennus epäonnistui",
"MusicVideos": "Musiikkivideot",
"Music": "Musiikki",
"Movies": "Elokuvat",
"MixedContent": "Sekoitettu sisältö",
"MixedContent": "Sekalainen sisältö",
"MessageServerConfigurationUpdated": "Palvelimen asetukset on päivitetty",
"MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty",
"MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}",
"MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
"Latest": "Uusimmat",
"LabelRunningTimeValue": "Toiston kesto: {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusten osio {0} on päivitetty",
"MessageApplicationUpdatedTo": "Jellyfin-palvelin on päivitetty versioon {0}",
"MessageApplicationUpdated": "Jellyfin-palvelin on päivitetty",
"Latest": "Viimeisimmät",
"LabelRunningTimeValue": "Kesto: {0}",
"LabelIpAddressValue": "IP-osoite: {0}",
"ItemRemovedWithName": "{0} poistettiin kirjastosta",
"ItemAddedWithName": "{0} lisättiin kirjastoon",
"Inherit": "Periytyä",
"Inherit": "Peri",
"HomeVideos": "Kotivideot",
"HeaderRecordingGroups": "Tallennusryhmät",
"HeaderNextUp": "Seuraavaksi",
"HeaderFavoriteSongs": "Suosikkikappaleet",
"HeaderFavoriteShows": "Suosikkisarjat",
"HeaderFavoriteEpisodes": "Suosikkijaksot",
"HeaderFavoriteArtists": "Suosikkiartistit",
"HeaderFavoriteArtists": "Suosikkiesittäjät",
"HeaderFavoriteAlbums": "Suosikkialbumit",
"HeaderContinueWatching": "Jatka katsomista",
"HeaderAlbumArtists": "Albumin artistit",
"HeaderContinueWatching": "Jatka katselua",
"HeaderAlbumArtists": "Albumin esittäjät",
"Genres": "Tyylilajit",
"Folders": "Kansiot",
"Favorites": "Suosikit",
"FailedLoginAttemptWithUserName": "Kirjautuminen epäonnistui kohteesta {0}",
"FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys lähteestä \"{0}\"",
"DeviceOnlineWithName": "{0} on yhdistetty",
"DeviceOfflineWithName": "{0} yhteys on katkaistu",
"DeviceOfflineWithName": "{0} on katkaissut yhteyden",
"Collections": "Kokoelmat",
"ChapterNameValue": "Jakso: {0}",
"ChapterNameValue": "Kappale {0}",
"Channels": "Kanavat",
"CameraImageUploadedFrom": "Uusi kamerakuva on ladattu {0}",
"CameraImageUploadedFrom": "Uusi kameran kuva on sirretty lähteestä {0}",
"Books": "Kirjat",
"AuthenticationSucceededWithUserName": "Käyttäjän {0} todennus onnistui",
"Artists": "Artistit",
"AuthenticationSucceededWithUserName": "{0} on todennettu",
"Artists": "Esittäjät",
"Application": "Sovellus",
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
"Albums": "Albumit",
"User": "Käyttäjä",
"System": "Järjestelmä",
"ScheduledTaskFailedWithName": "{0} epäonnistui",
"PluginUpdatedWithName": "{0} päivitetty",
"PluginInstalledWithName": "{0} asennettu",
"Photos": "Kuvat",
"ScheduledTaskStartedWithName": "{0} aloitettu",
"PluginUninstalledWithName": "{0} poistettu",
"PluginUpdatedWithName": "{0} päivitettiin",
"PluginInstalledWithName": "{0} asennettiin",
"Photos": "Valokuvat",
"ScheduledTaskStartedWithName": "\"{0}\" käynnistetty",
"PluginUninstalledWithName": "{0} poistettiin",
"Playlists": "Soittolistat",
"VersionNumber": "Versio {0}",
"ValueSpecialEpisodeName": "Erikois - {0}",
"ValueHasBeenAddedToLibrary": "{0} lisättiin mediakirjastoon",
"UserStoppedPlayingItemWithValues": "{0} toistaminen valmistui {1} laitteella {2}",
"UserStartedPlayingItemWithValues": "{0} toistaa {1} laitteella {2}",
"UserPolicyUpdatedWithName": "Käyttöoikeudet päivitetty käyttäjälle {0}",
"UserPasswordChangedWithName": "Salasana vaihdettu käyttäjälle {0}",
"UserOnlineFromDevice": "{0} on paikalla osoitteesta {1}",
"UserOfflineFromDevice": "{0} yhteys katkaistu kohteesta {1}",
"UserLockedOutWithName": "Käyttäjä {0} lukittu",
"UserDownloadingItemWithValues": "{0} lataa {1}",
"UserDeletedWithName": "Käyttäjä {0} poistettu",
"UserCreatedWithName": "Käyttäjä {0} luotu",
"TvShows": "TV-ohjelmat",
"Sync": "Synkronoi",
"SubtitleDownloadFailureFromForItem": "Tekstitystä ei voitu ladata osoitteesta {0} kohteelle {1}",
"StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Yritä hetken kuluttua uudelleen.",
"ValueSpecialEpisodeName": "Erikoisjakso - {0}",
"ValueHasBeenAddedToLibrary": "\"{0}\" on lisätty mediakirjastoon",
"UserStoppedPlayingItemWithValues": "{0} lopetti kohteen \"{1}\" toiston sijainnissa \"{2}\"",
"UserStartedPlayingItemWithValues": "{0} toistaa kohdetta \"{1}\" sijainnissa \"{2}\"",
"UserPolicyUpdatedWithName": "Käyttäjän {0} käyttöoikeudet on päivitetty",
"UserPasswordChangedWithName": "Käyttäjän {0} salasana on vaihdettu",
"UserOnlineFromDevice": "{0} on yhdistänyt sijainnista \"{1}\"",
"UserOfflineFromDevice": "{0} on katkaissut yhteyden sijainnista \"{1}\"",
"UserLockedOutWithName": "Käyttäjä {0} on lukittu",
"UserDownloadingItemWithValues": "{0} lataa kohdetta \"{1}\"",
"UserDeletedWithName": "Käyttäjä {0} on poistettu",
"UserCreatedWithName": "Käyttäjä {0} on luotu",
"TvShows": "Sarjat",
"Sync": "Synkronointi",
"SubtitleDownloadFailureFromForItem": "Tekstityksen lataus lähteestä \"{0}\" kohteelle \"{1}\" epäonnistui",
"StartupEmbyServerIsLoading": "Jellyfin-palvelin latautuu. Yritä hetken kuluttua uudelleen.",
"Songs": "Kappaleet",
"Shows": "Ohjelmat",
"ServerNameNeedsToBeRestarted": "{0} on käynnistettävä uudelleen",
"ProviderValue": "Tarjoaja: {0}",
"Plugin": "Liitännäinen",
"NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty",
"NotificationOptionVideoPlayback": "Videota toistetaan",
"NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos",
"NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui",
"NotificationOptionServerRestartRequired": "Palvelin on käynnistettävä uudelleen",
"NotificationOptionPluginUpdateInstalled": "Liitännäinen päivitetty",
"NotificationOptionPluginUninstalled": "Liitännäinen poistettu",
"NotificationOptionPluginInstalled": "Liitännäinen asennettu",
"NotificationOptionPluginError": "Ongelma liitännäisessä",
"NotificationOptionNewLibraryContent": "Uutta sisältöä lisätty",
"Shows": "Sarjat",
"ServerNameNeedsToBeRestarted": "\"{0}\" on käynnistettävä uudelleen",
"ProviderValue": "Lähde: {0}",
"Plugin": "Laajennus",
"NotificationOptionVideoPlaybackStopped": "Videon toisto lopetettu",
"NotificationOptionVideoPlayback": "Videon toisto aloitettu",
"NotificationOptionUserLockedOut": "Käyttäjä on lukittu",
"NotificationOptionTaskFailed": "Ajoitettu tehtävä epäonnistui",
"NotificationOptionServerRestartRequired": "Tarvitaan palvelimen uudelleenkäynnistys",
"NotificationOptionPluginUpdateInstalled": "Laajennus on päivitetty",
"NotificationOptionPluginUninstalled": "Laajennus on poistettu",
"NotificationOptionPluginInstalled": "Laajennus on asennettu",
"NotificationOptionPluginError": "Laajennuksen virhe",
"NotificationOptionNewLibraryContent": "Sisältöä on lisätty",
"NotificationOptionInstallationFailed": "Asennus epäonnistui",
"NotificationOptionCameraImageUploaded": "Kameran kuva ladattu",
"NotificationOptionCameraImageUploaded": "Kameran kuva on tallennettu",
"NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
"NotificationOptionAudioPlayback": "Toistetaan ääntä",
"NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettu",
"NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla",
"NotificationOptionAudioPlayback": "Äänen toisto aloitettu",
"NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettiin",
"NotificationOptionApplicationUpdateAvailable": "Sovelluspäivitys on saatavilla",
"TasksMaintenanceCategory": "Ylläpito",
"TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.",
"TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä määritettyjen metatietoasetusten mukaisesti.",
"TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
"TaskRefreshChannelsDescription": "Päivittää internet-kanavien tiedot.",
"TaskRefreshChannels": "Päivitä kanavat",
"TaskCleanTranscodeDescription": "Poistaa transkoodatut tiedostot jotka ovat yli päivän vanhoja.",
"TaskCleanTranscode": "Puhdista transkoodaushakemisto",
"TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset liitännäisille jotka on asetettu päivittymään automaattisesti.",
"TaskUpdatePlugins": "Päivitä liitännäiset",
"TaskRefreshPeopleDescription": "Päivittää näyttelijöiden ja ohjaajien mediatiedot kirjastossasi.",
"TaskCleanTranscodeDescription": "Poistaa päivää vanhemmat transkoodaustiedostot.",
"TaskCleanTranscode": "Puhdista transkoodauskansio",
"TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset laajennuksille, jotka on määritetty päivittymään automaattisesti.",
"TaskUpdatePlugins": "Päivitä laajennukset",
"TaskRefreshPeopleDescription": "Päivittää mediakirjaston näyttelijöiden ja ohjaajien metatiedot.",
"TaskRefreshPeople": "Päivitä henkilöt",
"TaskCleanLogsDescription": "Poistaa lokitiedostot jotka ovat yli {0} päivää vanhoja.",
"TaskCleanLogs": "Puhdista lokihakemisto",
"TaskRefreshLibraryDescription": "Skannaa mediakirjastosi uudet tiedostot ja päivittää metatiedot.",
"TaskRefreshLibrary": "Skannaa mediakirjasto",
"TaskRefreshChapterImagesDescription": "Luo pienoiskuvat videoille joissa on jaksoja.",
"TaskRefreshChapterImages": "Pura jakson kuvat",
"TaskCleanCacheDescription": "Poistaa järjestelmälle tarpeettomat väliaikaistiedostot.",
"TaskCleanCache": "Tyhjennä välimuisti-hakemisto",
"TasksChannelsCategory": "Internet kanavat",
"TaskCleanLogsDescription": "Poistaa {0} päivää vanhemmat lokitiedostot.",
"TaskCleanLogs": "Siivoa lokikansio",
"TaskRefreshLibraryDescription": "Tarkastaa mediakirjastosi sisällön uusien tiedostojen varalta ja päivittää metatiedot.",
"TaskRefreshLibrary": "Päivitä mediakirjasto",
"TaskRefreshChapterImagesDescription": "Luo esikatselukuvat videoille, jotka sisältävät kappalejaon.",
"TaskRefreshChapterImages": "Pura kappalejaon kuvat",
"TaskCleanCacheDescription": "Poistaa tarpeettomiksi jääneet väliaikaistiedostot.",
"TaskCleanCache": "Tyhjennä välimuistikansio",
"TasksChannelsCategory": "Internet-kanavat",
"TasksApplicationCategory": "Sovellus",
"TasksLibraryCategory": "Kirjasto",
"Forced": "Pakotettu",
"Default": "Oletus",
"TaskCleanActivityLogDescription": "Poistaa määritettyä vanhemmat tapahtumat aktiviteettilokista.",
"TaskCleanActivityLog": "Tyhjennä aktiviteettiloki",
"TaskCleanActivityLogDescription": "Poistaa määritettyä ikää vanhemmat tapahtumat toimintahistoriasta.",
"TaskCleanActivityLog": "Tyhjennä toimintahistoria",
"Undefined": "Määrittelemätön"
}

View File

@ -1,5 +1,5 @@
{
"Albums": "संग्रह",
"Albums": "एल्बम",
"HeaderRecordingGroups": "रिकॉर्डिंग समूह",
"HeaderNextUp": "इसके बाद",
"HeaderLiveTV": "लाइव टीवी",
@ -26,7 +26,7 @@
"AuthenticationSucceededWithUserName": "सफलता से प्रमाणीकृत",
"Artists": "कलाकारों",
"Application": "एप्लिकेशन",
"AppDeviceValues": "एप: {0}, मशीन: {1}",
"AppDeviceValues": "एप: {0}, उपकरण: {1}",
"NotificationOptionPluginUninstalled": "प्लगइन अनइंस्टाल हो गया",
"NotificationOptionPluginInstalled": "प्लगइन इनस्टॉल हो गया",
"NotificationOptionPluginError": "प्लगइन फ़ैल हो गया",

View File

@ -348,7 +348,7 @@ namespace Emby.Server.Implementations.Plugins
try
{
var data = JsonSerializer.Serialize(manifest, _jsonOptions);
File.WriteAllText(Path.Combine(path, "meta.json"), data, Encoding.UTF8);
File.WriteAllText(Path.Combine(path, "meta.json"), data);
return true;
}
#pragma warning disable CA1031 // Do not catch general exception types
@ -519,7 +519,7 @@ namespace Emby.Server.Implementations.Plugins
return _plugins.Remove(plugin);
}
private LocalPlugin LoadManifest(string dir)
internal LocalPlugin LoadManifest(string dir)
{
Version? version;
PluginManifest? manifest = null;

View File

@ -1456,7 +1456,12 @@ namespace Emby.Server.Implementations.Session
throw new SecurityException("Unknown quick connect token");
}
request.UserId = result.Items[0].UserId;
var info = result.Items[0];
request.UserId = info.UserId;
// There's no need to keep the quick connect token in the database, as AuthenticateNewSessionInternal() issues a long lived token.
_authRepo.Delete(info);
return AuthenticateNewSessionInternal(request, false);
}

View File

@ -15,10 +15,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.0.2" />
</ItemGroup>
<ItemGroup>

View File

@ -19,7 +19,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Data</PackageId>
<VersionPrefix>10.7.0</VersionPrefix>
<VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
@ -41,8 +41,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.3" />
</ItemGroup>
<ItemGroup>

View File

@ -26,11 +26,11 @@
<ItemGroup>
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -40,8 +40,8 @@
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.2" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.3" />
<PackageReference Include="prometheus-net" Version="4.1.1" />
<PackageReference Include="prometheus-net.AspNetCore" Version="4.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />

View File

@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Common</PackageId>
<VersionPrefix>10.7.0</VersionPrefix>
<VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId>
<VersionPrefix>10.7.0</VersionPrefix>
<VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,14 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool SupportsHwaccel(string hwaccel);
/// <summary>
/// Whether given filter is supported.
/// </summary>
/// <param name="filter">The filter.</param>
/// <param name="option">The option.</param>
/// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
bool SupportsFilter(string filter, string option);
/// <summary>
/// Extracts the audio image.
/// </summary>

View File

@ -296,6 +296,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
return found;
}
public bool CheckFilter(string filter, string option)
{
if (string.IsNullOrEmpty(filter))
{
return false;
}
string output = null;
try
{
output = GetProcessOutput(_encoderPath, "-h filter=" + filter);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error detecting the given filter");
}
if (output.Contains("Filter " + filter, StringComparison.Ordinal))
{
if (string.IsNullOrEmpty(option))
{
return true;
}
return output.Contains(option, StringComparison.Ordinal);
}
_logger.LogWarning("Filter: {Name} with option {Option} is not available", filter, option);
return false;
}
private IEnumerable<string> GetCodecs(Codec codec)
{
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";

View File

@ -295,6 +295,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
return _hwaccels.Contains(hwaccel, StringComparer.OrdinalIgnoreCase);
}
public bool SupportsFilter(string filter, string option)
{
if (_ffmpegPath != null)
{
var validator = new EncoderValidator(_logger, _ffmpegPath);
return validator.CheckFilter(filter, option);
}
return false;
}
public bool CanEncodeToAudioCodec(string codec)
{
if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))

View File

@ -57,7 +57,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w0-9]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
trackEvents.Add(subEvent);
}

View File

@ -79,7 +79,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.Text = string.Join(ParserValues.NewLine, multiline);
subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\\d?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\[0-9]?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "&lt;(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)&gt;", "<$1$3$7>", RegexOptions.IgnoreCase);

View File

@ -39,6 +39,8 @@ namespace MediaBrowser.Model.Configuration
public bool EnableTonemapping { get; set; }
public bool EnableVppTonemapping { get; set; }
public string TonemappingAlgorithm { get; set; }
public string TonemappingRange { get; set; }
@ -65,6 +67,8 @@ namespace MediaBrowser.Model.Configuration
public bool EnableDecodingColorDepth10Vp9 { get; set; }
public bool EnableEnhancedNvdecDecoder { get; set; }
public bool EnableHardwareEncoding { get; set; }
public bool AllowHevcEncoding { get; set; }
@ -88,6 +92,7 @@ namespace MediaBrowser.Model.Configuration
// The left side of the dot is the platform number, and the right side is the device number on the platform.
OpenclDevice = "0.0";
EnableTonemapping = false;
EnableVppTonemapping = false;
TonemappingAlgorithm = "hable";
TonemappingRange = "auto";
TonemappingDesat = 0;
@ -100,6 +105,7 @@ namespace MediaBrowser.Model.Configuration
DeinterlaceMethod = "yadif";
EnableDecodingColorDepth10Hevc = true;
EnableDecodingColorDepth10Vp9 = true;
EnableEnhancedNvdecDecoder = true;
EnableHardwareEncoding = true;
AllowHevcEncoding = true;
EnableSubtitleExtraction = true;

View File

@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Model</PackageId>
<VersionPrefix>10.7.0</VersionPrefix>
<VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@ -785,20 +785,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
case "musicBrainzArtistID":
{
if (reader.IsEmptyElement)
{
reader.Read();
break;
}
var id = reader.ReadElementContentAsString();
item.SetProviderId(MetadataProvider.MusicBrainzArtist.ToString(), id);
break;
}
default:
string readerName = reader.Name;
if (_validProviderIds.TryGetValue(readerName, out string? providerIdValue))

View File

@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("10.7.0")]
[assembly: AssemblyFileVersion("10.7.0")]
[assembly: AssemblyVersion("10.8.0")]
[assembly: AssemblyFileVersion("10.8.0")]

View File

@ -1,7 +1,7 @@
---
# We just wrap `build` so this is really it
name: "jellyfin"
version: "10.7.0"
version: "10.8.0"
packages:
- debian.amd64
- debian.arm64

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
jellyfin-server (10.8.0-1) unstable; urgency=medium
* Forthcoming stable release
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 04 Dec 2020 21:55:12 -0500
jellyfin-server (10.7.0-1) unstable; urgency=medium
* Forthcoming stable release

View File

@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
Standards-Version: 3.9.2
Package: jellyfin
Version: 10.7.0
Version: 10.8.0
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
Depends: jellyfin-server, jellyfin-web
Description: Provides the Jellyfin Free Software Media System

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -15,7 +15,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -15,7 +15,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -7,7 +7,7 @@
%endif
Name: jellyfin
Version: 10.7.0
Version: 10.8.0
Release: 1%{?dist}
Summary: The Free Software Media System
License: GPLv3
@ -137,6 +137,8 @@ fi
%systemd_postun_with_restart jellyfin.service
%changelog
* Fri Dec 04 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>

View File

@ -16,7 +16,7 @@
<PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.15.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />

View File

@ -0,0 +1,69 @@
using System;
using System.Buffers;
using System.IO;
using System.Text.Json;
using Emby.Server.Implementations.HttpServer;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Jellyfin.Server.Implementations.Tests.HttpServer
{
public class WebSocketConnectionTests
{
[Fact]
public void DeserializeWebSocketMessage_SingleSegment_Success()
{
var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json");
con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed);
Assert.Equal(109, bytesConsumed);
}
[Fact]
public void DeserializeWebSocketMessage_MultipleSegments_Success()
{
const int SplitPos = 64;
var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json");
var seg1 = new BufferSegment(new Memory<byte>(bytes, 0, SplitPos));
var seg2 = seg1.Append(new Memory<byte>(bytes, SplitPos, bytes.Length - SplitPos));
con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(seg1, 0, seg2, seg2.Memory.Length - 1), out var bytesConsumed);
Assert.Equal(109, bytesConsumed);
}
[Fact]
public void DeserializeWebSocketMessage_ValidPartial_Success()
{
var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
var bytes = File.ReadAllBytes("Test Data/HttpServer/ValidPartial.json");
con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed);
Assert.Equal(109, bytesConsumed);
}
[Fact]
public void DeserializeWebSocketMessage_Partial_ThrowJsonException()
{
var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
var bytes = File.ReadAllBytes("Test Data/HttpServer/Partial.json");
Assert.Throws<JsonException>(() => con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed));
}
internal class BufferSegment : ReadOnlySequenceSegment<byte>
{
public BufferSegment(Memory<byte> memory)
{
Memory = memory;
}
public BufferSegment Append(Memory<byte> memory)
{
var segment = new BufferSegment(memory)
{
RunningIndex = RunningIndex + Memory.Length
};
Next = segment;
return segment;
}
}
}
}

View File

@ -13,6 +13,12 @@
<RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<None Include="Test Data\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
@ -35,11 +41,6 @@
<ProjectReference Include="..\..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="LiveTv\discover.json" />
<EmbeddedResource Include="LiveTv\lineup.json" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@ -21,24 +22,15 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
public HdHomerunHostTests()
{
const string BaseResourcePath = "Jellyfin.Server.Implementations.Tests.LiveTv.";
var messageHandler = new Mock<HttpMessageHandler>();
messageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(
(m, _) =>
{
var resource = BaseResourcePath + m.RequestUri?.Segments[^1];
var stream = typeof(HdHomerunHostTests).Assembly.GetManifestResourceStream(resource);
if (stream == null)
{
throw new NullReferenceException("Resource doesn't exist: " + resource);
}
return Task.FromResult(new HttpResponseMessage()
{
Content = new StreamContent(stream)
Content = new StreamContent(File.OpenRead("Test Data/LiveTv/" + m.RequestUri?.Segments[^1]))
});
});

View File

@ -0,0 +1,45 @@
using System;
using System.IO;
using Emby.Server.Implementations.Plugins;
using MediaBrowser.Common.Plugins;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Jellyfin.Server.Implementations.Tests.Plugins
{
public class PluginManagerTests
{
private static readonly string _testPathRoot = Path.Combine(Path.GetTempPath(), "jellyfin-test-data");
[Fact]
public void SaveManifest_RoundTrip_Success()
{
var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, null!, new Version(1, 0));
var manifest = new PluginManifest()
{
Version = "1.0"
};
var tempPath = Path.Combine(_testPathRoot, "manifest-" + Path.GetRandomFileName());
Directory.CreateDirectory(tempPath);
Assert.True(pluginManager.SaveManifest(manifest, tempPath));
var res = pluginManager.LoadManifest(tempPath);
Assert.Equal(manifest.Category, res.Manifest.Category);
Assert.Equal(manifest.Changelog, res.Manifest.Changelog);
Assert.Equal(manifest.Description, res.Manifest.Description);
Assert.Equal(manifest.Id, res.Manifest.Id);
Assert.Equal(manifest.Name, res.Manifest.Name);
Assert.Equal(manifest.Overview, res.Manifest.Overview);
Assert.Equal(manifest.Owner, res.Manifest.Owner);
Assert.Equal(manifest.TargetAbi, res.Manifest.TargetAbi);
Assert.Equal(manifest.Timestamp, res.Manifest.Timestamp);
Assert.Equal(manifest.Version, res.Manifest.Version);
Assert.Equal(manifest.Status, res.Manifest.Status);
Assert.Equal(manifest.AutoUpdate, res.Manifest.AutoUpdate);
Assert.Equal(manifest.ImagePath, res.Manifest.ImagePath);
}
}
}

View File

@ -0,0 +1 @@
{"MessageType":"ForceKeepAlive","MessageId":"00000000-0000-0000-0000-000000000000","ServerId":null,"Data":60}

View File

@ -0,0 +1 @@
{"MessageType":"KeepAlive","MessageId":"d29ef449-6965-4000

View File

@ -0,0 +1 @@
{"MessageType":"ForceKeepAlive","MessageId":"00000000-0000-0000-0000-000000000000","ServerId":null,"Data":60}{"MessageType":"KeepAlive","MessageId":"d29ef449-6965-4000

View File

@ -31,6 +31,7 @@
<ItemGroup>
<ProjectReference Include="../../MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj" />
<ProjectReference Include="../../MediaBrowser.Providers/MediaBrowser.Providers.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@ -8,6 +8,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Providers.Movies;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@ -24,8 +25,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public EpisodeNfoProviderTests()
{
var providerManager = new Mock<IProviderManager>();
var imdbExternalId = new ImdbExternalId();
var externalIdInfo = new ExternalIdInfo(imdbExternalId.ProviderName, imdbExternalId.Key, imdbExternalId.Type, imdbExternalId.UrlFormatString);
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
.Returns(Enumerable.Empty<ExternalIdInfo>());
.Returns(new[] { externalIdInfo });
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());
@ -60,6 +66,8 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal(2017, item.ProductionYear);
Assert.Single(item.Studios);
Assert.Contains("Starz", item.Studios);
Assert.Equal("tt5017734", item.ProviderIds[MetadataProvider.Imdb.ToString()]);
Assert.Equal("1276153", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
// Credits
var writers = result.People.Where(x => x.Type == PersonType.Writer).ToArray();

View File

@ -9,6 +9,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Providers.Plugins.Tmdb.Movies;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@ -27,8 +28,12 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
_testUser = new User("Test User", "Auth provider", "Reset provider");
var providerManager = new Mock<IProviderManager>();
var tmdbExternalId = new TmdbMovieExternalId();
var externalIdInfo = new ExternalIdInfo(tmdbExternalId.ProviderName, tmdbExternalId.Key, tmdbExternalId.Type, tmdbExternalId.UrlFormatString);
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
.Returns(Enumerable.Empty<ExternalIdInfo>());
.Returns(new[] { externalIdInfo });
var nfoConfig = new XbmcMetadataOptions()
{
@ -63,7 +68,8 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal("Justice League", item.OriginalTitle);
Assert.Equal("Justice for all.", item.Tagline);
Assert.Equal("tt0974015", item.ProviderIds["imdb"]);
Assert.Equal("tt0974015", item.ProviderIds[MetadataProvider.Imdb.ToString()]);
Assert.Equal("141052", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
Assert.Equal(4, item.Genres.Length);
Assert.Contains("Action", item.Genres);

View File

@ -10,6 +10,8 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Providers.Music;
using MediaBrowser.Providers.Plugins.MusicBrainz;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@ -24,8 +26,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public MusicAlbumNfoProviderTests()
{
var providerManager = new Mock<IProviderManager>();
var musicBrainzArtist = new MusicBrainzArtistExternalId();
var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type, "MusicBrainzServer");
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
.Returns(Enumerable.Empty<ExternalIdInfo>());
.Returns(new[] { externalIdInfo });
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());

View File

@ -8,6 +8,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Providers.Music;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@ -22,8 +23,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public MusicArtistNfoParserTests()
{
var providerManager = new Mock<IProviderManager>();
var musicBrainzArtist = new MusicBrainzArtistExternalId();
var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type, "MusicBrainzServer");
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
.Returns(Enumerable.Empty<ExternalIdInfo>());
.Returns(new[] { externalIdInfo });
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());

View File

@ -47,8 +47,8 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal("American Gods", item.OriginalTitle);
Assert.Equal(string.Empty, item.Tagline);
Assert.Equal(0, item.RunTimeTicks);
Assert.Equal("46639", item.ProviderIds["tmdb"]);
Assert.Equal("253573", item.ProviderIds["tvdb"]);
Assert.Equal("46639", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
Assert.Equal("253573", item.ProviderIds[MetadataProvider.Tvdb.ToString()]);
Assert.Equal(3, item.Genres.Length);
Assert.Contains("Drama", item.Genres);

View File

@ -33,6 +33,7 @@
<playcount>2</playcount>
<watched>true</watched>
<lastplayed>2021-02-11 07:47:23</lastplayed>
<tmdbId>141052</tmdbId>
<thumb aspect="set.poster" preview="https://assets.fanart.tv/preview/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg">https://assets.fanart.tv/fanart/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg</thumb>
<thumb aspect="set.poster" preview="https://assets.fanart.tv/preview/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg">https://assets.fanart.tv/fanart/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg</thumb>
<thumb aspect="set.clearlogo" preview="https://assets.fanart.tv/preview/movies/468551/hdmovielogo/justice-league-collection-5ba855ed4239a.png">https://assets.fanart.tv/fanart/movies/468551/hdmovielogo/justice-league-collection-5ba855ed4239a.png</thumb>

View File

@ -24,6 +24,7 @@
<lastplayed></lastplayed>
<id>1276153</id>
<uniqueid type="tmdb" default="true">1276153</uniqueid>
<imdbId>tt5017734</imdbId>
<genre>Drama</genre>
<genre>Mystery</genre>
<genre>Sci-Fi &amp; Fantasy</genre>