Merge branch 'master' into network-rewrite

This commit is contained in:
Shadowghost
2022-12-20 09:19:45 +01:00
93 changed files with 354 additions and 663 deletions

View File

@@ -5,9 +5,11 @@
using System;
using System.Buffers.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using System.Threading;
@@ -2461,6 +2463,7 @@ namespace Emby.Server.Implementations.Data
if (query.SearchTerm.Length > 1)
{
builder.Append("+ ((CleanName like @SearchTermContains or (OriginalTitle not null and OriginalTitle like @SearchTermContains)) * 10)");
builder.Append("+ ((Tags not null and Tags like @SearchTermContains) * 5)");
}
builder.Append(") as SearchScore");
@@ -2557,8 +2560,6 @@ namespace Emby.Server.Implementations.Data
CheckDisposed();
var now = DateTime.UtcNow;
// Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
{
@@ -2580,28 +2581,24 @@ namespace Emby.Server.Implementations.Data
}
var commandText = commandTextBuilder.ToString();
int count;
using (new QueryTimeLogger(Logger, commandText))
using (var connection = GetConnection(true))
using (var statement = PrepareStatement(connection, commandText))
{
using (var statement = PrepareStatement(connection, commandText))
if (EnableJoinUserData(query))
{
if (EnableJoinUserData(query))
{
statement.TryBind("@UserId", query.User.InternalId);
}
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
count = statement.ExecuteQuery().SelectScalarInt().First();
statement.TryBind("@UserId", query.User.InternalId);
}
}
LogQueryTime("GetCount", commandText, now);
return count;
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
return statement.ExecuteQuery().SelectScalarInt().First();
}
}
public List<BaseItem> GetItemList(InternalItemsQuery query)
@@ -2610,8 +2607,6 @@ namespace Emby.Server.Implementations.Data
CheckDisposed();
var now = DateTime.UtcNow;
// Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
{
@@ -2655,61 +2650,58 @@ namespace Emby.Server.Implementations.Data
var commandText = commandTextBuilder.ToString();
var items = new List<BaseItem>();
using (new QueryTimeLogger(Logger, commandText))
using (var connection = GetConnection(true))
using (var statement = PrepareStatement(connection, commandText))
{
using (var statement = PrepareStatement(connection, commandText))
if (EnableJoinUserData(query))
{
if (EnableJoinUserData(query))
{
statement.TryBind("@UserId", query.User.InternalId);
}
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
var hasEpisodeAttributes = HasEpisodeAttributes(query);
var hasServiceName = HasServiceName(query);
var hasProgramAttributes = HasProgramAttributes(query);
var hasStartDate = HasStartDate(query);
var hasTrailerTypes = HasTrailerTypes(query);
var hasArtistFields = HasArtistFields(query);
var hasSeriesFields = HasSeriesFields(query);
foreach (var row in statement.ExecuteQuery())
{
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
if (item is not null)
{
items.Add(item);
}
}
statement.TryBind("@UserId", query.User.InternalId);
}
// Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.EnableGroupByMetadataKey)
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
var hasEpisodeAttributes = HasEpisodeAttributes(query);
var hasServiceName = HasServiceName(query);
var hasProgramAttributes = HasProgramAttributes(query);
var hasStartDate = HasStartDate(query);
var hasTrailerTypes = HasTrailerTypes(query);
var hasArtistFields = HasArtistFields(query);
var hasSeriesFields = HasSeriesFields(query);
foreach (var row in statement.ExecuteQuery())
{
var limit = query.Limit ?? int.MaxValue;
limit -= 4;
var newList = new List<BaseItem>();
foreach (var item in items)
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
if (item is not null)
{
AddItem(newList, item);
if (newList.Count >= limit)
{
break;
}
items.Add(item);
}
items = newList;
}
}
LogQueryTime("GetItemList", commandText, now);
// Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.EnableGroupByMetadataKey)
{
var limit = query.Limit ?? int.MaxValue;
limit -= 4;
var newList = new List<BaseItem>();
foreach (var item in items)
{
AddItem(newList, item);
if (newList.Count >= limit)
{
break;
}
}
items = newList;
}
return items;
}
@@ -2762,26 +2754,6 @@ namespace Emby.Server.Implementations.Data
items.Add(newItem);
}
private void LogQueryTime(string methodName, string commandText, DateTime startDate)
{
var elapsed = (DateTime.UtcNow - startDate).TotalMilliseconds;
#if DEBUG
const int SlowThreshold = 100;
#else
const int SlowThreshold = 10;
#endif
if (elapsed >= SlowThreshold)
{
Logger.LogDebug(
"{Method} query time (slow): {ElapsedMs}ms. Query: {Query}",
methodName,
elapsed,
commandText);
}
}
public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
{
ArgumentNullException.ThrowIfNull(query);
@@ -2797,8 +2769,6 @@ namespace Emby.Server.Implementations.Data
returnList);
}
var now = DateTime.UtcNow;
// Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
{
@@ -2899,6 +2869,7 @@ namespace Emby.Server.Implementations.Data
if (!isReturningZeroItems)
{
using (new QueryTimeLogger(Logger, itemQuery, "GetItems.ItemQuery"))
using (var statement = itemQueryStatement)
{
if (EnableJoinUserData(query))
@@ -2929,13 +2900,11 @@ namespace Emby.Server.Implementations.Data
}
}
}
LogQueryTime("GetItems.ItemQuery", itemQuery, now);
}
now = DateTime.UtcNow;
if (query.EnableTotalRecordCount)
{
using (new QueryTimeLogger(Logger, totalRecordCountQuery, "GetItems.TotalRecordCount"))
using (var statement = totalRecordCountQueryStatement)
{
if (EnableJoinUserData(query))
@@ -2951,8 +2920,6 @@ namespace Emby.Server.Implementations.Data
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
}
LogQueryTime("GetItems.TotalRecordCount", totalRecordCountQuery, now);
}
},
ReadTransactionMode);
@@ -3170,8 +3137,6 @@ namespace Emby.Server.Implementations.Data
CheckDisposed();
var now = DateTime.UtcNow;
var columns = new List<string> { "guid" };
SetFinalColumnsToSelect(query, columns);
var commandTextBuilder = new StringBuilder("select ", 256)
@@ -3208,29 +3173,27 @@ namespace Emby.Server.Implementations.Data
var commandText = commandTextBuilder.ToString();
var list = new List<Guid>();
using (new QueryTimeLogger(Logger, commandText))
using (var connection = GetConnection(true))
using (var statement = PrepareStatement(connection, commandText))
{
using (var statement = PrepareStatement(connection, commandText))
if (EnableJoinUserData(query))
{
if (EnableJoinUserData(query))
{
statement.TryBind("@UserId", query.User.InternalId);
}
statement.TryBind("@UserId", query.User.InternalId);
}
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
foreach (var row in statement.ExecuteQuery())
{
list.Add(row[0].ReadGuidFromBlob());
}
foreach (var row in statement.ExecuteQuery())
{
list.Add(row[0].ReadGuidFromBlob());
}
}
LogQueryTime("GetItemList", commandText, now);
return list;
}
@@ -5111,8 +5074,6 @@ AND Type = @InternalPersonType)");
{
CheckDisposed();
var now = DateTime.UtcNow;
var stringBuilder = new StringBuilder("Select Value From ItemValues where Type", 128);
if (itemValueTypes.Length == 1)
{
@@ -5144,6 +5105,7 @@ AND Type = @InternalPersonType)");
var commandText = stringBuilder.ToString();
var list = new List<string>();
using (new QueryTimeLogger(Logger, commandText))
using (var connection = GetConnection(true))
using (var statement = PrepareStatement(connection, commandText))
{
@@ -5156,7 +5118,6 @@ AND Type = @InternalPersonType)");
}
}
LogQueryTime("GetItemValueNames", commandText, now);
return list;
}
@@ -5171,8 +5132,6 @@ AND Type = @InternalPersonType)");
CheckDisposed();
var now = DateTime.UtcNow;
var typeClause = itemValueTypes.Length == 1 ?
("Type=" + itemValueTypes[0]) :
("Type in (" + string.Join(',', itemValueTypes) + ")");
@@ -5346,6 +5305,7 @@ AND Type = @InternalPersonType)");
var list = new List<(BaseItem, ItemCounts)>();
var result = new QueryResult<(BaseItem, ItemCounts)>();
using (new QueryTimeLogger(Logger, commandText))
using (var connection = GetConnection(true))
{
connection.RunInTransaction(
@@ -5419,8 +5379,6 @@ AND Type = @InternalPersonType)");
ReadTransactionMode);
}
LogQueryTime("GetItemValues", commandText, now);
if (result.TotalRecordCount == 0)
{
result.TotalRecordCount = list.Count;
@@ -6245,5 +6203,48 @@ AND Type = @InternalPersonType)");
return item;
}
#nullable enable
private readonly struct QueryTimeLogger : IDisposable
{
private readonly ILogger _logger;
private readonly string _commandText;
private readonly string _methodName;
private readonly long _startTimestamp;
public QueryTimeLogger(ILogger logger, string commandText, [CallerMemberName] string methodName = "")
{
_logger = logger;
_commandText = commandText;
_methodName = methodName;
_startTimestamp = logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : -1;
}
public void Dispose()
{
if (_startTimestamp == -1)
{
return;
}
var elapsedMs = Stopwatch.GetElapsedTime(_startTimestamp).TotalMilliseconds;
#if DEBUG
const int SlowThreshold = 100;
#else
const int SlowThreshold = 10;
#endif
if (elapsedMs >= SlowThreshold)
{
_logger.LogDebug(
"{Method} query time (slow): {ElapsedMs}ms. Query: {Query}",
_methodName,
elapsedMs,
_commandText);
}
}
}
}
}

