Merge remote-tracking branch 'upstream/master' into client-logger
This commit is contained in:
commit
d3d9311f48
6
.github/workflows/openapi.yml
vendored
6
.github/workflows/openapi.yml
vendored
|
@ -3,7 +3,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
pull_request_target:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
openapi-head:
|
openapi-head:
|
||||||
|
@ -12,6 +12,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
ref: ${{ github.head_ref }}
|
||||||
- name: Setup .NET Core
|
- name: Setup .NET Core
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
|
@ -53,7 +55,7 @@ jobs:
|
||||||
|
|
||||||
openapi-diff:
|
openapi-diff:
|
||||||
name: OpenAPI - Difference
|
name: OpenAPI - Difference
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request_target' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- openapi-head
|
- openapi-head
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"NotificationOptionInstallationFailed": "Instalada fiasko",
|
"NotificationOptionInstallationFailed": "Instalada malsukceso",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Ludado de sono haltis",
|
"NotificationOptionAudioPlaybackStopped": "Ludado de sono haltis",
|
||||||
"NotificationOptionAudioPlayback": "Ludado de sono lanĉis",
|
"NotificationOptionAudioPlayback": "Ludado de sono lanĉis",
|
||||||
"NameSeasonUnknown": "Sezono Nekonata",
|
"NameSeasonUnknown": "Sezono Nekonata",
|
||||||
|
@ -48,17 +48,17 @@
|
||||||
"Shows": "Serioj",
|
"Shows": "Serioj",
|
||||||
"HeaderFavoriteShows": "Favorataj Serioj",
|
"HeaderFavoriteShows": "Favorataj Serioj",
|
||||||
"TvShows": "TV-serioj",
|
"TvShows": "TV-serioj",
|
||||||
"Favorites": "Favoratoj",
|
"Favorites": "Favorataj",
|
||||||
"TaskCleanLogs": "Purigi Ĵurnalan Katalogon",
|
"TaskCleanLogs": "Purigi Ĵurnalan Katalogon",
|
||||||
"TaskRefreshLibrary": "Skanu Plurmeditekon",
|
"TaskRefreshLibrary": "Skani Plurmeditekon",
|
||||||
"ValueSpecialEpisodeName": "Speciala - {0}",
|
"ValueSpecialEpisodeName": "Speciala - {0}",
|
||||||
"TaskOptimizeDatabase": "Optimigi datumbazon",
|
"TaskOptimizeDatabase": "Optimumigi datenbazon",
|
||||||
"TaskRefreshChannels": "Refreŝigi Kanalojn",
|
"TaskRefreshChannels": "Refreŝigi Kanalojn",
|
||||||
"TaskUpdatePlugins": "Ĝisdatigi Kromprogramojn",
|
"TaskUpdatePlugins": "Ĝisdatigi Kromprogramojn",
|
||||||
"TaskRefreshPeople": "Refreŝigi Homojn",
|
"TaskRefreshPeople": "Refreŝigi Homojn",
|
||||||
"TasksChannelsCategory": "Interretaj Kanaloj",
|
"TasksChannelsCategory": "Interretaj Kanaloj",
|
||||||
"ProviderValue": "Provizanto: {0}",
|
"ProviderValue": "Provizanto: {0}",
|
||||||
"NotificationOptionPluginError": "Kromprograma malsukceso",
|
"NotificationOptionPluginError": "Kromprogramo malsukcesis",
|
||||||
"MixedContent": "Miksita enhavo",
|
"MixedContent": "Miksita enhavo",
|
||||||
"TasksApplicationCategory": "Aplikaĵo",
|
"TasksApplicationCategory": "Aplikaĵo",
|
||||||
"TasksMaintenanceCategory": "Prizorgado",
|
"TasksMaintenanceCategory": "Prizorgado",
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
"ServerNameNeedsToBeRestarted": "{0} devas esti relanĉita",
|
"ServerNameNeedsToBeRestarted": "{0} devas esti relanĉita",
|
||||||
"NotificationOptionVideoPlayback": "La videoludado lanĉis",
|
"NotificationOptionVideoPlayback": "La videoludado lanĉis",
|
||||||
"NotificationOptionServerRestartRequired": "Servila relanĉigo bezonata",
|
"NotificationOptionServerRestartRequired": "Servila relanĉigo bezonata",
|
||||||
"TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la teka skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.",
|
"TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la plurmediteka skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.",
|
||||||
"TaskUpdatePluginsDescription": "Elŝutas kaj instalas ĝisdatigojn por kromprogramojn, kiuj estas agorditaj por ĝisdatigi aŭtomate.",
|
"TaskUpdatePluginsDescription": "Elŝutas kaj instalas ĝisdatigojn por kromprogramojn, kiuj estas agorditaj por ĝisdatigi aŭtomate.",
|
||||||
"TaskDownloadMissingSubtitlesDescription": "Serĉas en interreto mankantajn subtekstojn surbaze de metadatena agordaro.",
|
"TaskDownloadMissingSubtitlesDescription": "Serĉas en interreto mankantajn subtekstojn surbaze de metadatena agordaro.",
|
||||||
"TaskRefreshPeopleDescription": "Ĝisdatigas metadatenojn por aktoroj kaj reĵisoroj en via plurmediteko.",
|
"TaskRefreshPeopleDescription": "Ĝisdatigas metadatenojn por aktoroj kaj reĵisoroj en via plurmediteko.",
|
||||||
|
@ -102,9 +102,9 @@
|
||||||
"MessageApplicationUpdatedTo": "Jellyfin Server estis ĝisdatigita al {0}",
|
"MessageApplicationUpdatedTo": "Jellyfin Server estis ĝisdatigita al {0}",
|
||||||
"MessageApplicationUpdated": "Jellyfin Server estis ĝisdatigita",
|
"MessageApplicationUpdated": "Jellyfin Server estis ĝisdatigita",
|
||||||
"TaskRefreshChannelsDescription": "Refreŝigas informon pri interretaj kanaloj.",
|
"TaskRefreshChannelsDescription": "Refreŝigas informon pri interretaj kanaloj.",
|
||||||
"TaskDownloadMissingSubtitles": "Elŝutu mankantajn subtekstojn",
|
"TaskDownloadMissingSubtitles": "Elŝuti mankantajn subtekstojn",
|
||||||
"TaskCleanTranscode": "Malplenigi Transkodadan Katalogon",
|
"TaskCleanTranscode": "Malplenigi Transkodadan Katalogon",
|
||||||
"TaskRefreshChapterImages": "Eltiru Ĉapitro-Bildojn",
|
"TaskRefreshChapterImages": "Eltiri Ĉapitraj Bildojn",
|
||||||
"TaskCleanCache": "Malplenigi Staplan Katalogon",
|
"TaskCleanCache": "Malplenigi Staplan Katalogon",
|
||||||
"TaskCleanActivityLog": "Malplenigi Aktivecan Ĵurnalon",
|
"TaskCleanActivityLog": "Malplenigi Aktivecan Ĵurnalon",
|
||||||
"PluginUpdatedWithName": "{0} estis ĝisdatigita",
|
"PluginUpdatedWithName": "{0} estis ĝisdatigita",
|
||||||
|
|
|
@ -119,6 +119,6 @@
|
||||||
"Undefined": "Не определено",
|
"Undefined": "Не определено",
|
||||||
"Forced": "Форсир-ые",
|
"Forced": "Форсир-ые",
|
||||||
"Default": "По умолчанию",
|
"Default": "По умолчанию",
|
||||||
"TaskOptimizeDatabaseDescription": "Сжимает базу данных и обрезает свободное место. Выполнение этой задачи после сканирования библиотеки или внесения других изменений, предполагающих модификации базы данных, может повысить производительность.",
|
"TaskOptimizeDatabaseDescription": "Сжимает базу данных и вырезает свободные места. Выполнение этой задачи после сканирования библиотеки или внесения других изменений, предполагающих модификации базы данных, может повысить производительность.",
|
||||||
"TaskOptimizeDatabase": "Оптимизировать базу данных"
|
"TaskOptimizeDatabase": "Оптимизировать базу данных"
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
"MixedContent": "Zmiešaný obsah",
|
"MixedContent": "Zmiešaný obsah",
|
||||||
"Movies": "Filmy",
|
"Movies": "Filmy",
|
||||||
"Music": "Hudba",
|
"Music": "Hudba",
|
||||||
"MusicVideos": "Hudobné videá",
|
"MusicVideos": "Hudobné videoklipy",
|
||||||
"NameInstallFailed": "Inštalácia {0} zlyhala",
|
"NameInstallFailed": "Inštalácia {0} zlyhala",
|
||||||
"NameSeasonNumber": "Séria {0}",
|
"NameSeasonNumber": "Séria {0}",
|
||||||
"NameSeasonUnknown": "Neznáma séria",
|
"NameSeasonUnknown": "Neznáma séria",
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"CameraImageUploadedFrom": "{0} 'den yeni bir kamera resmi yüklendi",
|
"CameraImageUploadedFrom": "{0} 'den yeni bir kamera resmi yüklendi",
|
||||||
"Channels": "Kanallar",
|
"Channels": "Kanallar",
|
||||||
"ChapterNameValue": "Bölüm {0}",
|
"ChapterNameValue": "Bölüm {0}",
|
||||||
"Collections": "Koleksiyon",
|
"Collections": "Koleksiyonlar",
|
||||||
"DeviceOfflineWithName": "{0} bağlantısı kesildi",
|
"DeviceOfflineWithName": "{0} bağlantısı kesildi",
|
||||||
"DeviceOnlineWithName": "{0} bağlı",
|
"DeviceOnlineWithName": "{0} bağlı",
|
||||||
"FailedLoginAttemptWithUserName": "{0} adresinden giriş başarısız oldu",
|
"FailedLoginAttemptWithUserName": "{0} adresinden giriş başarısız oldu",
|
||||||
|
|
|
@ -84,8 +84,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
Model.Entities.ExtraType.Scene
|
Model.Entities.ExtraType.Scene
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The supported extra folder names and types. See <see cref="Emby.Naming.Common.NamingOptions" />.
|
/// The supported extra folder names and types. See <see cref="Emby.Naming.Common.NamingOptions" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -354,11 +352,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// if (IsOffline)
|
|
||||||
// {
|
|
||||||
// return LocationType.Offline;
|
|
||||||
// }
|
|
||||||
|
|
||||||
var path = Path;
|
var path = Path;
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
|
@ -391,7 +384,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool IsFileProtocol => IsPathProtocol(MediaProtocol.File);
|
public bool IsFileProtocol => PathProtocol == MediaProtocol.File;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool HasPathProtocol => PathProtocol.HasValue;
|
public bool HasPathProtocol => PathProtocol.HasValue;
|
||||||
|
@ -583,14 +576,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual Guid DisplayParentId
|
public virtual Guid DisplayParentId => ParentId;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var parentId = ParentId;
|
|
||||||
return parentId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public BaseItem DisplayParent
|
public BaseItem DisplayParent
|
||||||
|
@ -853,13 +839,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return Id.ToString("N", CultureInfo.InvariantCulture);
|
return Id.ToString("N", CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsPathProtocol(MediaProtocol protocol)
|
|
||||||
{
|
|
||||||
var current = PathProtocol;
|
|
||||||
|
|
||||||
return current.HasValue && current.Value == protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
|
private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
|
||||||
{
|
{
|
||||||
var list = new List<Tuple<StringBuilder, bool>>();
|
var list = new List<Tuple<StringBuilder, bool>>();
|
||||||
|
@ -987,7 +966,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture);
|
ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
return System.IO.Path.Join(basePath, "library", idString.Slice(0, 2), idString);
|
return System.IO.Path.Join(basePath, "library", idString[..2], idString);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1302,8 +1281,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
terms.Add(item.Name);
|
terms.Add(item.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var video = item as Video;
|
if (item is Video video)
|
||||||
if (video != null)
|
|
||||||
{
|
{
|
||||||
if (video.Video3DFormat.HasValue)
|
if (video.Video3DFormat.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -1338,7 +1316,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Join('/', terms.ToArray());
|
return string.Join('/', terms);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1361,9 +1339,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.Select(audio =>
|
.Select(audio =>
|
||||||
{
|
{
|
||||||
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
||||||
var dbItem = LibraryManager.GetItemById(audio.Id) as Audio.Audio;
|
if (LibraryManager.GetItemById(audio.Id) is Audio.Audio dbItem)
|
||||||
|
|
||||||
if (dbItem != null)
|
|
||||||
{
|
{
|
||||||
audio = dbItem;
|
audio = dbItem;
|
||||||
}
|
}
|
||||||
|
@ -1570,8 +1546,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasTrailers = this as IHasTrailers;
|
if (this is IHasTrailers hasTrailers)
|
||||||
if (hasTrailers != null)
|
|
||||||
{
|
{
|
||||||
localTrailersChanged = await RefreshLocalTrailers(hasTrailers, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
localTrailersChanged = await RefreshLocalTrailers(hasTrailers, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -2268,7 +2243,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
var existingImage = GetImageInfo(image.Type, index);
|
var existingImage = GetImageInfo(image.Type, index);
|
||||||
|
|
||||||
if (existingImage != null)
|
if (existingImage == null)
|
||||||
|
{
|
||||||
|
AddImage(image);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
existingImage.Path = image.Path;
|
existingImage.Path = image.Path;
|
||||||
existingImage.DateModified = image.DateModified;
|
existingImage.DateModified = image.DateModified;
|
||||||
|
@ -2276,15 +2255,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
existingImage.Height = image.Height;
|
existingImage.Height = image.Height;
|
||||||
existingImage.BlurHash = image.BlurHash;
|
existingImage.BlurHash = image.BlurHash;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var current = ImageInfos;
|
|
||||||
var currentCount = current.Length;
|
|
||||||
var newArr = new ItemImageInfo[currentCount + 1];
|
|
||||||
current.CopyTo(newArr, 0);
|
|
||||||
newArr[currentCount] = image;
|
|
||||||
ImageInfos = newArr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
|
public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
|
||||||
|
@ -2298,7 +2268,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
if (image == null)
|
if (image == null)
|
||||||
{
|
{
|
||||||
ImageInfos = ImageInfos.Concat(new[] { GetImageInfo(file, type) }).ToArray();
|
AddImage(GetImageInfo(file, type));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2342,7 +2312,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
public void RemoveImage(ItemImageInfo image)
|
public void RemoveImage(ItemImageInfo image)
|
||||||
{
|
{
|
||||||
RemoveImages(new List<ItemImageInfo> { image });
|
RemoveImages(new[] { image });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveImages(IEnumerable<ItemImageInfo> deletedImages)
|
public void RemoveImages(IEnumerable<ItemImageInfo> deletedImages)
|
||||||
|
@ -2350,6 +2320,16 @@ namespace MediaBrowser.Controller.Entities
|
||||||
ImageInfos = ImageInfos.Except(deletedImages).ToArray();
|
ImageInfos = ImageInfos.Except(deletedImages).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddImage(ItemImageInfo image)
|
||||||
|
{
|
||||||
|
var current = ImageInfos;
|
||||||
|
var currentCount = current.Length;
|
||||||
|
var newArr = new ItemImageInfo[currentCount + 1];
|
||||||
|
current.CopyTo(newArr, 0);
|
||||||
|
newArr[currentCount] = image;
|
||||||
|
ImageInfos = newArr;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken)
|
public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||||
=> LibraryManager.UpdateItemAsync(this, GetParent(), updateReason, cancellationToken);
|
=> LibraryManager.UpdateItemAsync(this, GetParent(), updateReason, cancellationToken);
|
||||||
|
|
||||||
|
@ -2373,7 +2353,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
if (deletedImages.Count > 0)
|
if (deletedImages.Count > 0)
|
||||||
{
|
{
|
||||||
ImageInfos = ImageInfos.Except(deletedImages).ToArray();
|
RemoveImages(deletedImages);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deletedImages.Count > 0;
|
return deletedImages.Count > 0;
|
||||||
|
@ -2715,7 +2695,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
protected static string GetMappedPath(BaseItem item, string path, MediaProtocol? protocol)
|
protected static string GetMappedPath(BaseItem item, string path, MediaProtocol? protocol)
|
||||||
{
|
{
|
||||||
if (protocol.HasValue && protocol.Value == MediaProtocol.File)
|
if (protocol == MediaProtocol.File)
|
||||||
{
|
{
|
||||||
return LibraryManager.GetPathAfterNetworkSubstitution(path, item);
|
return LibraryManager.GetPathAfterNetworkSubstitution(path, item);
|
||||||
}
|
}
|
||||||
|
@ -2743,8 +2723,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
protected Task RefreshMetadataForOwnedItem(BaseItem ownedItem, bool copyTitleMetadata, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
protected Task RefreshMetadataForOwnedItem(BaseItem ownedItem, bool copyTitleMetadata, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var newOptions = new MetadataRefreshOptions(options);
|
var newOptions = new MetadataRefreshOptions(options)
|
||||||
newOptions.SearchResult = null;
|
{
|
||||||
|
SearchResult = null
|
||||||
|
};
|
||||||
|
|
||||||
var item = this;
|
var item = this;
|
||||||
|
|
||||||
|
@ -2805,8 +2787,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, bool copyTitleMetadata, string path, CancellationToken cancellationToken)
|
protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, bool copyTitleMetadata, string path, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var newOptions = new MetadataRefreshOptions(options);
|
var newOptions = new MetadataRefreshOptions(options)
|
||||||
newOptions.SearchResult = null;
|
{
|
||||||
|
SearchResult = null
|
||||||
|
};
|
||||||
|
|
||||||
var id = LibraryManager.GetNewItemId(path, typeof(Video));
|
var id = LibraryManager.GetNewItemId(path, typeof(Video));
|
||||||
|
|
||||||
|
@ -2820,14 +2804,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
newOptions.ForceSave = true;
|
newOptions.ForceSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// var parentId = Id;
|
|
||||||
// if (!video.IsOwnedItem || video.ParentId != parentId)
|
|
||||||
// {
|
|
||||||
// video.IsOwnedItem = true;
|
|
||||||
// video.ParentId = parentId;
|
|
||||||
// newOptions.ForceSave = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (video == null)
|
if (video == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
|
@ -2911,7 +2887,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.Select(i => i.OfficialRating)
|
.Select(i => i.OfficialRating)
|
||||||
.Where(i => !string.IsNullOrEmpty(i))
|
.Where(i => !string.IsNullOrEmpty(i))
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(i => new Tuple<string, int?>(i, LocalizationManager.GetRatingLevel(i)))
|
.Select(i => (i, LocalizationManager.GetRatingLevel(i)))
|
||||||
.OrderBy(i => i.Item2 ?? 1000)
|
.OrderBy(i => i.Item2 ?? 1000)
|
||||||
.Select(i => i.Item1);
|
.Select(i => i.Item1);
|
||||||
|
|
||||||
|
@ -2958,18 +2934,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.Where(i => i.ExtraType.HasValue && extraTypes.Contains(i.ExtraType.Value));
|
.Where(i => i.ExtraType.HasValue && extraTypes.Contains(i.ExtraType.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BaseItem> GetTrailers()
|
|
||||||
{
|
|
||||||
if (this is IHasTrailers)
|
|
||||||
{
|
|
||||||
return ((IHasTrailers)this).LocalTrailerIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Array.Empty<BaseItem>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual long GetRunTimeTicksForPlayState()
|
public virtual long GetRunTimeTicksForPlayState()
|
||||||
{
|
{
|
||||||
return RunTimeTicks ?? 0;
|
return RunTimeTicks ?? 0;
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace MediaBrowser.Controller.Entities
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The item has screenshots.
|
|
||||||
/// </summary>
|
|
||||||
public interface IHasScreenshots
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -256,11 +256,6 @@ namespace MediaBrowser.LocalMetadata.Images
|
||||||
{
|
{
|
||||||
PopulateBackdrops(item, images, files, imagePrefix, isInMixedFolder);
|
PopulateBackdrops(item, images, files, imagePrefix, isInMixedFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is IHasScreenshots)
|
|
||||||
{
|
|
||||||
PopulateScreenshots(images, files, imagePrefix, isInMixedFolder);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulatePrimaryImages(BaseItem item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
|
private void PopulatePrimaryImages(BaseItem item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
|
||||||
|
@ -363,11 +358,6 @@ namespace MediaBrowser.LocalMetadata.Images
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateScreenshots(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
|
|
||||||
{
|
|
||||||
PopulateBackdrops(images, files, imagePrefix, "screenshot", "screenshot", isInMixedFolder, ImageType.Screenshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
|
private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
|
||||||
{
|
{
|
||||||
AddImage(files, images, imagePrefix + firstFileName, type);
|
AddImage(files, images, imagePrefix + firstFileName, type);
|
||||||
|
|
|
@ -19,12 +19,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
writer.WriteLine("WEBVTT");
|
writer.WriteLine("WEBVTT");
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
writer.WriteLine("REGION");
|
writer.WriteLine("Region: id:subtitle width:80% lines:3 regionanchor:50%,100% viewportanchor:50%,90%");
|
||||||
writer.WriteLine("id:subtitle");
|
|
||||||
writer.WriteLine("width:80%");
|
|
||||||
writer.WriteLine("lines:3");
|
|
||||||
writer.WriteLine("regionanchor:50%,100%");
|
|
||||||
writer.WriteLine("viewportanchor:50%,90%");
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
foreach (var trackEvent in info.TrackEvents)
|
foreach (var trackEvent in info.TrackEvents)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +34,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
endTime = startTime.Add(TimeSpan.FromMilliseconds(1));
|
endTime = startTime.Add(TimeSpan.FromMilliseconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff} region:subtitle", startTime, endTime);
|
writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff} region:subtitle line:90%", startTime, endTime);
|
||||||
|
|
||||||
var text = trackEvent.Text;
|
var text = trackEvent.Text;
|
||||||
|
|
||||||
|
|
|
@ -343,12 +343,6 @@ namespace MediaBrowser.Providers.Manager
|
||||||
|
|
||||||
minWidth = savedOptions.GetMinWidth(ImageType.Backdrop);
|
minWidth = savedOptions.GetMinWidth(ImageType.Backdrop);
|
||||||
await DownloadMultiImages(item, ImageType.Backdrop, refreshOptions, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
|
await DownloadMultiImages(item, ImageType.Backdrop, refreshOptions, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (item is IHasScreenshots)
|
|
||||||
{
|
|
||||||
minWidth = savedOptions.GetMinWidth(ImageType.Screenshot);
|
|
||||||
await DownloadMultiImages(item, ImageType.Screenshot, refreshOptions, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
@ -438,11 +432,6 @@ namespace MediaBrowser.Providers.Manager
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is IHasScreenshots && UpdateMultiImages(item, images, ImageType.Screenshot))
|
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
|
|
||||||
|
@ -67,40 +66,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
|
||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var remoteImages = new List<RemoteImageInfo>();
|
var posters = collection.Images.Posters;
|
||||||
|
var backdrops = collection.Images.Backdrops;
|
||||||
|
var remoteImages = new List<RemoteImageInfo>(posters.Count + backdrops.Count);
|
||||||
|
|
||||||
for (var i = 0; i < collection.Images.Posters.Count; i++)
|
_tmdbClientManager.ConvertPostersToRemoteImageInfo(posters, language, remoteImages);
|
||||||
{
|
_tmdbClientManager.ConvertBackdropsToRemoteImageInfo(backdrops, language, remoteImages);
|
||||||
var poster = collection.Images.Posters[i];
|
|
||||||
remoteImages.Add(new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetPosterUrl(poster.FilePath),
|
|
||||||
CommunityRating = poster.VoteAverage,
|
|
||||||
VoteCount = poster.VoteCount,
|
|
||||||
Width = poster.Width,
|
|
||||||
Height = poster.Height,
|
|
||||||
Language = TmdbUtils.AdjustImageLanguage(poster.Iso_639_1, language),
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Primary,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < collection.Images.Backdrops.Count; i++)
|
|
||||||
{
|
|
||||||
var backdrop = collection.Images.Backdrops[i];
|
|
||||||
remoteImages.Add(new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetBackdropUrl(backdrop.FilePath),
|
|
||||||
CommunityRating = backdrop.VoteAverage,
|
|
||||||
VoteCount = backdrop.VoteCount,
|
|
||||||
Width = backdrop.Width,
|
|
||||||
Height = backdrop.Height,
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Backdrop,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteImages;
|
return remoteImages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,5 +21,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||||
/// Gets or sets a value indicating whether tags should be imported for movies from TMDb.
|
/// Gets or sets a value indicating whether tags should be imported for movies from TMDb.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ExcludeTagsMovies { get; set; }
|
public bool ExcludeTagsMovies { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating the maximum number of cast members to fetch for an item.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxCastMembers { get; set; } = 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,18 @@
|
||||||
<input is="emby-checkbox" type="checkbox" id="includeAdult" />
|
<input is="emby-checkbox" type="checkbox" id="includeAdult" />
|
||||||
<span>Include adult content in search results.</span>
|
<span>Include adult content in search results.</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="checkboxContainer">
|
||||||
|
<input is="emby-checkbox" type="checkbox" id="excludeTagsSeries" />
|
||||||
|
<span>Exclude tags/keywords from metadata fetched for series.</span>
|
||||||
|
</label>
|
||||||
|
<label class="checkboxContainer">
|
||||||
|
<input is="emby-checkbox" type="checkbox" id="excludeTagsMovies" />
|
||||||
|
<span>Exclude tags/keywords from metadata fetched for movies.</span>
|
||||||
|
</label>
|
||||||
|
<div class="inputContainer">
|
||||||
|
<input is="emby-input" type="number" id="maxCastMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Cast Members" />
|
||||||
|
<div class="fieldDescription">The maximum number of cast members to fetch for an item.</div>
|
||||||
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
|
<button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
|
||||||
|
@ -31,6 +43,14 @@
|
||||||
document.querySelector('#includeAdult').checked = config.IncludeAdult;
|
document.querySelector('#includeAdult').checked = config.IncludeAdult;
|
||||||
document.querySelector('#excludeTagsSeries').checked = config.ExcludeTagsSeries;
|
document.querySelector('#excludeTagsSeries').checked = config.ExcludeTagsSeries;
|
||||||
document.querySelector('#excludeTagsMovies').checked = config.ExcludeTagsMovies;
|
document.querySelector('#excludeTagsMovies').checked = config.ExcludeTagsMovies;
|
||||||
|
|
||||||
|
var maxCastMembers = document.querySelector('#maxCastMembers');
|
||||||
|
maxCastMembers.value = config.MaxCastMembers;
|
||||||
|
maxCastMembers.dispatchEvent(new Event('change', {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: false
|
||||||
|
}));
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
Dashboard.hideLoadingMsg();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -44,6 +64,7 @@
|
||||||
config.IncludeAdult = document.querySelector('#includeAdult').checked;
|
config.IncludeAdult = document.querySelector('#includeAdult').checked;
|
||||||
config.ExcludeTagsSeries = document.querySelector('#excludeTagsSeries').checked;
|
config.ExcludeTagsSeries = document.querySelector('#excludeTagsSeries').checked;
|
||||||
config.ExcludeTagsMovies = document.querySelector('#excludeTagsMovies').checked;
|
config.ExcludeTagsMovies = document.querySelector('#excludeTagsMovies').checked;
|
||||||
|
config.MaxCastMembers = document.querySelector('#maxCastMembers').value;
|
||||||
ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
using TMDbLib.Objects.Find;
|
using TMDbLib.Objects.Find;
|
||||||
|
@ -84,40 +83,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
|
||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var remoteImages = new List<RemoteImageInfo>();
|
var posters = movie.Images.Posters;
|
||||||
|
var backdrops = movie.Images.Backdrops;
|
||||||
|
var remoteImages = new List<RemoteImageInfo>(posters.Count + backdrops.Count);
|
||||||
|
|
||||||
for (var i = 0; i < movie.Images.Posters.Count; i++)
|
_tmdbClientManager.ConvertPostersToRemoteImageInfo(posters, language, remoteImages);
|
||||||
{
|
_tmdbClientManager.ConvertBackdropsToRemoteImageInfo(backdrops, language, remoteImages);
|
||||||
var poster = movie.Images.Posters[i];
|
|
||||||
remoteImages.Add(new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetPosterUrl(poster.FilePath),
|
|
||||||
CommunityRating = poster.VoteAverage,
|
|
||||||
VoteCount = poster.VoteCount,
|
|
||||||
Width = poster.Width,
|
|
||||||
Height = poster.Height,
|
|
||||||
Language = TmdbUtils.AdjustImageLanguage(poster.Iso_639_1, language),
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Primary,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < movie.Images.Backdrops.Count; i++)
|
|
||||||
{
|
|
||||||
var backdrop = movie.Images.Backdrops[i];
|
|
||||||
remoteImages.Add(new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetPosterUrl(backdrop.FilePath),
|
|
||||||
CommunityRating = backdrop.VoteAverage,
|
|
||||||
VoteCount = backdrop.VoteCount,
|
|
||||||
Width = backdrop.Width,
|
|
||||||
Height = backdrop.Height,
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Backdrop,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteImages;
|
return remoteImages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,8 +241,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
|
||||||
|
|
||||||
if (movieResult.Credits?.Cast != null)
|
if (movieResult.Credits?.Cast != null)
|
||||||
{
|
{
|
||||||
// TODO configurable
|
foreach (var actor in movieResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
|
||||||
foreach (var actor in movieResult.Credits.Cast.OrderBy(a => a.Order).Take(TmdbUtils.MaxCastMembers))
|
|
||||||
{
|
{
|
||||||
var personInfo = new PersonInfo
|
var personInfo = new PersonInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,21 +60,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
|
||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var remoteImages = new RemoteImageInfo[personResult.Images.Profiles.Count];
|
var profiles = personResult.Images.Profiles;
|
||||||
|
var remoteImages = new List<RemoteImageInfo>(profiles.Count);
|
||||||
|
|
||||||
for (var i = 0; i < personResult.Images.Profiles.Count; i++)
|
_tmdbClientManager.ConvertProfilesToRemoteImageInfo(profiles, language, remoteImages);
|
||||||
{
|
|
||||||
var image = personResult.Images.Profiles[i];
|
|
||||||
remoteImages[i] = new RemoteImageInfo
|
|
||||||
{
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Primary,
|
|
||||||
Width = image.Width,
|
|
||||||
Height = image.Height,
|
|
||||||
Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language),
|
|
||||||
Url = _tmdbClientManager.GetProfileUrl(image.FilePath)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteImages;
|
return remoteImages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
|
|
||||||
|
@ -75,23 +74,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var remoteImages = new RemoteImageInfo[stills.Count];
|
var remoteImages = new List<RemoteImageInfo>(stills.Count);
|
||||||
for (var i = 0; i < stills.Count; i++)
|
|
||||||
{
|
_tmdbClientManager.ConvertStillsToRemoteImageInfo(stills, language, remoteImages);
|
||||||
var image = stills[i];
|
|
||||||
remoteImages[i] = new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetStillUrl(image.FilePath),
|
|
||||||
CommunityRating = image.VoteAverage,
|
|
||||||
VoteCount = image.VoteCount,
|
|
||||||
Width = image.Width,
|
|
||||||
Height = image.Height,
|
|
||||||
Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language),
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Primary,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteImages;
|
return remoteImages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
|
|
||||||
if (credits?.Cast != null)
|
if (credits?.Cast != null)
|
||||||
{
|
{
|
||||||
foreach (var actor in credits.Cast.OrderBy(a => a.Order).Take(TmdbUtils.MaxCastMembers))
|
foreach (var actor in credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
|
||||||
{
|
{
|
||||||
metadataResult.AddPerson(new PersonInfo
|
metadataResult.AddPerson(new PersonInfo
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
|
|
||||||
if (credits?.GuestStars != null)
|
if (credits?.GuestStars != null)
|
||||||
{
|
{
|
||||||
foreach (var guest in credits.GuestStars.OrderBy(a => a.Order).Take(TmdbUtils.MaxCastMembers))
|
foreach (var guest in credits.GuestStars.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
|
||||||
{
|
{
|
||||||
metadataResult.AddPerson(new PersonInfo
|
metadataResult.AddPerson(new PersonInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,6 @@ using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
|
|
||||||
|
@ -62,23 +61,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var remoteImages = new RemoteImageInfo[posters.Count];
|
var remoteImages = new List<RemoteImageInfo>(posters.Count);
|
||||||
for (var i = 0; i < posters.Count; i++)
|
|
||||||
{
|
_tmdbClientManager.ConvertPostersToRemoteImageInfo(posters, language, remoteImages);
|
||||||
var image = posters[i];
|
|
||||||
remoteImages[i] = new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetPosterUrl(image.FilePath),
|
|
||||||
CommunityRating = image.VoteAverage,
|
|
||||||
VoteCount = image.VoteCount,
|
|
||||||
Width = image.Width,
|
|
||||||
Height = image.Height,
|
|
||||||
Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language),
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Primary,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteImages;
|
return remoteImages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
var credits = seasonResult.Credits;
|
var credits = seasonResult.Credits;
|
||||||
if (credits?.Cast != null)
|
if (credits?.Cast != null)
|
||||||
{
|
{
|
||||||
var cast = credits.Cast.OrderBy(c => c.Order).Take(TmdbUtils.MaxCastMembers).ToList();
|
var cast = credits.Cast.OrderBy(c => c.Order).Take(Plugin.Instance.Configuration.MaxCastMembers).ToList();
|
||||||
for (var i = 0; i < cast.Count; i++)
|
for (var i = 0; i < cast.Count; i++)
|
||||||
{
|
{
|
||||||
result.AddPerson(new PersonInfo
|
result.AddPerson(new PersonInfo
|
||||||
|
|
|
@ -11,7 +11,6 @@ using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
|
|
||||||
|
@ -70,41 +69,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
|
|
||||||
var posters = series.Images.Posters;
|
var posters = series.Images.Posters;
|
||||||
var backdrops = series.Images.Backdrops;
|
var backdrops = series.Images.Backdrops;
|
||||||
|
var remoteImages = new List<RemoteImageInfo>(posters.Count + backdrops.Count);
|
||||||
|
|
||||||
var remoteImages = new RemoteImageInfo[posters.Count + backdrops.Count];
|
_tmdbClientManager.ConvertPostersToRemoteImageInfo(posters, language, remoteImages);
|
||||||
|
_tmdbClientManager.ConvertBackdropsToRemoteImageInfo(backdrops, language, remoteImages);
|
||||||
for (var i = 0; i < posters.Count; i++)
|
|
||||||
{
|
|
||||||
var poster = posters[i];
|
|
||||||
remoteImages[i] = new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetPosterUrl(poster.FilePath),
|
|
||||||
CommunityRating = poster.VoteAverage,
|
|
||||||
VoteCount = poster.VoteCount,
|
|
||||||
Width = poster.Width,
|
|
||||||
Height = poster.Height,
|
|
||||||
Language = TmdbUtils.AdjustImageLanguage(poster.Iso_639_1, language),
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Primary,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < backdrops.Count; i++)
|
|
||||||
{
|
|
||||||
var backdrop = series.Images.Backdrops[i];
|
|
||||||
remoteImages[posters.Count + i] = new RemoteImageInfo
|
|
||||||
{
|
|
||||||
Url = _tmdbClientManager.GetBackdropUrl(backdrop.FilePath),
|
|
||||||
CommunityRating = backdrop.VoteAverage,
|
|
||||||
VoteCount = backdrop.VoteCount,
|
|
||||||
Width = backdrop.Width,
|
|
||||||
Height = backdrop.Height,
|
|
||||||
ProviderName = Name,
|
|
||||||
Type = ImageType.Backdrop,
|
|
||||||
RatingType = RatingType.Score
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteImages;
|
return remoteImages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,7 +331,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||||
{
|
{
|
||||||
if (seriesResult.Credits?.Cast != null)
|
if (seriesResult.Credits?.Cast != null)
|
||||||
{
|
{
|
||||||
foreach (var actor in seriesResult.Credits.Cast.OrderBy(a => a.Order).Take(TmdbUtils.MaxCastMembers))
|
foreach (var actor in seriesResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
|
||||||
{
|
{
|
||||||
var personInfo = new PersonInfo
|
var personInfo = new PersonInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Providers;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using TMDbLib.Client;
|
using TMDbLib.Client;
|
||||||
using TMDbLib.Objects.Collections;
|
using TMDbLib.Objects.Collections;
|
||||||
|
@ -482,6 +485,22 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||||
return searchResults.Results;
|
return searchResults.Results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles bad path checking and builds the absolute url.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">The image size to fetch.</param>
|
||||||
|
/// <param name="path">The relative URL of the image.</param>
|
||||||
|
/// <returns>The absolute URL.</returns>
|
||||||
|
private string GetUrl(string size, string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _tmDbClient.GetImageUrl(size, path).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the absolute URL of the poster.
|
/// Gets the absolute URL of the poster.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -489,27 +508,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||||
/// <returns>The absolute URL.</returns>
|
/// <returns>The absolute URL.</returns>
|
||||||
public string GetPosterUrl(string posterPath)
|
public string GetPosterUrl(string posterPath)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(posterPath))
|
return GetUrl(_tmDbClient.Config.Images.PosterSizes[^1], posterPath);
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _tmDbClient.GetImageUrl(_tmDbClient.Config.Images.PosterSizes[^1], posterPath).ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the absolute URL of the backdrop image.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="posterPath">The relative URL of the backdrop image.</param>
|
|
||||||
/// <returns>The absolute URL.</returns>
|
|
||||||
public string GetBackdropUrl(string posterPath)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(posterPath))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _tmDbClient.GetImageUrl(_tmDbClient.Config.Images.BackdropSizes[^1], posterPath).ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -519,27 +518,79 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||||
/// <returns>The absolute URL.</returns>
|
/// <returns>The absolute URL.</returns>
|
||||||
public string GetProfileUrl(string actorProfilePath)
|
public string GetProfileUrl(string actorProfilePath)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(actorProfilePath))
|
return GetUrl(_tmDbClient.Config.Images.ProfileSizes[^1], actorProfilePath);
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _tmDbClient.GetImageUrl(_tmDbClient.Config.Images.ProfileSizes[^1], actorProfilePath).ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the absolute URL of the still image.
|
/// Converts poster <see cref="ImageData"/>s into <see cref="RemoteImageInfo"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath">The relative URL of the still image.</param>
|
/// <param name="images">The input images.</param>
|
||||||
/// <returns>The absolute URL.</returns>
|
/// <param name="requestLanguage">The requested language.</param>
|
||||||
public string GetStillUrl(string filePath)
|
/// <param name="results">The collection to add the remote images into.</param>
|
||||||
|
public void ConvertPostersToRemoteImageInfo(List<ImageData> images, string requestLanguage, List<RemoteImageInfo> results)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(filePath))
|
ConvertToRemoteImageInfo(images, _tmDbClient.Config.Images.PosterSizes[^1], ImageType.Primary, requestLanguage, results);
|
||||||
{
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _tmDbClient.GetImageUrl(_tmDbClient.Config.Images.StillSizes[^1], filePath).ToString();
|
/// <summary>
|
||||||
|
/// Converts backdrop <see cref="ImageData"/>s into <see cref="RemoteImageInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="images">The input images.</param>
|
||||||
|
/// <param name="requestLanguage">The requested language.</param>
|
||||||
|
/// <param name="results">The collection to add the remote images into.</param>
|
||||||
|
public void ConvertBackdropsToRemoteImageInfo(List<ImageData> images, string requestLanguage, List<RemoteImageInfo> results)
|
||||||
|
{
|
||||||
|
ConvertToRemoteImageInfo(images, _tmDbClient.Config.Images.BackdropSizes[^1], ImageType.Backdrop, requestLanguage, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts profile <see cref="ImageData"/>s into <see cref="RemoteImageInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="images">The input images.</param>
|
||||||
|
/// <param name="requestLanguage">The requested language.</param>
|
||||||
|
/// <param name="results">The collection to add the remote images into.</param>
|
||||||
|
public void ConvertProfilesToRemoteImageInfo(List<ImageData> images, string requestLanguage, List<RemoteImageInfo> results)
|
||||||
|
{
|
||||||
|
ConvertToRemoteImageInfo(images, _tmDbClient.Config.Images.ProfileSizes[^1], ImageType.Primary, requestLanguage, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts still <see cref="ImageData"/>s into <see cref="RemoteImageInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="images">The input images.</param>
|
||||||
|
/// <param name="requestLanguage">The requested language.</param>
|
||||||
|
/// <param name="results">The collection to add the remote images into.</param>
|
||||||
|
public void ConvertStillsToRemoteImageInfo(List<ImageData> images, string requestLanguage, List<RemoteImageInfo> results)
|
||||||
|
{
|
||||||
|
ConvertToRemoteImageInfo(images, _tmDbClient.Config.Images.StillSizes[^1], ImageType.Primary, requestLanguage, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts <see cref="ImageData"/>s into <see cref="RemoteImageInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="images">The input images.</param>
|
||||||
|
/// <param name="size">The size of the image to fetch.</param>
|
||||||
|
/// <param name="type">The type of the image.</param>
|
||||||
|
/// <param name="requestLanguage">The requested language.</param>
|
||||||
|
/// <param name="results">The collection to add the remote images into.</param>
|
||||||
|
private void ConvertToRemoteImageInfo(List<ImageData> images, string size, ImageType type, string requestLanguage, List<RemoteImageInfo> results)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < images.Count; i++)
|
||||||
|
{
|
||||||
|
var image = images[i];
|
||||||
|
results.Add(new RemoteImageInfo
|
||||||
|
{
|
||||||
|
Url = GetUrl(size, image.FilePath),
|
||||||
|
CommunityRating = image.VoteAverage,
|
||||||
|
VoteCount = image.VoteCount,
|
||||||
|
Width = image.Width,
|
||||||
|
Height = image.Height,
|
||||||
|
Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, requestLanguage),
|
||||||
|
ProviderName = TmdbUtils.ProviderName,
|
||||||
|
Type = type,
|
||||||
|
RatingType = RatingType.Score
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task EnsureClientConfigAsync()
|
private Task EnsureClientConfigAsync()
|
||||||
|
@ -554,7 +605,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||||
|
|
|
@ -28,11 +28,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ApiKey = "4219e299c89411838049ab0dab19ebd5";
|
public const string ApiKey = "4219e299c89411838049ab0dab19ebd5";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maximum number of cast members to pull.
|
|
||||||
/// </summary>
|
|
||||||
public const int MaxCastMembers = 15;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The crew types to keep.
|
/// The crew types to keep.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -785,7 +785,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
||||||
case "fanart":
|
case "fanart":
|
||||||
{
|
{
|
||||||
var subtree = reader.ReadSubtree();
|
var subtree = reader.ReadSubtree();
|
||||||
subtree.ReadToDescendant("thumb");
|
if (!subtree.ReadToDescendant("thumb"))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
FetchThumbNode(subtree, itemResult);
|
FetchThumbNode(subtree, itemResult);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
@ -28,13 +27,13 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
{
|
{
|
||||||
public class ItemImageProviderTests
|
public class ItemImageProviderTests
|
||||||
{
|
{
|
||||||
private static readonly string TestDataImagePath = "Test Data/Images/blank{0}.jpg";
|
private const string TestDataImagePath = "Test Data/Images/blank{0}.jpg";
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ValidateImages_PhotoEmptyProviders_NoChange()
|
public void ValidateImages_PhotoEmptyProviders_NoChange()
|
||||||
{
|
{
|
||||||
var itemImageProvider = GetItemImageProvider(null, null);
|
var itemImageProvider = GetItemImageProvider(null, null);
|
||||||
var changed = itemImageProvider.ValidateImages(new Photo(), new List<ILocalImageProvider>(), null);
|
var changed = itemImageProvider.ValidateImages(new Photo(), Enumerable.Empty<ILocalImageProvider>(), null);
|
||||||
|
|
||||||
Assert.False(changed);
|
Assert.False(changed);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +42,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
public void ValidateImages_EmptyItemEmptyProviders_NoChange()
|
public void ValidateImages_EmptyItemEmptyProviders_NoChange()
|
||||||
{
|
{
|
||||||
var itemImageProvider = GetItemImageProvider(null, null);
|
var itemImageProvider = GetItemImageProvider(null, null);
|
||||||
var changed = itemImageProvider.ValidateImages(new MovieWithScreenshots(), new List<ILocalImageProvider>(), null);
|
var changed = itemImageProvider.ValidateImages(new Video(), Enumerable.Empty<ILocalImageProvider>(), null);
|
||||||
|
|
||||||
Assert.False(changed);
|
Assert.False(changed);
|
||||||
}
|
}
|
||||||
|
@ -55,8 +54,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
// minimal test cases that hit different handling
|
// minimal test cases that hit different handling
|
||||||
{ ImageType.Primary, 1 },
|
{ ImageType.Primary, 1 },
|
||||||
{ ImageType.Backdrop, 1 },
|
{ ImageType.Backdrop, 1 },
|
||||||
{ ImageType.Backdrop, 2 },
|
{ ImageType.Backdrop, 2 }
|
||||||
{ ImageType.Screenshot, 1 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return theoryTypes;
|
return theoryTypes;
|
||||||
|
@ -69,11 +67,11 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
||||||
BaseItem.FileSystem = Mock.Of<IFileSystem>();
|
BaseItem.FileSystem = Mock.Of<IFileSystem>();
|
||||||
|
|
||||||
var item = new MovieWithScreenshots();
|
var item = new Video();
|
||||||
var imageProvider = GetImageProvider(imageType, imageCount, true);
|
var imageProvider = GetImageProvider(imageType, imageCount, true);
|
||||||
|
|
||||||
var itemImageProvider = GetItemImageProvider(null, null);
|
var itemImageProvider = GetItemImageProvider(null, null);
|
||||||
var changed = itemImageProvider.ValidateImages(item, new List<ILocalImageProvider> { imageProvider }, null);
|
var changed = itemImageProvider.ValidateImages(item, new[] { imageProvider }, null);
|
||||||
|
|
||||||
Assert.True(changed);
|
Assert.True(changed);
|
||||||
Assert.Equal(imageCount, item.GetImages(imageType).Count());
|
Assert.Equal(imageCount, item.GetImages(imageType).Count());
|
||||||
|
@ -86,7 +84,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
var item = GetItemWithImages(imageType, imageCount, true);
|
var item = GetItemWithImages(imageType, imageCount, true);
|
||||||
|
|
||||||
var itemImageProvider = GetItemImageProvider(null, null);
|
var itemImageProvider = GetItemImageProvider(null, null);
|
||||||
var changed = itemImageProvider.ValidateImages(item, new List<ILocalImageProvider>(), null);
|
var changed = itemImageProvider.ValidateImages(item, Enumerable.Empty<ILocalImageProvider>(), null);
|
||||||
|
|
||||||
Assert.False(changed);
|
Assert.False(changed);
|
||||||
Assert.Equal(imageCount, item.GetImages(imageType).Count());
|
Assert.Equal(imageCount, item.GetImages(imageType).Count());
|
||||||
|
@ -99,7 +97,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
var item = GetItemWithImages(imageType, imageCount, false);
|
var item = GetItemWithImages(imageType, imageCount, false);
|
||||||
|
|
||||||
var itemImageProvider = GetItemImageProvider(null, null);
|
var itemImageProvider = GetItemImageProvider(null, null);
|
||||||
var changed = itemImageProvider.ValidateImages(item, new List<ILocalImageProvider>(), null);
|
var changed = itemImageProvider.ValidateImages(item, Enumerable.Empty<ILocalImageProvider>(), null);
|
||||||
|
|
||||||
Assert.True(changed);
|
Assert.True(changed);
|
||||||
Assert.Empty(item.GetImages(imageType));
|
Assert.Empty(item.GetImages(imageType));
|
||||||
|
@ -109,7 +107,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
public void MergeImages_EmptyItemNewImagesEmpty_NoChange()
|
public void MergeImages_EmptyItemNewImagesEmpty_NoChange()
|
||||||
{
|
{
|
||||||
var itemImageProvider = GetItemImageProvider(null, null);
|
var itemImageProvider = GetItemImageProvider(null, null);
|
||||||
var changed = itemImageProvider.MergeImages(new MovieWithScreenshots(), new List<LocalImageInfo>());
|
var changed = itemImageProvider.MergeImages(new Video(), Array.Empty<LocalImageInfo>());
|
||||||
|
|
||||||
Assert.False(changed);
|
Assert.False(changed);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +235,8 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
var refreshOptions = forceRefresh
|
var refreshOptions = forceRefresh
|
||||||
? new ImageRefreshOptions(null)
|
? new ImageRefreshOptions(null)
|
||||||
{
|
{
|
||||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh, ReplaceAllImages = true
|
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
|
ReplaceAllImages = true
|
||||||
}
|
}
|
||||||
: new ImageRefreshOptions(null);
|
: new ImageRefreshOptions(null);
|
||||||
|
|
||||||
|
@ -269,7 +268,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
||||||
BaseItem.FileSystem = Mock.Of<IFileSystem>();
|
BaseItem.FileSystem = Mock.Of<IFileSystem>();
|
||||||
|
|
||||||
var item = new MovieWithScreenshots();
|
var item = new Video();
|
||||||
|
|
||||||
var libraryOptions = GetLibraryOptions(item, imageType, imageCount);
|
var libraryOptions = GetLibraryOptions(item, imageType, imageCount);
|
||||||
|
|
||||||
|
@ -311,11 +310,9 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
[InlineData(ImageType.Primary, 1, false)]
|
[InlineData(ImageType.Primary, 1, false)]
|
||||||
[InlineData(ImageType.Backdrop, 1, false)]
|
[InlineData(ImageType.Backdrop, 1, false)]
|
||||||
[InlineData(ImageType.Backdrop, 2, false)]
|
[InlineData(ImageType.Backdrop, 2, false)]
|
||||||
[InlineData(ImageType.Screenshot, 2, false)]
|
|
||||||
[InlineData(ImageType.Primary, 1, true)]
|
[InlineData(ImageType.Primary, 1, true)]
|
||||||
[InlineData(ImageType.Backdrop, 1, true)]
|
[InlineData(ImageType.Backdrop, 1, true)]
|
||||||
[InlineData(ImageType.Backdrop, 2, true)]
|
[InlineData(ImageType.Backdrop, 2, true)]
|
||||||
[InlineData(ImageType.Screenshot, 2, true)]
|
|
||||||
public async void RefreshImages_PopulatedItemPopulatedProviderRemote_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh)
|
public async void RefreshImages_PopulatedItemPopulatedProviderRemote_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh)
|
||||||
{
|
{
|
||||||
var item = GetItemWithImages(imageType, imageCount, false);
|
var item = GetItemWithImages(imageType, imageCount, false);
|
||||||
|
@ -330,19 +327,20 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
var refreshOptions = forceRefresh
|
var refreshOptions = forceRefresh
|
||||||
? new ImageRefreshOptions(null)
|
? new ImageRefreshOptions(null)
|
||||||
{
|
{
|
||||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh, ReplaceAllImages = true
|
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
|
ReplaceAllImages = true
|
||||||
}
|
}
|
||||||
: new ImageRefreshOptions(null);
|
: new ImageRefreshOptions(null);
|
||||||
|
|
||||||
var remoteInfo = new List<RemoteImageInfo>();
|
var remoteInfo = new RemoteImageInfo[imageCount];
|
||||||
for (int i = 0; i < imageCount; i++)
|
for (int i = 0; i < imageCount; i++)
|
||||||
{
|
{
|
||||||
remoteInfo.Add(new RemoteImageInfo
|
remoteInfo[i] = new RemoteImageInfo
|
||||||
{
|
{
|
||||||
Type = imageType,
|
Type = imageType,
|
||||||
Url = "image url " + i,
|
Url = "image url " + i,
|
||||||
Width = 1 // min width is set to 0, this will always pass
|
Width = 1 // min width is set to 0, this will always pass
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var providerManager = new Mock<IProviderManager>(MockBehavior.Strict);
|
var providerManager = new Mock<IProviderManager>(MockBehavior.Strict);
|
||||||
|
@ -383,7 +381,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
// seek 2 so it won't short-circuit out of downloading when populated
|
// seek 2 so it won't short-circuit out of downloading when populated
|
||||||
var libraryOptions = GetLibraryOptions(item, imageType, 2);
|
var libraryOptions = GetLibraryOptions(item, imageType, 2);
|
||||||
|
|
||||||
var content = "Content";
|
const string Content = "Content";
|
||||||
var remoteProvider = new Mock<IRemoteImageProvider>(MockBehavior.Strict);
|
var remoteProvider = new Mock<IRemoteImageProvider>(MockBehavior.Strict);
|
||||||
remoteProvider.Setup(rp => rp.Name).Returns("MockRemoteProvider");
|
remoteProvider.Setup(rp => rp.Name).Returns("MockRemoteProvider");
|
||||||
remoteProvider.Setup(rp => rp.GetSupportedImages(item))
|
remoteProvider.Setup(rp => rp.GetSupportedImages(item))
|
||||||
|
@ -393,7 +391,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
{
|
{
|
||||||
ReasonPhrase = url,
|
ReasonPhrase = url,
|
||||||
StatusCode = HttpStatusCode.OK,
|
StatusCode = HttpStatusCode.OK,
|
||||||
Content = new StringContent(content, Encoding.UTF8, "image/jpeg")
|
Content = new StringContent(Content, Encoding.UTF8, "image/jpeg")
|
||||||
});
|
});
|
||||||
|
|
||||||
var refreshOptions = fullRefresh
|
var refreshOptions = fullRefresh
|
||||||
|
@ -404,15 +402,15 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
}
|
}
|
||||||
: new ImageRefreshOptions(null);
|
: new ImageRefreshOptions(null);
|
||||||
|
|
||||||
var remoteInfo = new List<RemoteImageInfo>();
|
var remoteInfo = new RemoteImageInfo[targetImageCount];
|
||||||
for (int i = 0; i < targetImageCount; i++)
|
for (int i = 0; i < targetImageCount; i++)
|
||||||
{
|
{
|
||||||
remoteInfo.Add(new RemoteImageInfo
|
remoteInfo[i] = new RemoteImageInfo()
|
||||||
{
|
{
|
||||||
Type = imageType,
|
Type = imageType,
|
||||||
Url = "image url " + i,
|
Url = "image url " + i,
|
||||||
Width = 1 // min width is set to 0, this will always pass
|
Width = 1 // min width is set to 0, this will always pass
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var providerManager = new Mock<IProviderManager>(MockBehavior.Strict);
|
var providerManager = new Mock<IProviderManager>(MockBehavior.Strict);
|
||||||
|
@ -425,7 +423,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
var fileSystem = new Mock<IFileSystem>();
|
var fileSystem = new Mock<IFileSystem>();
|
||||||
// match reported file size to image content length - condition for skipping already downloaded multi-images
|
// match reported file size to image content length - condition for skipping already downloaded multi-images
|
||||||
fileSystem.Setup(fs => fs.GetFileInfo(It.IsAny<string>()))
|
fileSystem.Setup(fs => fs.GetFileInfo(It.IsAny<string>()))
|
||||||
.Returns(new FileSystemMetadata { Length = content.Length });
|
.Returns(new FileSystemMetadata { Length = Content.Length });
|
||||||
var itemImageProvider = GetItemImageProvider(providerManager.Object, fileSystem);
|
var itemImageProvider = GetItemImageProvider(providerManager.Object, fileSystem);
|
||||||
var result = await itemImageProvider.RefreshImages(item, libraryOptions, new List<IImageProvider> { remoteProvider.Object }, refreshOptions, CancellationToken.None);
|
var result = await itemImageProvider.RefreshImages(item, libraryOptions, new List<IImageProvider> { remoteProvider.Object }, refreshOptions, CancellationToken.None);
|
||||||
|
|
||||||
|
@ -437,7 +435,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
[MemberData(nameof(GetImageTypesWithCount))]
|
[MemberData(nameof(GetImageTypesWithCount))]
|
||||||
public async void RefreshImages_EmptyItemPopulatedProviderRemoteExtras_LimitsImages(ImageType imageType, int imageCount)
|
public async void RefreshImages_EmptyItemPopulatedProviderRemoteExtras_LimitsImages(ImageType imageType, int imageCount)
|
||||||
{
|
{
|
||||||
var item = new MovieWithScreenshots();
|
var item = new Video();
|
||||||
|
|
||||||
var libraryOptions = GetLibraryOptions(item, imageType, imageCount);
|
var libraryOptions = GetLibraryOptions(item, imageType, imageCount);
|
||||||
|
|
||||||
|
@ -449,15 +447,16 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
var refreshOptions = new ImageRefreshOptions(null);
|
var refreshOptions = new ImageRefreshOptions(null);
|
||||||
|
|
||||||
// populate remote with double the required images to verify count is trimmed to the library option count
|
// populate remote with double the required images to verify count is trimmed to the library option count
|
||||||
var remoteInfo = new List<RemoteImageInfo>();
|
var remoteInfoCount = imageCount * 2;
|
||||||
for (int i = 0; i < imageCount * 2; i++)
|
var remoteInfo = new RemoteImageInfo[remoteInfoCount];
|
||||||
|
for (int i = 0; i < remoteInfoCount; i++)
|
||||||
{
|
{
|
||||||
remoteInfo.Add(new RemoteImageInfo
|
remoteInfo[i] = new RemoteImageInfo()
|
||||||
{
|
{
|
||||||
Type = imageType,
|
Type = imageType,
|
||||||
Url = "image url " + i,
|
Url = "image url " + i,
|
||||||
Width = 1 // min width is set to 0, this will always pass
|
Width = 1 // min width is set to 0, this will always pass
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var providerManager = new Mock<IProviderManager>(MockBehavior.Strict);
|
var providerManager = new Mock<IProviderManager>(MockBehavior.Strict);
|
||||||
|
@ -525,7 +524,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
||||||
BaseItem.FileSystem ??= Mock.Of<IFileSystem>();
|
BaseItem.FileSystem ??= Mock.Of<IFileSystem>();
|
||||||
|
|
||||||
var item = new MovieWithScreenshots();
|
var item = new Video();
|
||||||
|
|
||||||
var path = validPaths ? TestDataImagePath : "invalid path {0}";
|
var path = validPaths ? TestDataImagePath : "invalid path {0}";
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
|
@ -552,20 +551,20 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a list of <see cref="LocalImageInfo"/> references of the specified type and size, optionally pointing to files that exist.
|
/// Creates a list of <see cref="LocalImageInfo"/> references of the specified type and size, optionally pointing to files that exist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static List<LocalImageInfo> GetImages(ImageType type, int count, bool validPaths)
|
private static LocalImageInfo[] GetImages(ImageType type, int count, bool validPaths)
|
||||||
{
|
{
|
||||||
var path = validPaths ? TestDataImagePath : "invalid path {0}";
|
var path = validPaths ? TestDataImagePath : "invalid path {0}";
|
||||||
var images = new List<LocalImageInfo>(count);
|
var images = new LocalImageInfo[count];
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
images.Add(new LocalImageInfo
|
images[i] = new LocalImageInfo
|
||||||
{
|
{
|
||||||
Type = type,
|
Type = type,
|
||||||
FileInfo = new FileSystemMetadata
|
FileInfo = new FileSystemMetadata
|
||||||
{
|
{
|
||||||
FullName = string.Format(CultureInfo.InvariantCulture, path, i)
|
FullName = string.Format(CultureInfo.InvariantCulture, path, i)
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return images;
|
return images;
|
||||||
|
@ -596,11 +595,5 @@ namespace Jellyfin.Providers.Tests.Manager
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a class that implements IHasScreenshots for testing since no BaseItem class is also IHasScreenshots
|
|
||||||
private class MovieWithScreenshots : Movie, IHasScreenshots
|
|
||||||
{
|
|
||||||
// No contents
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,18 @@ namespace Jellyfin.Providers.Tests.Tmdb
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, TmdbUtils.NormalizeLanguage(input!));
|
Assert.Equal(expected, TmdbUtils.NormalizeLanguage(input!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(null, null, null)]
|
||||||
|
[InlineData(null, "en-US", null)]
|
||||||
|
[InlineData("en", null, "en")]
|
||||||
|
[InlineData("en", "en-US", "en-US")]
|
||||||
|
[InlineData("fr-CA", "fr-BE", "fr-CA")]
|
||||||
|
[InlineData("fr-CA", "fr", "fr-CA")]
|
||||||
|
[InlineData("de", "en-US", "de")]
|
||||||
|
public static void AdjustImageLanguage_Valid_Success(string imageLanguage, string requestLanguage, string expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, TmdbUtils.AdjustImageLanguage(imageLanguage, requestLanguage));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user