aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
authorPatrick Barron <barronpm@gmail.com>2020-05-12 22:22:20 -0400
committerPatrick Barron <barronpm@gmail.com>2020-05-12 22:22:20 -0400
commitc1360a1dc312938e77e52a509eb9186300bcb40d (patch)
tree492b4d717a12b20a4649b2fbc48050430ea72d50 /Emby.Server.Implementations
parent9ad839c7766bd5d6121a10b2c306d6fef9666c52 (diff)
parent32c118222647f121c0b17055c0ef158763c0b5d2 (diff)
Merge branch 'master' into userdb-efcore
# Conflicts: # Emby.Server.Implementations/Data/SqliteUserDataRepository.cs # Emby.Server.Implementations/Library/UserManager.cs # Jellyfin.Data/Entities/User.cs # Jellyfin.Data/ISavingChanges.cs # Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj # Jellyfin.Server.Implementations/JellyfinDb.cs # Jellyfin.Server/Migrations/MigrationRunner.cs # MediaBrowser.Model/Notifications/NotificationOptions.cs # MediaBrowser.sln
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/ConfigurationOptions.cs1
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs389
-rw-r--r--Emby.Server.Implementations/Localization/Core/af.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-MX.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/es.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json26
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json20
-rw-r--r--Emby.Server.Implementations/Localization/Core/gsw.json92
-rw-r--r--Emby.Server.Implementations/Localization/Core/he.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json12
-rw-r--r--Emby.Server.Implementations/Localization/Core/it.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/mk.json9
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/sl-SI.json23
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/uk.json36
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-HK.json7
-rw-r--r--Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs8
18 files changed, 578 insertions, 68 deletions
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index db7c35a7c..dea9b6682 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.Updates;
-using MediaBrowser.Providers.Music;
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
namespace Emby.Server.Implementations
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
new file mode 100644
index 000000000..6ee6230fc
--- /dev/null
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -0,0 +1,389 @@
+#pragma warning disable CS1591
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
+using Microsoft.Extensions.Logging;
+using SQLitePCL.pretty;
+
+namespace Emby.Server.Implementations.Data
+{
+ public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
+ {
+ public SqliteUserDataRepository(
+ ILogger<SqliteUserDataRepository> logger,
+ IApplicationPaths appPaths)
+ : base(logger)
+ {
+ DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
+ }
+
+ /// <inheritdoc />
+ public string Name => "SQLite";
+
+ /// <summary>
+ /// Opens the connection to the database.
+ /// </summary>
+ public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection)
+ {
+ WriteLock.Dispose();
+ WriteLock = dbLock;
+ WriteConnection?.Dispose();
+ WriteConnection = dbConnection;
+
+ using (var connection = GetConnection())
+ {
+ var userDatasTableExists = TableExists(connection, "UserDatas");
+ var userDataTableExists = TableExists(connection, "userdata");
+
+ var users = userDatasTableExists ? null : userManager.Users;
+
+ connection.RunInTransaction(db =>
+ {
+ db.ExecuteAll(string.Join(";", new[] {
+
+ "create table if not exists UserDatas (key nvarchar not null, userId INT not null, rating float null, played bit not null, playCount int not null, isFavorite bit not null, playbackPositionTicks bigint not null, lastPlayedDate datetime null, AudioStreamIndex INT, SubtitleStreamIndex INT)",
+
+ "drop index if exists idx_userdata",
+ "drop index if exists idx_userdata1",
+ "drop index if exists idx_userdata2",
+ "drop index if exists userdataindex1",
+ "drop index if exists userdataindex",
+ "drop index if exists userdataindex3",
+ "drop index if exists userdataindex4",
+ "create unique index if not exists UserDatasIndex1 on UserDatas (key, userId)",
+ "create index if not exists UserDatasIndex2 on UserDatas (key, userId, played)",
+ "create index if not exists UserDatasIndex3 on UserDatas (key, userId, playbackPositionTicks)",
+ "create index if not exists UserDatasIndex4 on UserDatas (key, userId, isFavorite)"
+ }));
+
+ if (userDataTableExists)
+ {
+ var existingColumnNames = GetColumnNames(db, "userdata");
+
+ AddColumn(db, "userdata", "InternalUserId", "int", existingColumnNames);
+ AddColumn(db, "userdata", "AudioStreamIndex", "int", existingColumnNames);
+ AddColumn(db, "userdata", "SubtitleStreamIndex", "int", existingColumnNames);
+
+ if (!userDatasTableExists)
+ {
+ ImportUserIds(db, users);
+
+ db.ExecuteAll("INSERT INTO UserDatas (key, userId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex) SELECT key, InternalUserId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex from userdata where InternalUserId not null");
+ }
+ }
+ }, TransactionMode);
+ }
+ }
+
+ private void ImportUserIds(IDatabaseConnection db, IEnumerable<User> users)
+ {
+ var userIdsWithUserData = GetAllUserIdsWithUserData(db);
+
+ using (var statement = db.PrepareStatement("update userdata set InternalUserId=@InternalUserId where UserId=@UserId"))
+ {
+ foreach (var user in users)
+ {
+ if (!userIdsWithUserData.Contains(user.Id))
+ {
+ continue;
+ }
+
+ statement.TryBind("@UserId", user.Id.ToByteArray());
+ statement.TryBind("@InternalUserId", user.InternalId);
+
+ statement.MoveNext();
+ statement.Reset();
+ }
+ }
+ }
+
+ private List<Guid> GetAllUserIdsWithUserData(IDatabaseConnection db)
+ {
+ var list = new List<Guid>();
+
+ using (var statement = PrepareStatement(db, "select DISTINCT UserId from UserData where UserId not null"))
+ {
+ foreach (var row in statement.ExecuteQuery())
+ {
+ try
+ {
+ list.Add(row[0].ReadGuidFromBlob());
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError(ex, "Error while getting user");
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /// <summary>
+ /// Saves the user data.
+ /// </summary>
+ public void SaveUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken)
+ {
+ if (userData == null)
+ {
+ throw new ArgumentNullException(nameof(userData));
+ }
+ if (internalUserId <= 0)
+ {
+ throw new ArgumentNullException(nameof(internalUserId));
+ }
+ if (string.IsNullOrEmpty(key))
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ PersistUserData(internalUserId, key, userData, cancellationToken);
+ }
+
+ public void SaveAllUserData(long internalUserId, UserItemData[] userData, CancellationToken cancellationToken)
+ {
+ if (userData == null)
+ {
+ throw new ArgumentNullException(nameof(userData));
+ }
+ if (internalUserId <= 0)
+ {
+ throw new ArgumentNullException(nameof(internalUserId));
+ }
+
+ PersistAllUserData(internalUserId, userData, cancellationToken);
+ }
+
+ /// <summary>
+ /// Persists the user data.
+ /// </summary>
+ /// <param name="internalUserId">The user id.</param>
+ /// <param name="key">The key.</param>
+ /// <param name="userData">The user data.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public void PersistUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ using (var connection = GetConnection())
+ {
+ connection.RunInTransaction(db =>
+ {
+ SaveUserData(db, internalUserId, key, userData);
+ }, TransactionMode);
+ }
+ }
+
+ private static void SaveUserData(IDatabaseConnection db, long internalUserId, string key, UserItemData userData)
+ {
+ using (var statement = db.PrepareStatement("replace into UserDatas (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"))
+ {
+ statement.TryBind("@userId", internalUserId);
+ statement.TryBind("@key", key);
+
+ if (userData.Rating.HasValue)
+ {
+ statement.TryBind("@rating", userData.Rating.Value);
+ }
+ else
+ {
+ statement.TryBindNull("@rating");
+ }
+
+ statement.TryBind("@played", userData.Played);
+ statement.TryBind("@playCount", userData.PlayCount);
+ statement.TryBind("@isFavorite", userData.IsFavorite);
+ statement.TryBind("@playbackPositionTicks", userData.PlaybackPositionTicks);
+
+ if (userData.LastPlayedDate.HasValue)
+ {
+ statement.TryBind("@lastPlayedDate", userData.LastPlayedDate.Value.ToDateTimeParamValue());
+ }
+ else
+ {
+ statement.TryBindNull("@lastPlayedDate");
+ }
+
+ if (userData.AudioStreamIndex.HasValue)
+ {
+ statement.TryBind("@AudioStreamIndex", userData.AudioStreamIndex.Value);
+ }
+ else
+ {
+ statement.TryBindNull("@AudioStreamIndex");
+ }
+
+ if (userData.SubtitleStreamIndex.HasValue)
+ {
+ statement.TryBind("@SubtitleStreamIndex", userData.SubtitleStreamIndex.Value);
+ }
+ else
+ {
+ statement.TryBindNull("@SubtitleStreamIndex");
+ }
+
+ statement.MoveNext();
+ }
+ }
+
+ /// <summary>
+ /// Persist all user data for the specified user
+ /// </summary>
+ private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ using (var connection = GetConnection())
+ {
+ connection.RunInTransaction(db =>
+ {
+ foreach (var userItemData in userDataList)
+ {
+ SaveUserData(db, internalUserId, userItemData.Key, userItemData);
+ }
+ }, TransactionMode);
+ }
+ }
+
+ /// <summary>
+ /// Gets the user data.
+ /// </summary>
+ /// <param name="internalUserId">The user id.</param>
+ /// <param name="key">The key.</param>
+ /// <returns>Task{UserItemData}.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// userId
+ /// or
+ /// key
+ /// </exception>
+ public UserItemData GetUserData(long internalUserId, string key)
+ {
+ if (internalUserId <= 0)
+ {
+ throw new ArgumentNullException(nameof(internalUserId));
+ }
+
+ if (string.IsNullOrEmpty(key))
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ using (var connection = GetConnection(true))
+ {
+ using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId"))
+ {
+ statement.TryBind("@UserId", internalUserId);
+ statement.TryBind("@Key", key);
+
+ foreach (var row in statement.ExecuteQuery())
+ {
+ return ReadRow(row);
+ }
+ }
+
+ return null;
+ }
+ }
+
+ public UserItemData GetUserData(long internalUserId, List<string> keys)
+ {
+ if (keys == null)
+ {
+ throw new ArgumentNullException(nameof(keys));
+ }
+
+ if (keys.Count == 0)
+ {
+ return null;
+ }
+
+ return GetUserData(internalUserId, keys[0]);
+ }
+
+ /// <summary>
+ /// Return all user-data associated with the given user
+ /// </summary>
+ /// <param name="internalUserId"></param>
+ /// <returns></returns>
+ public List<UserItemData> GetAllUserData(long internalUserId)
+ {
+ if (internalUserId <= 0)
+ {
+ throw new ArgumentNullException(nameof(internalUserId));
+ }
+
+ var list = new List<UserItemData>();
+
+ using (var connection = GetConnection())
+ {
+ using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId"))
+ {
+ statement.TryBind("@UserId", internalUserId);
+
+ foreach (var row in statement.ExecuteQuery())
+ {
+ list.Add(ReadRow(row));
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /// <summary>
+ /// Read a row from the specified reader into the provided userData object
+ /// </summary>
+ /// <param name="reader"></param>
+ private UserItemData ReadRow(IReadOnlyList<IResultSetValue> reader)
+ {
+ var userData = new UserItemData();
+
+ userData.Key = reader[0].ToString();
+ //userData.UserId = reader[1].ReadGuidFromBlob();
+
+ if (reader[2].SQLiteType != SQLiteType.Null)
+ {
+ userData.Rating = reader[2].ToDouble();
+ }
+
+ userData.Played = reader[3].ToBool();
+ userData.PlayCount = reader[4].ToInt();
+ userData.IsFavorite = reader[5].ToBool();
+ userData.PlaybackPositionTicks = reader[6].ToInt64();
+
+ if (reader[7].SQLiteType != SQLiteType.Null)
+ {
+ userData.LastPlayedDate = reader[7].TryReadDateTime();
+ }
+
+ if (reader[8].SQLiteType != SQLiteType.Null)
+ {
+ userData.AudioStreamIndex = reader[8].ToInt();
+ }
+
+ if (reader[9].SQLiteType != SQLiteType.Null)
+ {
+ userData.SubtitleStreamIndex = reader[9].ToInt();
+ }
+
+ return userData;
+ }
+
+ /// <inheritdoc/>
+ /// <remarks>
+ /// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and
+ /// <see cref="BaseSqliteRepository.WriteConnection"/> are managed by <see cref="SqliteItemRepository"/>.
+ /// See <see cref="Initialize(IUserManager, SemaphoreSlim, SQLiteDatabaseConnection)"/>.
+ /// </remarks>
+ protected override void Dispose(bool dispose)
+ {
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/Localization/Core/af.json b/Emby.Server.Implementations/Localization/Core/af.json
index 1363eaf85..20447347b 100644
--- a/Emby.Server.Implementations/Localization/Core/af.json
+++ b/Emby.Server.Implementations/Localization/Core/af.json
@@ -4,7 +4,7 @@
"Folders": "Fouers",
"Favorites": "Gunstelinge",
"HeaderFavoriteShows": "Gunsteling Vertonings",
- "ValueSpecialEpisodeName": "Spesiaal - {0}",
+ "ValueSpecialEpisodeName": "Spesiale - {0}",
"HeaderAlbumArtists": "Album Kunstenaars",
"Books": "Boeke",
"HeaderNextUp": "Volgende",
diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json
index e0bbe90b3..d93920f43 100644
--- a/Emby.Server.Implementations/Localization/Core/es-MX.json
+++ b/Emby.Server.Implementations/Localization/Core/es-MX.json
@@ -11,7 +11,7 @@
"Collections": "Colecciones",
"DeviceOfflineWithName": "{0} se ha desconectado",
"DeviceOnlineWithName": "{0} está conectado",
- "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}",
+ "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión desde {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Genres": "Géneros",
diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json
index de1baada8..e7bd3959b 100644
--- a/Emby.Server.Implementations/Localization/Core/es.json
+++ b/Emby.Server.Implementations/Localization/Core/es.json
@@ -71,7 +71,7 @@
"ScheduledTaskFailedWithName": "{0} falló",
"ScheduledTaskStartedWithName": "{0} iniciada",
"ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
- "Shows": "Series",
+ "Shows": "Mostrar",
"Songs": "Canciones",
"StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
"SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
index b39adefe7..f8d6e0e09 100644
--- a/Emby.Server.Implementations/Localization/Core/fi.json
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -1,5 +1,5 @@
{
- "HeaderLiveTV": "Suorat lähetykset",
+ "HeaderLiveTV": "Live-TV",
"NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon Kausi",
"NameSeasonNumber": "Kausi {0}",
@@ -12,7 +12,7 @@
"MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty",
"MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}",
"MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
- "Latest": "Viimeisin",
+ "Latest": "Uusimmat",
"LabelRunningTimeValue": "Toiston kesto: {0}",
"LabelIpAddressValue": "IP-osoite: {0}",
"ItemRemovedWithName": "{0} poistettiin kirjastosta",
@@ -41,7 +41,7 @@
"CameraImageUploadedFrom": "Uusi kamerakuva on ladattu {0}",
"Books": "Kirjat",
"AuthenticationSucceededWithUserName": "{0} todennus onnistui",
- "Artists": "Esiintyjät",
+ "Artists": "Artistit",
"Application": "Sovellus",
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
"Albums": "Albumit",
@@ -67,21 +67,21 @@
"UserDownloadingItemWithValues": "{0} lataa {1}",
"UserDeletedWithName": "Käyttäjä {0} poistettu",
"UserCreatedWithName": "Käyttäjä {0} luotu",
- "TvShows": "TV-Ohjelmat",
+ "TvShows": "TV-sarjat",
"Sync": "Synkronoi",
- "SubtitleDownloadFailureFromForItem": "Tekstityksen lataaminen epäonnistui {0} - {1}",
+ "SubtitleDownloadFailureFromForItem": "Tekstitysten lataus ({0} -> {1}) epäonnistui //this string would have to be generated for each provider and movie because of finnish cases, sorry",
"StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Kokeile hetken kuluttua uudelleen.",
"Songs": "Kappaleet",
- "Shows": "Ohjelmat",
- "ServerNameNeedsToBeRestarted": "{0} vaatii uudelleenkäynnistyksen",
+ "Shows": "Sarjat",
+ "ServerNameNeedsToBeRestarted": "{0} täytyy käynnistää uudelleen",
"ProviderValue": "Tarjoaja: {0}",
"Plugin": "Liitännäinen",
"NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty",
- "NotificationOptionVideoPlayback": "Videon toisto aloitettu",
- "NotificationOptionUserLockedOut": "Käyttäjä lukittu",
+ "NotificationOptionVideoPlayback": "Videota toistetaan",
+ "NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos",
"NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui",
- "NotificationOptionServerRestartRequired": "Palvelimen uudelleenkäynnistys vaaditaan",
- "NotificationOptionPluginUpdateInstalled": "Lisäosan päivitys asennettu",
+ "NotificationOptionServerRestartRequired": "Palvelin pitää käynnistää uudelleen",
+ "NotificationOptionPluginUpdateInstalled": "Liitännäinen päivitetty",
"NotificationOptionPluginUninstalled": "Liitännäinen poistettu",
"NotificationOptionPluginInstalled": "Liitännäinen asennettu",
"NotificationOptionPluginError": "Ongelma liitännäisessä",
@@ -90,8 +90,8 @@
"NotificationOptionCameraImageUploaded": "Kameran kuva ladattu",
"NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
"NotificationOptionAudioPlayback": "Toistetaan ääntä",
- "NotificationOptionApplicationUpdateInstalled": "Uusi sovellusversio asennettu",
- "NotificationOptionApplicationUpdateAvailable": "Sovelluksesta on uusi versio saatavilla",
+ "NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettu",
+ "NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla",
"TasksMaintenanceCategory": "Ylläpito",
"TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.",
"TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json
index 2c9dae6a1..c2349ba5b 100644
--- a/Emby.Server.Implementations/Localization/Core/fr-CA.json
+++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json
@@ -94,5 +94,23 @@
"ValueSpecialEpisodeName": "Spécial - {0}",
"VersionNumber": "Version {0}",
"TasksLibraryCategory": "Bibliothèque",
- "TasksMaintenanceCategory": "Entretien"
+ "TasksMaintenanceCategory": "Entretien",
+ "TaskDownloadMissingSubtitlesDescription": "Recherche l'internet pour des sous-titres manquants à base de métadonnées configurées.",
+ "TaskDownloadMissingSubtitles": "Télécharger des sous-titres manquants",
+ "TaskRefreshChannelsDescription": "Rafraîchit des informations des chaines d'internet.",
+ "TaskRefreshChannels": "Rafraîchir des chaines",
+ "TaskCleanTranscodeDescription": "Retirer des fichiers de transcodage de plus qu'un jour.",
+ "TaskCleanTranscode": "Nettoyer le directoire de transcodage",
+ "TaskUpdatePluginsDescription": "Télécharger et installer des mises à jours des plugins qui sont configurés m.à.j. automisés.",
+ "TaskUpdatePlugins": "Mise à jour des plugins",
+ "TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre bibliothèque.",
+ "TaskRefreshPeople": "Rafraîchir les acteurs",
+ "TaskCleanLogsDescription": "Retire les données qui ont plus que {0} jours.",
+ "TaskCleanLogs": "Nettoyer les données de directoire",
+ "TaskRefreshLibraryDescription": "Analyse votre bibliothèque média pour des nouveaux fichiers et rafraîchit les métadonnées.",
+ "TaskRefreshChapterImages": "Extraire des images du chapitre",
+ "TaskRefreshChapterImagesDescription": "Créer des vignettes pour des vidéos qui ont des chapitres",
+ "TaskRefreshLibrary": "Analyser la bibliothèque de média",
+ "TaskCleanCache": "Nettoyer le cache de directoire",
+ "TasksApplicationCategory": "Application"
}
diff --git a/Emby.Server.Implementations/Localization/Core/gsw.json b/Emby.Server.Implementations/Localization/Core/gsw.json
index 9611e33f5..8780a884b 100644
--- a/Emby.Server.Implementations/Localization/Core/gsw.json
+++ b/Emby.Server.Implementations/Localization/Core/gsw.json
@@ -1,41 +1,41 @@
{
- "Albums": "Albom",
- "AppDeviceValues": "App: {0}, Grät: {1}",
- "Application": "Aawändig",
- "Artists": "Könstler",
- "AuthenticationSucceededWithUserName": "{0} het sech aagmäudet",
- "Books": "Büecher",
- "CameraImageUploadedFrom": "Es nöis Foti esch ufeglade worde vo {0}",
- "Channels": "Kanäu",
- "ChapterNameValue": "Kapitu {0}",
- "Collections": "Sammlige",
- "DeviceOfflineWithName": "{0} esch offline gange",
- "DeviceOnlineWithName": "{0} esch online cho",
- "FailedLoginAttemptWithUserName": "Fäugschlagne Aamäudeversuech vo {0}",
- "Favorites": "Favorite",
+ "Albums": "Alben",
+ "AppDeviceValues": "App: {0}, Gerät: {1}",
+ "Application": "Anwendung",
+ "Artists": "Künstler",
+ "AuthenticationSucceededWithUserName": "{0} hat sich angemeldet",
+ "Books": "Bücher",
+ "CameraImageUploadedFrom": "Ein neues Foto wurde von {0} hochgeladen",
+ "Channels": "Kanäle",
+ "ChapterNameValue": "Kapitel {0}",
+ "Collections": "Sammlungen",
+ "DeviceOfflineWithName": "{0} wurde getrennt",
+ "DeviceOnlineWithName": "{0} ist verbunden",
+ "FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
+ "Favorites": "Favoriten",
"Folders": "Ordner",
"Genres": "Genres",
- "HeaderAlbumArtists": "Albom-Könstler",
+ "HeaderAlbumArtists": "Album-Künstler",
"HeaderCameraUploads": "Kamera-Uploads",
- "HeaderContinueWatching": "Wiiterluege",
- "HeaderFavoriteAlbums": "Lieblingsalbe",
- "HeaderFavoriteArtists": "Lieblings-Interprete",
- "HeaderFavoriteEpisodes": "Lieblingsepisode",
- "HeaderFavoriteShows": "Lieblingsserie",
+ "HeaderContinueWatching": "weiter schauen",
+ "HeaderFavoriteAlbums": "Lieblingsalben",
+ "HeaderFavoriteArtists": "Lieblings-Künstler",
+ "HeaderFavoriteEpisodes": "Lieblingsepisoden",
+ "HeaderFavoriteShows": "Lieblingsserien",
"HeaderFavoriteSongs": "Lieblingslieder",
- "HeaderLiveTV": "Live-Färnseh",
- "HeaderNextUp": "Als nächts",
- "HeaderRecordingGroups": "Ufnahmegruppe",
- "HomeVideos": "Heimfilmli",
- "Inherit": "Hinzuefüege",
- "ItemAddedWithName": "{0} esch de Bibliothek dezuegfüegt worde",
- "ItemRemovedWithName": "{0} esch vo de Bibliothek entfärnt worde",
- "LabelIpAddressValue": "IP-Adrässe: {0}",
- "LabelRunningTimeValue": "Loufziit: {0}",
- "Latest": "Nöischti",
- "MessageApplicationUpdated": "Jellyfin Server esch aktualisiert worde",
- "MessageApplicationUpdatedTo": "Jellyfin Server esch of Version {0} aktualisiert worde",
- "MessageNamedServerConfigurationUpdatedWithValue": "De Serveriistöuigsberiich {0} esch aktualisiert worde",
+ "HeaderLiveTV": "Live-Fernseh",
+ "HeaderNextUp": "Als Nächstes",
+ "HeaderRecordingGroups": "Aufnahme-Gruppen",
+ "HomeVideos": "Heimvideos",
+ "Inherit": "Vererben",
+ "ItemAddedWithName": "{0} wurde der Bibliothek hinzugefügt",
+ "ItemRemovedWithName": "{0} wurde aus der Bibliothek entfernt",
+ "LabelIpAddressValue": "IP-Adresse: {0}",
+ "LabelRunningTimeValue": "Laufzeit: {0}",
+ "Latest": "Neueste",
+ "MessageApplicationUpdated": "Jellyfin-Server wurde aktualisiert",
+ "MessageApplicationUpdatedTo": "Jellyfin-Server wurde auf Version {0} aktualisiert",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Der Server-Einstellungsbereich {0} wurde aktualisiert",
"MessageServerConfigurationUpdated": "Serveriistöuige send aktualisiert worde",
"MixedContent": "Gmeschti Inhäut",
"Movies": "Film",
@@ -50,7 +50,7 @@
"NotificationOptionAudioPlayback": "Audiowedergab gstartet",
"NotificationOptionAudioPlaybackStopped": "Audiwedergab gstoppt",
"NotificationOptionCameraImageUploaded": "Foti ueglade",
- "NotificationOptionInstallationFailed": "Installationsfäuer",
+ "NotificationOptionInstallationFailed": "Installationsfehler",
"NotificationOptionNewLibraryContent": "Nöie Inhaut hinzuegfüegt",
"NotificationOptionPluginError": "Plugin-Fäuer",
"NotificationOptionPluginInstalled": "Plugin installiert",
@@ -92,5 +92,27 @@
"UserStoppedPlayingItemWithValues": "{0} het d'Wedergab vo {1} of {2} gstoppt",
"ValueHasBeenAddedToLibrary": "{0} esch dinnere Biblithek hinzuegfüegt worde",
"ValueSpecialEpisodeName": "Extra - {0}",
- "VersionNumber": "Version {0}"
+ "VersionNumber": "Version {0}",
+ "TaskCleanLogs": "Lösche Log Pfad",
+ "TaskRefreshLibraryDescription": "Scanne alle Bibliotheken für hinzugefügte Datein und erneuere Metadaten.",
+ "TaskRefreshLibrary": "Scanne alle Bibliotheken",
+ "TaskRefreshChapterImagesDescription": "Kreiert Vorschaubilder für Videos welche Kapitel haben.",
+ "TaskRefreshChapterImages": "Extrahiere Kapitel-Bilder",
+ "TaskCleanCacheDescription": "Löscht Zwischenspeicherdatein die nicht länger von System gebraucht werden.",
+ "TaskCleanCache": "Leere Cache Pfad",
+ "TasksChannelsCategory": "Internet Kanäle",
+ "TasksApplicationCategory": "Applikation",
+ "TasksLibraryCategory": "Bibliothek",
+ "TasksMaintenanceCategory": "Verwaltung",
+ "TaskDownloadMissingSubtitlesDescription": "Durchsucht das Internet nach fehlenden Untertiteln, basierend auf den Metadaten Einstellungen.",
+ "TaskDownloadMissingSubtitles": "Lade fehlende Untertitel herunter",
+ "TaskRefreshChannelsDescription": "Aktualisiert Internet Kanal Informationen.",
+ "TaskRefreshChannels": "Aktualisiere Kanäle",
+ "TaskCleanTranscodeDescription": "Löscht Transkodierdateien welche älter als ein Tag sind.",
+ "TaskCleanTranscode": "Räume Transcodier Verzeichnis auf",
+ "TaskUpdatePluginsDescription": "Lädt Aktualisierungen für Erweiterungen herunter und installiert diese, für welche automatische Aktualisierungen konfiguriert sind.",
+ "TaskUpdatePlugins": "Aktualisiere Erweiterungen",
+ "TaskRefreshPeopleDescription": "Aktualisiert Metadaten für Schausteller und Regisseure in deiner Bibliothek.",
+ "TaskRefreshPeople": "Aktualisiere Schauspieler",
+ "TaskCleanLogsDescription": "Löscht Log Dateien die älter als {0} Tage sind."
}
diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json
index 266291362..8abe31d2a 100644
--- a/Emby.Server.Implementations/Localization/Core/he.json
+++ b/Emby.Server.Implementations/Localization/Core/he.json
@@ -62,7 +62,7 @@
"NotificationOptionVideoPlayback": "Video playback started",
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
"Photos": "תמונות",
- "Playlists": "רשימות ניגון",
+ "Playlists": "רשימות הפעלה",
"Plugin": "Plugin",
"PluginInstalledWithName": "{0} was installed",
"PluginUninstalledWithName": "{0} was uninstalled",
diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index 6947178d7..c169a35e7 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -30,7 +30,7 @@
"Inherit": "Naslijedi",
"ItemAddedWithName": "{0} je dodano u biblioteku",
"ItemRemovedWithName": "{0} je uklonjen iz biblioteke",
- "LabelIpAddressValue": "Ip adresa: {0}",
+ "LabelIpAddressValue": "IP adresa: {0}",
"LabelRunningTimeValue": "Vrijeme rada: {0}",
"Latest": "Najnovije",
"MessageApplicationUpdated": "Jellyfin Server je ažuriran",
@@ -92,5 +92,13 @@
"UserStoppedPlayingItemWithValues": "{0} je zaustavio {1}",
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
"ValueSpecialEpisodeName": "Specijal - {0}",
- "VersionNumber": "Verzija {0}"
+ "VersionNumber": "Verzija {0}",
+ "TaskRefreshLibraryDescription": "Skenira vašu medijsku knjižnicu sa novim datotekama i osvježuje metapodatke.",
+ "TaskRefreshLibrary": "Skeniraj medijsku knjižnicu",
+ "TaskRefreshChapterImagesDescription": "Stvara sličice za videozapise koji imaju poglavlja.",
+ "TaskRefreshChapterImages": "Raspakiraj slike poglavlja",
+ "TaskCleanCacheDescription": "Briše priručne datoteke nepotrebne za sistem.",
+ "TaskCleanCache": "Očisti priručnu memoriju",
+ "TasksApplicationCategory": "Aplikacija",
+ "TasksMaintenanceCategory": "Održavanje"
}
diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json
index 0758bbe9c..7f5a56e86 100644
--- a/Emby.Server.Implementations/Localization/Core/it.json
+++ b/Emby.Server.Implementations/Localization/Core/it.json
@@ -5,7 +5,7 @@
"Artists": "Artisti",
"AuthenticationSucceededWithUserName": "{0} autenticato con successo",
"Books": "Libri",
- "CameraImageUploadedFrom": "È stata caricata una nuova immagine della fotocamera dal device {0}",
+ "CameraImageUploadedFrom": "È stata caricata una nuova fotografia da {0}",
"Channels": "Canali",
"ChapterNameValue": "Capitolo {0}",
"Collections": "Collezioni",
diff --git a/Emby.Server.Implementations/Localization/Core/mk.json b/Emby.Server.Implementations/Localization/Core/mk.json
index 8df137302..bbdf99aba 100644
--- a/Emby.Server.Implementations/Localization/Core/mk.json
+++ b/Emby.Server.Implementations/Localization/Core/mk.json
@@ -91,5 +91,12 @@
"Songs": "Песни",
"Shows": "Серии",
"ServerNameNeedsToBeRestarted": "{0} треба да се рестартира",
- "ScheduledTaskStartedWithName": "{0} започна"
+ "ScheduledTaskStartedWithName": "{0} започна",
+ "TaskRefreshChapterImages": "Извези Слики од Поглавје",
+ "TaskCleanCacheDescription": "Ги брише кешираните фајлови што не се повеќе потребни од системот.",
+ "TaskCleanCache": "Исчисти Го Кешот",
+ "TasksChannelsCategory": "Интернет Канали",
+ "TasksApplicationCategory": "Апликација",
+ "TasksLibraryCategory": "Библиотека",
+ "TasksMaintenanceCategory": "Одржување"
}
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index baa12e98e..41c74d54d 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -5,7 +5,7 @@
"Artists": "Artiesten",
"AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
"Books": "Boeken",
- "CameraImageUploadedFrom": "Er is een nieuwe afbeelding toegevoegd via {0}",
+ "CameraImageUploadedFrom": "Er is een nieuwe camera afbeelding toegevoegd via {0}",
"Channels": "Kanalen",
"ChapterNameValue": "Hoofdstuk {0}",
"Collections": "Verzamelingen",
@@ -26,7 +26,7 @@
"HeaderLiveTV": "Live TV",
"HeaderNextUp": "Volgende",
"HeaderRecordingGroups": "Opnamegroepen",
- "HomeVideos": "Start video's",
+ "HomeVideos": "Home video's",
"Inherit": "Overerven",
"ItemAddedWithName": "{0} is toegevoegd aan de bibliotheek",
"ItemRemovedWithName": "{0} is verwijderd uit de bibliotheek",
@@ -50,7 +50,7 @@
"NotificationOptionAudioPlayback": "Muziek gestart",
"NotificationOptionAudioPlaybackStopped": "Muziek gestopt",
"NotificationOptionCameraImageUploaded": "Camera-afbeelding geüpload",
- "NotificationOptionInstallationFailed": "Installatie mislukking",
+ "NotificationOptionInstallationFailed": "Installatie mislukt",
"NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
"NotificationOptionPluginError": "Plug-in fout",
"NotificationOptionPluginInstalled": "Plug-in geïnstalleerd",
diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json
index b60dd33bd..60c58d472 100644
--- a/Emby.Server.Implementations/Localization/Core/sl-SI.json
+++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json
@@ -92,5 +92,26 @@
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
"ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
"ValueSpecialEpisodeName": "Poseben - {0}",
- "VersionNumber": "Različica {0}"
+ "VersionNumber": "Različica {0}",
+ "TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise",
+ "TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.",
+ "TaskRefreshChannels": "Osveži kanale",
+ "TaskCleanTranscodeDescription": "Izbriše več kot dan stare datoteke prekodiranja.",
+ "TaskCleanTranscode": "Počisti mapo prekodiranja",
+ "TaskUpdatePluginsDescription": "Prenese in namesti posodobitve za dodatke, ki imajo omogočene samodejne posodobitve.",
+ "TaskUpdatePlugins": "Posodobi dodatke",
+ "TaskRefreshPeopleDescription": "Osveži metapodatke za igralce in režiserje v vaši knjižnici.",
+ "TaskRefreshPeople": "Osveži osebe",
+ "TaskCleanLogsDescription": "Izbriše dnevniške datoteke starejše od {0} dni.",
+ "TaskCleanLogs": "Počisti mapo dnevnika",
+ "TaskRefreshLibraryDescription": "Preišče vašo knjižnico za nove datoteke in osveži metapodatke.",
+ "TaskRefreshLibrary": "Preišči knjižnico predstavnosti",
+ "TaskRefreshChapterImagesDescription": "Ustvari sličice za poglavja videoposnetkov.",
+ "TaskRefreshChapterImages": "Izvleči slike poglavij",
+ "TaskCleanCacheDescription": "Izbriše predpomnjene datoteke, ki niso več potrebne.",
+ "TaskCleanCache": "Počisti mapo predpomnilnika",
+ "TasksChannelsCategory": "Spletni kanali",
+ "TasksApplicationCategory": "Aplikacija",
+ "TasksLibraryCategory": "Knjižnica",
+ "TasksMaintenanceCategory": "Vzdrževanje"
}
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index b7c50394a..c8662b2ca 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -9,7 +9,7 @@
"Channels": "Kanaler",
"ChapterNameValue": "Kapitel {0}",
"Collections": "Samlingar",
- "DeviceOfflineWithName": "{0} har tappat anslutningen",
+ "DeviceOfflineWithName": "{0} har kopplat från",
"DeviceOnlineWithName": "{0} är ansluten",
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
"Favorites": "Favoriter",
@@ -50,7 +50,7 @@
"NotificationOptionAudioPlayback": "Ljuduppspelning har påbörjats",
"NotificationOptionAudioPlaybackStopped": "Ljuduppspelning stoppades",
"NotificationOptionCameraImageUploaded": "Kamerabild har laddats upp",
- "NotificationOptionInstallationFailed": "Fel vid installation",
+ "NotificationOptionInstallationFailed": "Installationen misslyckades",
"NotificationOptionNewLibraryContent": "Nytt innehåll har lagts till",
"NotificationOptionPluginError": "Fel uppstod med tillägget",
"NotificationOptionPluginInstalled": "Tillägg har installerats",
@@ -113,5 +113,6 @@
"TasksChannelsCategory": "Internetkanaler",
"TasksApplicationCategory": "Applikation",
"TasksLibraryCategory": "Bibliotek",
- "TasksMaintenanceCategory": "Underhåll"
+ "TasksMaintenanceCategory": "Underhåll",
+ "TaskRefreshPeople": "Uppdatera Personer"
}
diff --git a/Emby.Server.Implementations/Localization/Core/uk.json b/Emby.Server.Implementations/Localization/Core/uk.json
new file mode 100644
index 000000000..b2e0b66fe
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/uk.json
@@ -0,0 +1,36 @@
+{
+ "MusicVideos": "Музичні відео",
+ "Music": "Музика",
+ "Movies": "Фільми",
+ "MessageApplicationUpdatedTo": "Jellyfin Server був оновлений до версії {0}",
+ "MessageApplicationUpdated": "Jellyfin Server був оновлений",
+ "Latest": "Останні",
+ "LabelIpAddressValue": "IP-адреси: {0}",
+ "ItemRemovedWithName": "{0} видалено з бібліотеки",
+ "ItemAddedWithName": "{0} додано до бібліотеки",
+ "HeaderNextUp": "Наступний",
+ "HeaderLiveTV": "Ефірне ТБ",
+ "HeaderFavoriteSongs": "Улюблені пісні",
+ "HeaderFavoriteShows": "Улюблені шоу",
+ "HeaderFavoriteEpisodes": "Улюблені серії",
+ "HeaderFavoriteArtists": "Улюблені виконавці",
+ "HeaderFavoriteAlbums": "Улюблені альбоми",
+ "HeaderContinueWatching": "Продовжити перегляд",
+ "HeaderCameraUploads": "Завантажено з камери",
+ "HeaderAlbumArtists": "Виконавці альбомів",
+ "Genres": "Жанри",
+ "Folders": "Директорії",
+ "Favorites": "Улюблені",
+ "DeviceOnlineWithName": "{0} під'єднано",
+ "DeviceOfflineWithName": "{0} від'єднано",
+ "Collections": "Колекції",
+ "ChapterNameValue": "Глава {0}",
+ "Channels": "Канали",
+ "CameraImageUploadedFrom": "Нова фотографія завантажена з {0}",
+ "Books": "Книги",
+ "AuthenticationSucceededWithUserName": "{0} успішно авторизовані",
+ "Artists": "Виконавці",
+ "Application": "Додаток",
+ "AppDeviceValues": "Додаток: {0}, Пристрій: {1}",
+ "Albums": "Альбоми"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json
index 224748e61..a67a67582 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-HK.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json
@@ -1,6 +1,6 @@
{
"Albums": "專輯",
- "AppDeviceValues": "軟體: {0}, 設備: {1}",
+ "AppDeviceValues": "軟件: {0}, 設備: {1}",
"Application": "應用程式",
"Artists": "藝人",
"AuthenticationSucceededWithUserName": "{0} 授權成功",
@@ -92,5 +92,8 @@
"UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
"ValueHasBeenAddedToLibrary": "{0} 已添加到你的媒體庫",
"ValueSpecialEpisodeName": "特典 - {0}",
- "VersionNumber": "版本{0}"
+ "VersionNumber": "版本{0}",
+ "TaskDownloadMissingSubtitles": "下載遺失的字幕",
+ "TaskUpdatePlugins": "更新插件",
+ "TasksApplicationCategory": "應用程式"
}
diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs
index 9c638f439..ee5131c1f 100644
--- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs
+++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs
@@ -63,6 +63,9 @@ namespace Emby.Server.Implementations.SocketSharp
if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip))
{
ip = Request.HttpContext.Connection.RemoteIpAddress;
+
+ // Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests)
+ ip ??= IPAddress.Loopback;
}
}
@@ -90,7 +93,10 @@ namespace Emby.Server.Implementations.SocketSharp
public IQueryCollection QueryString => Request.Query;
- public bool IsLocal => Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
+ public bool IsLocal =>
+ (Request.HttpContext.Connection.LocalIpAddress == null
+ && Request.HttpContext.Connection.RemoteIpAddress == null)
+ || Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
public string HttpMethod => Request.Method;