View File

@@ -574,8 +574,7 @@ namespace Emby.Server.Implementations.Dto
.Where(i => user is null ?
true :
i.IsVisible(user))
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First())
.DistinctBy(x => x.Name, StringComparer.OrdinalIgnoreCase)
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < people.Count; i++)

View File

@@ -29,7 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.1" />
<PackageReference Include="Mono.Nat" Version="3.0.4" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.4.0" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />

View File

@@ -282,19 +282,16 @@ namespace Emby.Server.Implementations.EntryPoints
{
// Remove dupes in case some were saved multiple times
var foldersAddedTo = _foldersAddedTo
.GroupBy(x => x.Id)
.Select(x => x.First())
.DistinctBy(x => x.Id)
.ToList();
var foldersRemovedFrom = _foldersRemovedFrom
.GroupBy(x => x.Id)
.Select(x => x.First())
.DistinctBy(x => x.Id)
.ToList();
var itemsUpdated = _itemsUpdated
.Where(i => !_itemsAdded.Contains(i))
.GroupBy(x => x.Id)
.Select(x => x.First())
.DistinctBy(x => x.Id)
.ToList();
SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None).GetAwaiter().GetResult();

View File

@@ -123,8 +123,7 @@ namespace Emby.Server.Implementations.EntryPoints
var user = _userManager.GetUserById(userId);
var dtoList = changedItems
.GroupBy(x => x.Id)
.Select(x => x.First())
.DistinctBy(x => x.Id)
.Select(i =>
{
var dto = _userDataManager.GetUserDataDto(i, user);

View File

@@ -133,8 +133,7 @@ namespace Emby.Server.Implementations.IO
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(GetAffectedBaseItem)
.Where(item => item is not null)
.GroupBy(x => x!.Id) // Removed null values in the previous .Where()
.Select(x => x.First())!;
.DistinctBy(x => x!.Id)!; // Removed null values in the previous .Where()
foreach (var item in itemsToRefresh)
{

View File

@@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.IO
.OfType<Folder>()
.SelectMany(f => f.PhysicalLocations)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i);
.Order();
foreach (var path in paths)
{

View File

@@ -81,8 +81,7 @@ namespace Emby.Server.Implementations.Images
}
return i;
}).GroupBy(x => x.Id)
.Select(x => x.First());
}).DistinctBy(x => x.Id);
List<BaseItem> returnItems;
if (isUsingCollectionStrip)

