mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
7cde256402
@ -37,6 +37,7 @@
|
|||||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.7.0" />
|
<PackageReference Include="ServiceStack.Text.Core" Version="5.7.0" />
|
||||||
<PackageReference Include="sharpcompress" Version="0.24.0" />
|
<PackageReference Include="sharpcompress" Version="0.24.0" />
|
||||||
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.0.1" />
|
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.0.1" />
|
||||||
|
<PackageReference Include="System.Interactive.Async" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1 +1,96 @@
|
|||||||
{}
|
{
|
||||||
|
"Artists": "Kunstenare",
|
||||||
|
"Channels": "Kanale",
|
||||||
|
"Folders": "Fouers",
|
||||||
|
"Favorites": "Gunstelinge",
|
||||||
|
"HeaderFavoriteShows": "Gunsteling Vertonings",
|
||||||
|
"ValueSpecialEpisodeName": "Spesiaal - {0}",
|
||||||
|
"HeaderAlbumArtists": "Album Kunstenaars",
|
||||||
|
"Books": "Boeke",
|
||||||
|
"HeaderNextUp": "Volgende",
|
||||||
|
"Movies": "Rolprente",
|
||||||
|
"Shows": "Program",
|
||||||
|
"HeaderContinueWatching": "Hou Aan Kyk",
|
||||||
|
"HeaderFavoriteEpisodes": "Gunsteling Episodes",
|
||||||
|
"Photos": "Fotos",
|
||||||
|
"Playlists": "Speellysse",
|
||||||
|
"HeaderFavoriteArtists": "Gunsteling Kunstenaars",
|
||||||
|
"HeaderFavoriteAlbums": "Gunsteling Albums",
|
||||||
|
"Sync": "Sinkroniseer",
|
||||||
|
"HeaderFavoriteSongs": "Gunsteling Liedjies",
|
||||||
|
"Songs": "Liedjies",
|
||||||
|
"DeviceOnlineWithName": "{0} is verbind",
|
||||||
|
"DeviceOfflineWithName": "{0} het afgesluit",
|
||||||
|
"Collections": "Versamelings",
|
||||||
|
"Inherit": "Ontvang",
|
||||||
|
"HeaderLiveTV": "Live TV",
|
||||||
|
"Application": "Program",
|
||||||
|
"AppDeviceValues": "App: {0}, Toestel: {1}",
|
||||||
|
"VersionNumber": "Weergawe {0}",
|
||||||
|
"ValueHasBeenAddedToLibrary": "{0} is by jou media biblioteek bygevoeg",
|
||||||
|
"UserStoppedPlayingItemWithValues": "{0} het klaar {1} op {2} gespeel",
|
||||||
|
"UserStartedPlayingItemWithValues": "{0} is besig om {1} op {2} te speel",
|
||||||
|
"UserPolicyUpdatedWithName": "Gebruiker beleid is verander vir {0}",
|
||||||
|
"UserPasswordChangedWithName": "Gebruiker {0} se wagwoord is verander",
|
||||||
|
"UserOnlineFromDevice": "{0} is aanlyn van {1}",
|
||||||
|
"UserOfflineFromDevice": "{0} is ontkoppel van {1}",
|
||||||
|
"UserLockedOutWithName": "Gebruiker {0} is uitgesluit",
|
||||||
|
"UserDownloadingItemWithValues": "{0} is besig om {1} af te laai",
|
||||||
|
"UserDeletedWithName": "Gebruiker {0} is verwyder",
|
||||||
|
"UserCreatedWithName": "Gebruiker {0} is geskep",
|
||||||
|
"User": "Gebruiker",
|
||||||
|
"TvShows": "TV Programme",
|
||||||
|
"System": "Stelsel",
|
||||||
|
"SubtitlesDownloadedForItem": "Ondertitels afgelaai vir {0}",
|
||||||
|
"SubtitleDownloadFailureFromForItem": "Ondertitels het misluk om af te laai van {0} vir {1}",
|
||||||
|
"StartupEmbyServerIsLoading": "Jellyfin Bediener is besig om te laai. Probeer weer in 'n kort tyd.",
|
||||||
|
"ServerNameNeedsToBeRestarted": "{0} moet herbegin word",
|
||||||
|
"ScheduledTaskStartedWithName": "{0} het begin",
|
||||||
|
"ScheduledTaskFailedWithName": "{0} het misluk",
|
||||||
|
"ProviderValue": "Voorsiener: {0}",
|
||||||
|
"PluginUpdatedWithName": "{0} was opgedateer",
|
||||||
|
"PluginUninstalledWithName": "{0} was verwyder",
|
||||||
|
"PluginInstalledWithName": "{0} is geïnstalleer",
|
||||||
|
"Plugin": "Inprop module",
|
||||||
|
"NotificationOptionVideoPlaybackStopped": "Video terugspeel het gestop",
|
||||||
|
"NotificationOptionVideoPlayback": "Video terugspeel het begin",
|
||||||
|
"NotificationOptionUserLockedOut": "Gebruiker uitgeslyt",
|
||||||
|
"NotificationOptionTaskFailed": "Geskeduleerde taak het misluk",
|
||||||
|
"NotificationOptionServerRestartRequired": "Bediener herbegin nodig",
|
||||||
|
"NotificationOptionPluginUpdateInstalled": "Nuwe inprop module geïnstalleer",
|
||||||
|
"NotificationOptionPluginUninstalled": "Inprop module verwyder",
|
||||||
|
"NotificationOptionPluginInstalled": "Inprop module geïnstalleer",
|
||||||
|
"NotificationOptionPluginError": "Inprop module het misluk",
|
||||||
|
"NotificationOptionNewLibraryContent": "Nuwe inhoud bygevoeg",
|
||||||
|
"NotificationOptionInstallationFailed": "Installering het misluk",
|
||||||
|
"NotificationOptionCameraImageUploaded": "Kamera foto is opgelaai",
|
||||||
|
"NotificationOptionAudioPlaybackStopped": "Oudio terugspeel het gestop",
|
||||||
|
"NotificationOptionAudioPlayback": "Oudio terugspeel het begin",
|
||||||
|
"NotificationOptionApplicationUpdateInstalled": "Nuwe program weergawe geïnstalleer",
|
||||||
|
"NotificationOptionApplicationUpdateAvailable": "Nuwe program weergawe beskikbaar",
|
||||||
|
"NewVersionIsAvailable": "'n Nuwe Jellyfin Bedienaar weergawe kan afgelaai word.",
|
||||||
|
"NameSeasonUnknown": "Seisoen Onbekend",
|
||||||
|
"NameSeasonNumber": "Seisoen {0}",
|
||||||
|
"NameInstallFailed": "{0} installering het misluk",
|
||||||
|
"MusicVideos": "Musiek videos",
|
||||||
|
"Music": "Musiek",
|
||||||
|
"MixedContent": "Gemengde inhoud",
|
||||||
|
"MessageServerConfigurationUpdated": "Bediener konfigurasie is opgedateer",
|
||||||
|
"MessageNamedServerConfigurationUpdatedWithValue": "Bediener konfigurasie seksie {0} is opgedateer",
|
||||||
|
"MessageApplicationUpdatedTo": "Jellyfin Bediener is opgedateer na {0}",
|
||||||
|
"MessageApplicationUpdated": "Jellyfin Bediener is opgedateer",
|
||||||
|
"Latest": "Nuutste",
|
||||||
|
"LabelRunningTimeValue": "Lopende tyd: {0}",
|
||||||
|
"LabelIpAddressValue": "IP adres: {0}",
|
||||||
|
"ItemRemovedWithName": "{0} is uit versameling verwyder",
|
||||||
|
"ItemAddedWithName": "{0} is in die versameling",
|
||||||
|
"HomeVideos": "Tuis opnames",
|
||||||
|
"HeaderRecordingGroups": "Groep Opnames",
|
||||||
|
"HeaderCameraUploads": "Kamera Oplaai",
|
||||||
|
"Genres": "Genres",
|
||||||
|
"FailedLoginAttemptWithUserName": "Mislukte aansluiting van {0}",
|
||||||
|
"ChapterNameValue": "Hoofstuk",
|
||||||
|
"CameraImageUploadedFrom": "'n Nuwe kamera photo opgelaai van {0}",
|
||||||
|
"AuthenticationSucceededWithUserName": "{0} suksesvol geverifieer",
|
||||||
|
"Albums": "Albums"
|
||||||
|
}
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
"AppDeviceValues": "App: {0}, Gerät: {1}",
|
"AppDeviceValues": "App: {0}, Gerät: {1}",
|
||||||
"Application": "Anwendung",
|
"Application": "Anwendung",
|
||||||
"Artists": "Interpreten",
|
"Artists": "Interpreten",
|
||||||
"AuthenticationSucceededWithUserName": "{0} hat sich angemeldet",
|
"AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich angemeldet",
|
||||||
"Books": "Bücher",
|
"Books": "Bücher",
|
||||||
"CameraImageUploadedFrom": "Ein neues Foto wurde hochgeladen von {0}",
|
"CameraImageUploadedFrom": "Ein neues Foto wurde hochgeladen von {0}",
|
||||||
"Channels": "Kanäle",
|
"Channels": "Kanäle",
|
||||||
"ChapterNameValue": "Kapitel {0}",
|
"ChapterNameValue": "Kapitel {0}",
|
||||||
"Collections": "Sammlungen",
|
"Collections": "Sammlungen",
|
||||||
"DeviceOfflineWithName": "{0} wurde getrennt",
|
"DeviceOfflineWithName": "{0} wurde getrennt",
|
||||||
"DeviceOnlineWithName": "{0} hat sich verbunden",
|
"DeviceOnlineWithName": "{0} ist verbunden",
|
||||||
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
|
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
|
||||||
"Favorites": "Favoriten",
|
"Favorites": "Favoriten",
|
||||||
"Folders": "Verzeichnisse",
|
"Folders": "Verzeichnisse",
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
"CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
|
"CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
|
||||||
"Channels": "Channels",
|
"Channels": "Channels",
|
||||||
"ChapterNameValue": "Chapter {0}",
|
"ChapterNameValue": "Chapter {0}",
|
||||||
"Collections": "Versamelings",
|
"Collections": "Collections",
|
||||||
"DeviceOfflineWithName": "{0} het afgesluit",
|
"DeviceOfflineWithName": "{0} has disconnected",
|
||||||
"DeviceOnlineWithName": "{0} is verbind",
|
"DeviceOnlineWithName": "{0} is connected",
|
||||||
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
|
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
|
||||||
"Favorites": "Favorites",
|
"Favorites": "Favorites",
|
||||||
"Folders": "Folders",
|
"Folders": "Folders",
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
{
|
{
|
||||||
"Albums": "אלבומים",
|
"Albums": "אלבומים",
|
||||||
"AppDeviceValues": "App: {0}, Device: {1}",
|
"AppDeviceValues": "יישום: {0}, מכשיר: {1}",
|
||||||
"Application": "אפליקציה",
|
"Application": "אפליקציה",
|
||||||
"Artists": "אמנים",
|
"Artists": "אמנים",
|
||||||
"AuthenticationSucceededWithUserName": "{0} successfully authenticated",
|
"AuthenticationSucceededWithUserName": "{0} זוהה בהצלחה",
|
||||||
"Books": "ספרים",
|
"Books": "ספרים",
|
||||||
"CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
|
"CameraImageUploadedFrom": "תמונה חדשה הועלתה מ{0}",
|
||||||
"Channels": "Channels",
|
"Channels": "ערוצים",
|
||||||
"ChapterNameValue": "Chapter {0}",
|
"ChapterNameValue": "פרק {0}",
|
||||||
"Collections": "Collections",
|
"Collections": "קולקציות",
|
||||||
"DeviceOfflineWithName": "{0} has disconnected",
|
"DeviceOfflineWithName": "{0} התנתק",
|
||||||
"DeviceOnlineWithName": "{0} is connected",
|
"DeviceOnlineWithName": "{0} מחובר",
|
||||||
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
|
"FailedLoginAttemptWithUserName": "ניסיון כניסה שגוי מ{0}",
|
||||||
"Favorites": "Favorites",
|
"Favorites": "אהובים",
|
||||||
"Folders": "Folders",
|
"Folders": "תיקיות",
|
||||||
"Genres": "ז'אנרים",
|
"Genres": "ז'אנרים",
|
||||||
"HeaderAlbumArtists": "Album Artists",
|
"HeaderAlbumArtists": "אמני האלבום",
|
||||||
"HeaderCameraUploads": "Camera Uploads",
|
"HeaderCameraUploads": "העלאות ממצלמה",
|
||||||
"HeaderContinueWatching": "המשך בצפייה",
|
"HeaderContinueWatching": "המשך לצפות",
|
||||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
"HeaderFavoriteAlbums": "אלבומים שאהבתי",
|
||||||
"HeaderFavoriteArtists": "Favorite Artists",
|
"HeaderFavoriteArtists": "אמנים שאהבתי",
|
||||||
"HeaderFavoriteEpisodes": "Favorite Episodes",
|
"HeaderFavoriteEpisodes": "פרקים אהובים",
|
||||||
"HeaderFavoriteShows": "Favorite Shows",
|
"HeaderFavoriteShows": "תוכניות אהובות",
|
||||||
"HeaderFavoriteSongs": "Favorite Songs",
|
"HeaderFavoriteSongs": "שירים שאהבתי",
|
||||||
"HeaderLiveTV": "Live TV",
|
"HeaderLiveTV": "טלוויזיה בשידור חי",
|
||||||
"HeaderNextUp": "Next Up",
|
"HeaderNextUp": "הבא",
|
||||||
"HeaderRecordingGroups": "קבוצות הקלטה",
|
"HeaderRecordingGroups": "קבוצות הקלטה",
|
||||||
"HomeVideos": "Home videos",
|
"HomeVideos": "סרטונים בייתים",
|
||||||
"Inherit": "Inherit",
|
"Inherit": "הורש",
|
||||||
"ItemAddedWithName": "{0} was added to the library",
|
"ItemAddedWithName": "{0} was added to the library",
|
||||||
"ItemRemovedWithName": "{0} was removed from the library",
|
"ItemRemovedWithName": "{0} נמחק מהספרייה",
|
||||||
"LabelIpAddressValue": "Ip address: {0}",
|
"LabelIpAddressValue": "Ip כתובת: {0}",
|
||||||
"LabelRunningTimeValue": "Running time: {0}",
|
"LabelRunningTimeValue": "משך צפייה: {0}",
|
||||||
"Latest": "אחרון",
|
"Latest": "אחרון",
|
||||||
"MessageApplicationUpdated": "Jellyfin Server has been updated",
|
"MessageApplicationUpdated": "שרת הJellyfin עודכן",
|
||||||
"MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
|
"MessageApplicationUpdatedTo": "שרת הJellyfin עודכן לגרסא {0}",
|
||||||
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
|
"MessageNamedServerConfigurationUpdatedWithValue": "הגדרת השרת {0} שונתה",
|
||||||
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
||||||
"MixedContent": "תוכן מעורב",
|
"MixedContent": "תוכן מעורב",
|
||||||
"Movies": "סרטים",
|
"Movies": "סרטים",
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"NotificationOptionAudioPlayback": "Audio playback started",
|
"NotificationOptionAudioPlayback": "Audio playback started",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
|
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
|
||||||
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
|
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
|
||||||
"NotificationOptionInstallationFailed": "Installation failure",
|
"NotificationOptionInstallationFailed": "התקנה נכשלה",
|
||||||
"NotificationOptionNewLibraryContent": "New content added",
|
"NotificationOptionNewLibraryContent": "New content added",
|
||||||
"NotificationOptionPluginError": "Plugin failure",
|
"NotificationOptionPluginError": "Plugin failure",
|
||||||
"NotificationOptionPluginInstalled": "Plugin installed",
|
"NotificationOptionPluginInstalled": "Plugin installed",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"Artists": "Umelci",
|
"Artists": "Umelci",
|
||||||
"AuthenticationSucceededWithUserName": "{0} úspešne overený",
|
"AuthenticationSucceededWithUserName": "{0} úspešne overený",
|
||||||
"Books": "Knihy",
|
"Books": "Knihy",
|
||||||
"CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
|
"CameraImageUploadedFrom": "Z {0} bola nahraná nová fotografia",
|
||||||
"Channels": "Kanály",
|
"Channels": "Kanály",
|
||||||
"ChapterNameValue": "Kapitola {0}",
|
"ChapterNameValue": "Kapitola {0}",
|
||||||
"Collections": "Zbierky",
|
"Collections": "Zbierky",
|
||||||
@ -15,9 +15,9 @@
|
|||||||
"Favorites": "Obľúbené",
|
"Favorites": "Obľúbené",
|
||||||
"Folders": "Priečinky",
|
"Folders": "Priečinky",
|
||||||
"Genres": "Žánre",
|
"Genres": "Žánre",
|
||||||
"HeaderAlbumArtists": "Album Artists",
|
"HeaderAlbumArtists": "Albumy umelcov",
|
||||||
"HeaderCameraUploads": "Nahrané fotografie",
|
"HeaderCameraUploads": "Nahrané fotografie",
|
||||||
"HeaderContinueWatching": "Pokračujte v pozeraní",
|
"HeaderContinueWatching": "Pokračovať v pozeraní",
|
||||||
"HeaderFavoriteAlbums": "Obľúbené albumy",
|
"HeaderFavoriteAlbums": "Obľúbené albumy",
|
||||||
"HeaderFavoriteArtists": "Obľúbení umelci",
|
"HeaderFavoriteArtists": "Obľúbení umelci",
|
||||||
"HeaderFavoriteEpisodes": "Obľúbené epizódy",
|
"HeaderFavoriteEpisodes": "Obľúbené epizódy",
|
||||||
|
@ -7,8 +7,6 @@ using System.Net.NetworkInformation;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Networking
|
namespace Emby.Server.Implementations.Networking
|
||||||
@ -55,10 +53,7 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
_macAddresses = null;
|
_macAddresses = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NetworkChanged != null)
|
NetworkChanged?.Invoke(this, EventArgs.Empty);
|
||||||
{
|
|
||||||
NetworkChanged(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
|
public IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
|
||||||
@ -261,10 +256,10 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedSubnet.IndexOf('/') != -1)
|
if (normalizedSubnet.Contains('/', StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
var ipnetwork = IPNetwork.Parse(normalizedSubnet);
|
var ipNetwork = IPNetwork.Parse(normalizedSubnet);
|
||||||
if (ipnetwork.Contains(address))
|
if (ipNetwork.Contains(address))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -455,9 +450,9 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
|
|
||||||
public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask)
|
public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask)
|
||||||
{
|
{
|
||||||
IPAddress network1 = GetNetworkAddress(address1, subnetMask);
|
IPAddress network1 = GetNetworkAddress(address1, subnetMask);
|
||||||
IPAddress network2 = GetNetworkAddress(address2, subnetMask);
|
IPAddress network2 = GetNetworkAddress(address2, subnetMask);
|
||||||
return network1.Equals(network2);
|
return network1.Equals(network2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPAddress GetNetworkAddress(IPAddress address, IPAddress subnetMask)
|
private IPAddress GetNetworkAddress(IPAddress address, IPAddress subnetMask)
|
||||||
@ -473,7 +468,7 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
|
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
|
||||||
for (int i = 0; i < broadcastAddress.Length; i++)
|
for (int i = 0; i < broadcastAddress.Length; i++)
|
||||||
{
|
{
|
||||||
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
|
broadcastAddress[i] = (byte)(ipAdressBytes[i] & subnetMaskBytes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IPAddress(broadcastAddress);
|
return new IPAddress(broadcastAddress);
|
||||||
@ -513,24 +508,5 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the network shares.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <returns>IEnumerable{NetworkShare}.</returns>
|
|
||||||
public virtual IEnumerable<NetworkShare> GetNetworkShares(string path)
|
|
||||||
{
|
|
||||||
return new List<NetworkShare>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets available devices within the domain
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>PC's in the Domain</returns>
|
|
||||||
public virtual IEnumerable<FileSystemEntryInfo> GetNetworkDevices()
|
|
||||||
{
|
|
||||||
return new List<FileSystemEntryInfo>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||||||
{
|
{
|
||||||
progress.Report(0);
|
progress.Report(0);
|
||||||
|
|
||||||
var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(cancellationToken).ConfigureAwait(false)).ToList();
|
var packagesToInstall = await _installationManager.GetAvailablePluginUpdates(cancellationToken)
|
||||||
|
.ToListAsync(cancellationToken)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
progress.Report(10);
|
progress.Report(10);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Mime;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Extensions;
|
using Microsoft.AspNetCore.Http.Extensions;
|
||||||
@ -14,9 +15,9 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
{
|
{
|
||||||
public class WebSocketSharpRequest : IHttpRequest
|
public class WebSocketSharpRequest : IHttpRequest
|
||||||
{
|
{
|
||||||
public const string FormUrlEncoded = "application/x-www-form-urlencoded";
|
private const string FormUrlEncoded = "application/x-www-form-urlencoded";
|
||||||
public const string MultiPartFormData = "multipart/form-data";
|
private const string MultiPartFormData = "multipart/form-data";
|
||||||
public const string Soap11 = "text/xml; charset=utf-8";
|
private const string Soap11 = "text/xml; charset=utf-8";
|
||||||
|
|
||||||
private string _remoteIp;
|
private string _remoteIp;
|
||||||
private Dictionary<string, object> _items;
|
private Dictionary<string, object> _items;
|
||||||
@ -77,7 +78,7 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
get =>
|
get =>
|
||||||
_responseContentType
|
_responseContentType
|
||||||
?? (_responseContentType = GetResponseContentType(Request));
|
?? (_responseContentType = GetResponseContentType(Request));
|
||||||
set => this._responseContentType = value;
|
set => _responseContentType = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PathInfo => Request.Path.Value;
|
public string PathInfo => Request.Path.Value;
|
||||||
@ -90,7 +91,6 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
|
|
||||||
public bool IsLocal => Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
|
public bool IsLocal => Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
|
||||||
|
|
||||||
|
|
||||||
public string HttpMethod => Request.Method;
|
public string HttpMethod => Request.Method;
|
||||||
|
|
||||||
public string Verb => HttpMethod;
|
public string Verb => HttpMethod;
|
||||||
@ -123,24 +123,29 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
return specifiedContentType;
|
return specifiedContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string serverDefaultContentType = "application/json";
|
const string ServerDefaultContentType = MediaTypeNames.Application.Json;
|
||||||
|
|
||||||
var acceptContentTypes = httpReq.Headers.GetCommaSeparatedValues(HeaderNames.Accept);
|
var acceptContentTypes = httpReq.Headers.GetCommaSeparatedValues(HeaderNames.Accept);
|
||||||
string defaultContentType = null;
|
string defaultContentType = null;
|
||||||
if (HasAnyOfContentTypes(httpReq, FormUrlEncoded, MultiPartFormData))
|
if (HasAnyOfContentTypes(httpReq, FormUrlEncoded, MultiPartFormData))
|
||||||
{
|
{
|
||||||
defaultContentType = serverDefaultContentType;
|
defaultContentType = ServerDefaultContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
var acceptsAnything = false;
|
var acceptsAnything = false;
|
||||||
var hasDefaultContentType = defaultContentType != null;
|
var hasDefaultContentType = defaultContentType != null;
|
||||||
if (acceptContentTypes != null)
|
if (acceptContentTypes != null)
|
||||||
{
|
{
|
||||||
foreach (var acceptsType in acceptContentTypes)
|
foreach (ReadOnlySpan<char> acceptsType in acceptContentTypes)
|
||||||
{
|
{
|
||||||
// TODO: @bond move to Span when Span.Split lands
|
ReadOnlySpan<char> contentType = acceptsType;
|
||||||
// https://github.com/dotnet/corefx/issues/26528
|
var index = contentType.IndexOf(';');
|
||||||
var contentType = acceptsType?.Split(';')[0].Trim();
|
if (index != -1)
|
||||||
|
{
|
||||||
|
contentType = contentType.Slice(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType = contentType.Trim();
|
||||||
acceptsAnything = contentType.Equals("*/*", StringComparison.OrdinalIgnoreCase);
|
acceptsAnything = contentType.Equals("*/*", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (acceptsAnything)
|
if (acceptsAnything)
|
||||||
@ -157,7 +162,7 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return serverDefaultContentType;
|
return ServerDefaultContentType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +173,7 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We could also send a '406 Not Acceptable', but this is allowed also
|
// We could also send a '406 Not Acceptable', but this is allowed also
|
||||||
return serverDefaultContentType;
|
return ServerDefaultContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasAnyOfContentTypes(HttpRequest request, params string[] contentTypes)
|
public static bool HasAnyOfContentTypes(HttpRequest request, params string[] contentTypes)
|
||||||
@ -196,12 +201,12 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
|
|
||||||
private static string GetQueryStringContentType(HttpRequest httpReq)
|
private static string GetQueryStringContentType(HttpRequest httpReq)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<char> format = httpReq.Query["format"].ToString().AsSpan();
|
ReadOnlySpan<char> format = httpReq.Query["format"].ToString();
|
||||||
if (format == null)
|
if (format == null)
|
||||||
{
|
{
|
||||||
const int formatMaxLength = 4;
|
const int FormatMaxLength = 4;
|
||||||
ReadOnlySpan<char> pi = httpReq.Path.ToString().AsSpan();
|
ReadOnlySpan<char> pi = httpReq.Path.ToString();
|
||||||
if (pi == null || pi.Length <= formatMaxLength)
|
if (pi == null || pi.Length <= FormatMaxLength)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -212,18 +217,18 @@ namespace Emby.Server.Implementations.SocketSharp
|
|||||||
}
|
}
|
||||||
|
|
||||||
format = LeftPart(pi, '/');
|
format = LeftPart(pi, '/');
|
||||||
if (format.Length > formatMaxLength)
|
if (format.Length > FormatMaxLength)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format = LeftPart(format, '.');
|
format = LeftPart(format, '.');
|
||||||
if (format.Contains("json".AsSpan(), StringComparison.OrdinalIgnoreCase))
|
if (format.Contains("json", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "application/json";
|
return "application/json";
|
||||||
}
|
}
|
||||||
else if (format.Contains("xml".AsSpan(), StringComparison.OrdinalIgnoreCase))
|
else if (format.Contains("xml", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "application/xml";
|
return "application/xml";
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
// Package not found.
|
// Package not found.
|
||||||
if (package == null)
|
if (package == null)
|
||||||
{
|
{
|
||||||
return null;
|
return Enumerable.Empty<PackageVersionInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetCompatibleVersions(
|
return GetCompatibleVersions(
|
||||||
@ -190,19 +190,23 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
|
public async IAsyncEnumerable<PackageVersionInfo> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
|
var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var systemUpdateLevel = _applicationHost.SystemUpdateLevel;
|
var systemUpdateLevel = _applicationHost.SystemUpdateLevel;
|
||||||
|
|
||||||
// Figure out what needs to be installed
|
// Figure out what needs to be installed
|
||||||
return _applicationHost.Plugins.Select(x =>
|
foreach (var plugin in _applicationHost.Plugins)
|
||||||
{
|
{
|
||||||
var compatibleversions = GetCompatibleVersions(catalog, x.Name, x.Id, x.Version, systemUpdateLevel);
|
var compatibleversions = GetCompatibleVersions(catalog, plugin.Name, plugin.Id, plugin.Version, systemUpdateLevel);
|
||||||
return compatibleversions.FirstOrDefault(y => y.Version > x.Version);
|
var version = compatibleversions.FirstOrDefault(y => y.Version > plugin.Version);
|
||||||
}).Where(x => x != null)
|
if (version != null
|
||||||
.Where(x => !CompletedInstallations.Any(y => string.Equals(y.AssemblyGuid, x.guid, StringComparison.OrdinalIgnoreCase)));
|
&& !CompletedInstallations.Any(x => string.Equals(x.AssemblyGuid, version.guid, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
yield return version;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -52,6 +52,7 @@ namespace MediaBrowser.Api
|
|||||||
public bool? IsFile { get; set; }
|
public bool? IsFile { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
[Route("/Environment/NetworkShares", "GET", Summary = "Gets shares from a network device")]
|
[Route("/Environment/NetworkShares", "GET", Summary = "Gets shares from a network device")]
|
||||||
public class GetNetworkShares : IReturn<List<FileSystemEntryInfo>>
|
public class GetNetworkShares : IReturn<List<FileSystemEntryInfo>>
|
||||||
{
|
{
|
||||||
@ -192,22 +193,18 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
var networkPrefix = UncSeparatorString + UncSeparatorString;
|
var networkPrefix = UncSeparatorString + UncSeparatorString;
|
||||||
|
|
||||||
if (path.StartsWith(networkPrefix, StringComparison.OrdinalIgnoreCase) && path.LastIndexOf(UncSeparator) == 1)
|
if (path.StartsWith(networkPrefix, StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& path.LastIndexOf(UncSeparator) == 1)
|
||||||
{
|
{
|
||||||
return ToOptimizedResult(GetNetworkShares(path).OrderBy(i => i.Path).ToList());
|
return ToOptimizedResult(Array.Empty<FileSystemEntryInfo>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ToOptimizedResult(GetFileSystemEntries(request).ToList());
|
return ToOptimizedResult(GetFileSystemEntries(request).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
public object Get(GetNetworkShares request)
|
public object Get(GetNetworkShares request)
|
||||||
{
|
=> ToOptimizedResult(Array.Empty<FileSystemEntryInfo>());
|
||||||
var path = request.Path;
|
|
||||||
|
|
||||||
var shares = GetNetworkShares(path).OrderBy(i => i.Path).ToList();
|
|
||||||
|
|
||||||
return ToOptimizedResult(shares);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the specified request.
|
/// Gets the specified request.
|
||||||
@ -241,26 +238,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetNetworkDevices request)
|
public object Get(GetNetworkDevices request)
|
||||||
{
|
=> ToOptimizedResult(Array.Empty<FileSystemEntryInfo>());
|
||||||
var result = _networkManager.GetNetworkDevices().ToList();
|
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the network shares.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
|
|
||||||
private IEnumerable<FileSystemEntryInfo> GetNetworkShares(string path)
|
|
||||||
{
|
|
||||||
return _networkManager.GetNetworkShares(path).Where(s => s.ShareType == NetworkShareType.Disk).Select(c => new FileSystemEntryInfo
|
|
||||||
{
|
|
||||||
Name = c.Name,
|
|
||||||
Path = Path.Combine(path, c.Name),
|
|
||||||
Type = FileSystemEntryType.NetworkShare
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the file system entries.
|
/// Gets the file system entries.
|
||||||
|
@ -4,8 +4,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Net
|
namespace MediaBrowser.Common.Net
|
||||||
{
|
{
|
||||||
@ -36,19 +34,6 @@ namespace MediaBrowser.Common.Net
|
|||||||
/// <returns><c>true</c> if [is in private address space] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [is in private address space] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
||||||
bool IsInPrivateAddressSpace(string endpoint);
|
bool IsInPrivateAddressSpace(string endpoint);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the network shares.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <returns>IEnumerable{NetworkShare}.</returns>
|
|
||||||
IEnumerable<NetworkShare> GetNetworkShares(string path);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets available devices within the domain
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>PC's in the Domain</returns>
|
|
||||||
IEnumerable<FileSystemEntryInfo> GetNetworkDevices();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether [is in local network] [the specified endpoint].
|
/// Determines whether [is in local network] [the specified endpoint].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -92,7 +92,7 @@ namespace MediaBrowser.Common.Updates
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>The available plugin updates.</returns>
|
/// <returns>The available plugin updates.</returns>
|
||||||
Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default);
|
IAsyncEnumerable<PackageVersionInfo> GetAvailablePluginUpdates(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Installs the package.
|
/// Installs the package.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user