aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json66
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs44
3 files changed, 80 insertions, 32 deletions
diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
index 59af7ce8a..86242d137 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
@@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
{
public class BookResolver : MediaBrowser.Controller.Resolvers.ItemResolver<Book>
{
- private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".opf", ".pdf" };
+ private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".pdf" };
protected override Book Resolve(ItemResolveArgs args)
{
diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json
index 0c19a0152..3c51d64e0 100644
--- a/Emby.Server.Implementations/Localization/Core/fr-CA.json
+++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json
@@ -1,9 +1,9 @@
{
"Albums": "Albums",
- "AppDeviceValues": "Application : {0}, Appareil : {1}",
+ "AppDeviceValues": "App : {0}, Appareil : {1}",
"Application": "Application",
"Artists": "Artistes",
- "AuthenticationSucceededWithUserName": "{0} s'est authentifié avec succès",
+ "AuthenticationSucceededWithUserName": "{0} authentifié avec succès",
"Books": "Livres",
"CameraImageUploadedFrom": "Une nouvelle image de caméra a été téléchargée depuis {0}",
"Channels": "Chaînes",
@@ -11,11 +11,11 @@
"Collections": "Collections",
"DeviceOfflineWithName": "{0} s'est déconnecté",
"DeviceOnlineWithName": "{0} est connecté",
- "FailedLoginAttemptWithUserName": "Échec d'une tentative de connexion de {0}",
+ "FailedLoginAttemptWithUserName": "Tentative de connexion échoué par {0}",
"Favorites": "Favoris",
"Folders": "Dossiers",
"Genres": "Genres",
- "HeaderAlbumArtists": "Artistes",
+ "HeaderAlbumArtists": "Artistes de l'album",
"HeaderContinueWatching": "Reprendre le visionnement",
"HeaderFavoriteAlbums": "Albums favoris",
"HeaderFavoriteArtists": "Artistes favoris",
@@ -26,12 +26,12 @@
"HeaderNextUp": "À Suivre",
"HeaderRecordingGroups": "Groupes d'enregistrements",
"HomeVideos": "Vidéos personnelles",
- "Inherit": "Hériter",
+ "Inherit": "Hérite",
"ItemAddedWithName": "{0} a été ajouté à la médiathèque",
"ItemRemovedWithName": "{0} a été supprimé de la médiathèque",
"LabelIpAddressValue": "Adresse IP : {0}",
"LabelRunningTimeValue": "Durée : {0}",
- "Latest": "Derniers",
+ "Latest": "Plus récent",
"MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
"MessageApplicationUpdatedTo": "Le serveur Jellyfin a été mis à jour vers la version {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
@@ -40,15 +40,15 @@
"Movies": "Films",
"Music": "Musique",
"MusicVideos": "Vidéos musicales",
- "NameInstallFailed": "{0} échec d'installation",
+ "NameInstallFailed": "échec d'installation de {0}",
"NameSeasonNumber": "Saison {0}",
"NameSeasonUnknown": "Saison Inconnue",
- "NewVersionIsAvailable": "Une nouvelle version du serveur Jellyfin est disponible au téléchargement.",
+ "NewVersionIsAvailable": "Une nouvelle version du serveur Jellyfin est disponible.",
"NotificationOptionApplicationUpdateAvailable": "Mise à jour de l'application disponible",
"NotificationOptionApplicationUpdateInstalled": "Mise à jour de l'application installée",
"NotificationOptionAudioPlayback": "Lecture audio démarrée",
"NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée",
- "NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée",
+ "NotificationOptionCameraImageUploaded": "Image d'appareil photo transférée",
"NotificationOptionInstallationFailed": "Échec d'installation",
"NotificationOptionNewLibraryContent": "Nouveau contenu ajouté",
"NotificationOptionPluginError": "Erreur d'extension",
@@ -70,9 +70,9 @@
"ScheduledTaskFailedWithName": "{0} a échoué",
"ScheduledTaskStartedWithName": "{0} a commencé",
"ServerNameNeedsToBeRestarted": "{0} doit être redémarré",
- "Shows": "Émissions",
+ "Shows": "Séries",
"Songs": "Chansons",
- "StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.",
+ "StartupEmbyServerIsLoading": "Serveur Jellyfin en cours de chargement. Réessayez dans quelques instants.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
"Sync": "Synchroniser",
@@ -80,39 +80,43 @@
"TvShows": "Séries Télé",
"User": "Utilisateur",
"UserCreatedWithName": "L'utilisateur {0} a été créé",
- "UserDeletedWithName": "L'utilisateur {0} a été supprimé",
- "UserDownloadingItemWithValues": "{0} est en train de télécharger {1}",
+ "UserDeletedWithName": "L'utilisateur {0} supprimé",
+ "UserDownloadingItemWithValues": "{0} télécharge {1}",
"UserLockedOutWithName": "L'utilisateur {0} a été verrouillé",
- "UserOfflineFromDevice": "{0} s'est déconnecté depuis {1}",
- "UserOnlineFromDevice": "{0} s'est connecté depuis {1}",
- "UserPasswordChangedWithName": "Le mot de passe pour l'utilisateur {0} a été modifié",
+ "UserOfflineFromDevice": "{0} s'est déconnecté de {1}",
+ "UserOnlineFromDevice": "{0} s'est connecté de {1}",
+ "UserPasswordChangedWithName": "Le mot de passe de utilisateur {0} a été modifié",
"UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}",
- "UserStartedPlayingItemWithValues": "{0} est en train de lire {1} sur {2}",
- "UserStoppedPlayingItemWithValues": "{0} vient d'arrêter la lecture de {1} sur {2}",
+ "UserStartedPlayingItemWithValues": "{0} joue {1} sur {2}",
+ "UserStoppedPlayingItemWithValues": "{0} a terminé la lecture de {1} sur {2}",
"ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre médiathèque",
"ValueSpecialEpisodeName": "Spécial - {0}",
"VersionNumber": "Version {0}",
- "TasksLibraryCategory": "Bibliothèque",
+ "TasksLibraryCategory": "Médiathèque",
"TasksMaintenanceCategory": "Entretien",
- "TaskDownloadMissingSubtitlesDescription": "Recherche l'internet pour des sous-titres manquants à base de métadonnées configurées.",
+ "TaskDownloadMissingSubtitlesDescription": "Recherche les sous-titres manquant sur l'internet selon la configuration des métadonnées.",
"TaskDownloadMissingSubtitles": "Télécharger les sous-titres manquants",
- "TaskRefreshChannelsDescription": "Rafraîchit des informations des chaines internet.",
- "TaskRefreshChannels": "Rafraîchir des chaines",
- "TaskCleanTranscodeDescription": "Supprime les fichiers de transcodage de plus d'un jour.",
+ "TaskRefreshChannelsDescription": "Rafraîchit les informations des chaines internet.",
+ "TaskRefreshChannels": "Rafraîchir les chaines",
+ "TaskCleanTranscodeDescription": "Supprime les fichiers de transcodage datant de plus d'un jour.",
"TaskCleanTranscode": "Nettoyer le répertoire de transcodage",
- "TaskUpdatePluginsDescription": "Télécharger et installer les mises à jours des extensions qui sont configurés pour les m.à.j. automisés.",
+ "TaskUpdatePluginsDescription": "Télécharge et installe les mises à jours des extensions configurés pour les m.à.j. automatiques.",
"TaskUpdatePlugins": "Mise à jour des extensions",
- "TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre bibliothèque de médias.",
- "TaskRefreshPeople": "Rafraîchir les acteurs",
- "TaskCleanLogsDescription": "Supprime les journaux qui ont plus que {0} jours.",
+ "TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre médiathèque.",
+ "TaskRefreshPeople": "Rafraîchir les personnes",
+ "TaskCleanLogsDescription": "Supprime les journaux plus vieux que {0} jours.",
"TaskCleanLogs": "Nettoyer le répertoire des journaux",
- "TaskRefreshLibraryDescription": "Analyse votre bibliothèque média pour trouver de nouveaux fichiers et rafraîchit les métadonnées.",
+ "TaskRefreshLibraryDescription": "Analyse votre médiathèque pour trouver de nouveaux fichiers et rafraîchit les métadonnées.",
"TaskRefreshChapterImages": "Extraire les images de chapitre",
"TaskRefreshChapterImagesDescription": "Créer des vignettes pour les vidéos qui ont des chapitres.",
- "TaskRefreshLibrary": "Analyser la bibliothèque de médias",
+ "TaskRefreshLibrary": "Analyser la médiathèque",
"TaskCleanCache": "Nettoyer le répertoire des fichiers temporaires",
"TasksApplicationCategory": "Application",
"TaskCleanCacheDescription": "Supprime les fichiers temporaires qui ne sont plus nécessaire pour le système.",
- "TasksChannelsCategory": "Canaux Internet",
- "Default": "Par défaut"
+ "TasksChannelsCategory": "Chaines Internet",
+ "Default": "Par défaut",
+ "TaskCleanActivityLogDescription": "Éfface les entrées du journal plus anciennes que l'âge configuré.",
+ "TaskCleanActivityLog": "Nettoyer le journal d'activité",
+ "Undefined": "Indéfini",
+ "Forced": "Forcé"
}
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
index 1d87036a2..aee959c53 100644
--- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
+++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
@@ -42,6 +42,12 @@ namespace Emby.Server.Implementations.SyncPlay
private readonly ILibraryManager _libraryManager;
/// <summary>
+ /// The map between users and counter of active sessions.
+ /// </summary>
+ private readonly ConcurrentDictionary<Guid, int> _activeUsers =
+ new ConcurrentDictionary<Guid, int>();
+
+ /// <summary>
/// The map between sessions and groups.
/// </summary>
private readonly ConcurrentDictionary<string, Group> _sessionToGroupMap =
@@ -122,6 +128,7 @@ namespace Emby.Server.Implementations.SyncPlay
throw new InvalidOperationException("Could not add session to group!");
}
+ UpdateSessionsCounter(session.UserId, 1);
group.CreateGroup(session, request, cancellationToken);
}
}
@@ -172,6 +179,7 @@ namespace Emby.Server.Implementations.SyncPlay
if (existingGroup.GroupId.Equals(request.GroupId))
{
// Restore session.
+ UpdateSessionsCounter(session.UserId, 1);
group.SessionJoin(session, request, cancellationToken);
return;
}
@@ -185,6 +193,7 @@ namespace Emby.Server.Implementations.SyncPlay
throw new InvalidOperationException("Could not add session to group!");
}
+ UpdateSessionsCounter(session.UserId, 1);
group.SessionJoin(session, request, cancellationToken);
}
}
@@ -223,6 +232,7 @@ namespace Emby.Server.Implementations.SyncPlay
throw new InvalidOperationException("Could not remove session from group!");
}
+ UpdateSessionsCounter(session.UserId, -1);
group.SessionLeave(session, request, cancellationToken);
if (group.IsGroupEmpty())
@@ -318,6 +328,19 @@ namespace Emby.Server.Implementations.SyncPlay
}
}
+ /// <inheritdoc />
+ public bool IsUserActive(Guid userId)
+ {
+ if (_activeUsers.TryGetValue(userId, out var sessionsCounter))
+ {
+ return sessionsCounter > 0;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
@@ -343,5 +366,26 @@ namespace Emby.Server.Implementations.SyncPlay
JoinGroup(session, request, CancellationToken.None);
}
}
+
+ private void UpdateSessionsCounter(Guid userId, int toAdd)
+ {
+ // Update sessions counter.
+ var newSessionsCounter = _activeUsers.AddOrUpdate(
+ userId,
+ 1,
+ (key, sessionsCounter) => sessionsCounter + toAdd);
+
+ // Should never happen.
+ if (newSessionsCounter < 0)
+ {
+ throw new InvalidOperationException("Sessions counter is negative!");
+ }
+
+ // Clean record if user has no more active sessions.
+ if (newSessionsCounter == 0)
+ {
+ _activeUsers.TryRemove(new KeyValuePair<Guid, int>(userId, newSessionsCounter));
+ }
+ }
}
}