View File

@@ -58,8 +58,7 @@ namespace Emby.Server.Implementations.Images
return null;
})
.Where(i => i is not null)
.GroupBy(x => x.Id)
.Select(x => x.First())
.DistinctBy(x => x.Id)
.ToList();
}
}

View File

@@ -1154,7 +1154,7 @@ namespace Emby.Server.Implementations.Library
.ToList();
}
private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> allCollectionFolders, Dictionary<Guid, Guid> refreshQueue)
private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> allCollectionFolders, HashSet<Guid> refreshQueue)
{
var info = new VirtualFolderInfo
{
@@ -1175,29 +1175,29 @@ namespace Emby.Server.Implementations.Library
}
})
.Where(i => i is not null)
.OrderBy(i => i)
.Order()
.ToArray(),
CollectionType = GetCollectionType(dir)
};
var libraryFolder = allCollectionFolders.FirstOrDefault(i => string.Equals(i.Path, dir, StringComparison.OrdinalIgnoreCase));
if (libraryFolder is not null && libraryFolder.HasImage(ImageType.Primary))
{
info.PrimaryImageItemId = libraryFolder.Id.ToString("N", CultureInfo.InvariantCulture);
}
if (libraryFolder is not null)
{
info.ItemId = libraryFolder.Id.ToString("N", CultureInfo.InvariantCulture);
var libraryFolderId = libraryFolder.Id.ToString("N", CultureInfo.InvariantCulture);
info.ItemId = libraryFolderId;
if (libraryFolder.HasImage(ImageType.Primary))
{
info.PrimaryImageItemId = libraryFolderId;
}
info.LibraryOptions = GetLibraryOptions(libraryFolder);
if (refreshQueue is not null)
{
info.RefreshProgress = libraryFolder.GetRefreshProgress();
info.RefreshStatus = info.RefreshProgress.HasValue ? "Active" : refreshQueue.ContainsKey(libraryFolder.Id) ? "Queued" : "Idle";
info.RefreshStatus = info.RefreshProgress.HasValue ? "Active" : refreshQueue.Contains(libraryFolder.Id) ? "Queued" : "Idle";
}
}
@@ -1999,38 +1999,35 @@ namespace Emby.Server.Implementations.Library
public List<Folder> GetCollectionFolders(BaseItem item)
{
while (item is not null)
{
var parent = item.GetParent();
if (parent is null || parent is AggregateFolder)
{
break;
}
item = parent;
}
if (item is null)
{
return new List<Folder>();
}
return GetCollectionFoldersInternal(item, GetUserRootFolder().Children.OfType<Folder>());
return GetCollectionFolders(item, GetUserRootFolder().Children.OfType<Folder>());
}
public List<Folder> GetCollectionFolders(BaseItem item, List<Folder> allUserRootChildren)
public List<Folder> GetCollectionFolders(BaseItem item, IEnumerable<Folder> allUserRootChildren)
{
while (item is not null)
{
var parent = item.GetParent();
if (parent is null || parent is AggregateFolder)
if (parent is AggregateFolder)
{
break;
}
item = parent;
if (parent is null)
{
var owner = item.GetOwner();
if (owner is null)
{
break;
}
item = owner;
}
else
{
item = parent;
}
}
if (item is null)

View File

@@ -163,17 +163,15 @@ namespace Emby.Server.Implementations.Library.Resolvers
try
{
// use disc-utils, both DVDs and BDs use UDF filesystem
using (var videoFileStream = File.Open(video.Path, FileMode.Open, FileAccess.Read))
using (UdfReader udfReader = new UdfReader(videoFileStream))
using var videoFileStream = File.Open(video.Path, FileMode.Open, FileAccess.Read, FileShare.Read);
using UdfReader udfReader = new UdfReader(videoFileStream);
if (udfReader.DirectoryExists("VIDEO_TS"))
{
if (udfReader.DirectoryExists("VIDEO_TS"))
{
video.IsoType = IsoType.Dvd;
}
else if (udfReader.DirectoryExists("BDMV"))
{
video.IsoType = IsoType.BluRay;
}
video.IsoType = IsoType.Dvd;
}
else if (udfReader.DirectoryExists("BDMV"))
{
video.IsoType = IsoType.BluRay;
}
}
catch (Exception ex)

View File

@@ -529,7 +529,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
}
return false;
}).OrderBy(i => i).ToList();
}).Order().ToList();
// If different video types were found, don't allow this
if (videoTypes.Distinct().Count() > 1)

View File

@@ -2392,8 +2392,7 @@ namespace Emby.Server.Implementations.LiveTv
.Select(i => _libraryManager.FindByPath(i, true))
.Where(i => i is not null && i.IsVisibleStandalone(user))
.SelectMany(i => _libraryManager.GetCollectionFolders(i))
.GroupBy(x => x.Id)
.Select(x => x.First())
.DistinctBy(x => x.Id)
.OrderBy(i => i.SortName)
.ToList();

View File

@@ -92,37 +92,37 @@
"ValueHasBeenAddedToLibrary": "{0} is toegevoegd aan je mediabibliotheek",
"ValueSpecialEpisodeName": "Speciaal - {0}",
"VersionNumber": "Versie {0}",
"TaskDownloadMissingSubtitlesDescription": "Zoekt op het internet naar missende ondertiteling gebaseerd op metadata configuratie.",
"TaskDownloadMissingSubtitles": "Download missende ondertiteling",
"TaskDownloadMissingSubtitlesDescription": "Zoekt op het internet naar ontbrekende ondertiteling gebaseerd op metadataconfiguratie.",
"TaskDownloadMissingSubtitles": "Ontbrekende ondertiteling downloaden",
"TaskRefreshChannelsDescription": "Vernieuwt informatie van internet kanalen.",
"TaskRefreshChannels": "Vernieuw Kanalen",
"TaskCleanTranscodeDescription": "Verwijdert transcode bestanden ouder dan 1 dag.",
"TaskCleanLogs": "Log Folder Opschonen",
"TaskCleanTranscode": "Transcode Folder Opschonen",
"TaskUpdatePluginsDescription": "Download en installeert updates voor plugins waar automatisch updaten aan staat.",
"TaskUpdatePlugins": "Update Plugins",
"TaskCleanLogs": "Logboekmap opschonen",
"TaskCleanTranscode": "Transcoderingsmap opschonen",
"TaskUpdatePluginsDescription": "Downloadt en installeert updates van plug-ins waarvoor automatisch bijwerken is ingeschakeld.",
"TaskUpdatePlugins": "Plug-ins bijwerken",
"TaskRefreshPeopleDescription": "Update metadata for acteurs en regisseurs in de media bibliotheek.",
"TaskRefreshPeople": "Vernieuw Personen",
"TaskRefreshPeople": "Personen vernieuwen",
"TaskCleanLogsDescription": "Verwijdert log bestanden ouder dan {0} dagen.",
"TaskRefreshLibraryDescription": "Scant de media bibliotheek voor nieuwe bestanden en vernieuwt de metadata.",
"TaskRefreshLibrary": "Scan Media Bibliotheek",
"TaskRefreshLibraryDescription": "Scant de mediabibliotheek op nieuwe bestanden en vernieuwt de metadata.",
"TaskRefreshLibrary": "Mediabibliotheek scannen",
"TaskRefreshChapterImagesDescription": "Maakt thumbnails aan voor videos met hoofdstukken.",
"TaskRefreshChapterImages": "Hoofdstukafbeeldingen Uitpakken",
"TaskRefreshChapterImages": "Hoofdstukafbeeldingen uitpakken",
"TaskCleanCacheDescription": "Verwijdert gecachte bestanden die het systeem niet langer nodig heeft.",
"TaskCleanCache": "Cache Folder Opschonen",
"TaskCleanCache": "Cache-map opschonen",
"TasksChannelsCategory": "Internet Kanalen",
"TasksApplicationCategory": "Applicatie",
"TasksApplicationCategory": "Toepassing",
"TasksLibraryCategory": "Bibliotheek",
"TasksMaintenanceCategory": "Onderhoud",
"TaskCleanActivityLogDescription": "Verwijdert activiteiten logs ouder dan de ingestelde tijd.",
"TaskCleanActivityLog": "Leeg activiteiten logboek",
"TaskCleanActivityLog": "Activiteitenlogboek legen",
"Undefined": "Niet gedefinieerd",
"Forced": "Geforceerd",
"Default": "Standaard",
"TaskOptimizeDatabaseDescription": "Comprimeert de database en trimt vrije ruimte. Het uitvoeren van deze taak kan de prestaties verbeteren, na het scannen van de bibliotheek of andere aanpassingen die invloed hebben op de database.",
"TaskOptimizeDatabase": "Database optimaliseren",
"TaskKeyframeExtractorDescription": "Haalt keyframes uit videobestanden om preciezere HLS afspeellijsten te maken. Dit kan lang duren.",
"TaskKeyframeExtractor": "Keyframe Extractor",
"TaskKeyframeExtractorDescription": "Haalt keyframes uit videobestanden om preciezere HLS-afspeellijsten te maken. Deze taak kan lang duren.",
"TaskKeyframeExtractor": "Keyframe-uitpakker",
"External": "Extern",
"HearingImpaired": "Slechthorend"
}

View File

@@ -102,8 +102,8 @@
"LabelIpAddressValue": "آئ پی ایڈریس {0}",
"ItemRemovedWithName": "لائبریری سے ہٹا دیا گیا ھے",
"ItemAddedWithName": "[0} لائبریری میں شامل کیا گیا ھے",
"Inherit": "وراثت میں",
"HomeVideos": "ہوم ویڈیو",
"Inherit": "وراثت",
"HomeVideos": "ہوم ویڈیوز",
"HeaderRecordingGroups": "ریکارڈنگ گروپس",
"FailedLoginAttemptWithUserName": "{0} سے لاگ ان کی ناکام کوشش",
"DeviceOnlineWithName": "{0} متصل ھو چکا ھے",
@@ -115,5 +115,13 @@
"AppDeviceValues": "پروگرام:{0}, ڈیوائس:{1}",
"Forced": "جَبری",
"Undefined": "غير وضاحتى",
"Default": "طے شدہ"
"Default": "طے شدہ",
"TaskKeyframeExtractorDescription": "زیادہ درست HLS پلے لسٹس بنانے کے لیے ویڈیو فائلوں سے کلیدی فریم نکالتا ہے۔ یہ کام طویل عرصے تک چل سکتا ہے۔",
"TaskOptimizeDatabase": "ڈیٹا بیس کو بہتر بنائیں",
"TaskOptimizeDatabaseDescription": "ڈیٹا بیس کو کمپیکٹ کرتا ہے اور خالی جگہ کو چھوٹا کرتا ہے۔ لائبریری کو اسکین کرنے یا دیگر تبدیلیاں کرنے کے بعد اس کام کو چلانے سے کارکردگی بہتر ہو سکتی ہے۔",
"TaskKeyframeExtractor": "کی فریم ایکسٹریکٹر",
"TaskCleanActivityLogDescription": "تشکیل شدہ عمر سے زیادہ پرانی سرگرمی لاگ اندراجات کو حذف کرتا ہے۔",
"External": "بیرونی",
"HearingImpaired": "قوت سماعت سے محروم",
"TaskCleanActivityLog": "سرگرمی لاگ کو صاف کریں۔"
}

View File

@@ -82,24 +82,6 @@ namespace Emby.Server.Implementations
/// <value>The year path.</value>
public string YearPath => Path.Combine(InternalMetadataPath, "Year");
/// <summary>
/// Gets the path to the General IBN directory.
/// </summary>
/// <value>The general path.</value>
public string GeneralPath => Path.Combine(InternalMetadataPath, "general");
/// <summary>
/// Gets the path to the Ratings IBN directory.
/// </summary>
/// <value>The ratings path.</value>
public string RatingsPath => Path.Combine(InternalMetadataPath, "ratings");
/// <summary>
/// Gets the media info images path.
/// </summary>
/// <value>The media info images path.</value>
public string MediaInfoImagesPath => Path.Combine(InternalMetadataPath, "mediainfo");
/// <summary>
/// Gets the path to the user configuration directory.
/// </summary>