Browse Source

dlna fixes

Luke Pulverenti 11 năm trước cách đây
mục cha
commit
13509c1d8d
37 tập tin đã thay đổi với 249 bổ sung37 xóa
  1. 4 4
      MediaBrowser.Controller/Entities/TV/Season.cs
  2. 8 0
      MediaBrowser.Controller/Entities/TV/Series.cs
  3. 4 3
      MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs
  4. 22 16
      MediaBrowser.Dlna/PlayTo/Device.cs
  5. 2 2
      MediaBrowser.Dlna/PlayTo/DlnaController.cs
  6. 1 1
      MediaBrowser.Dlna/PlayTo/TransportStateEventArgs.cs
  7. 13 4
      MediaBrowser.Dlna/Server/ControlHandler.cs
  8. 170 1
      MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs
  9. 2 2
      MediaBrowser.Dlna/Server/SsdpHandler.cs
  10. 2 1
      MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
  11. 1 0
      MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
  12. 1 1
      MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
  13. 0 0
      MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
  14. 1 1
      MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
  15. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/ar.json
  16. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/ca.json
  17. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/cs.json
  18. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/de.json
  19. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/el.json
  20. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
  21. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/en_US.json
  22. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/es.json
  23. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
  24. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/fr.json
  25. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/he.json
  26. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/it.json
  27. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/kk.json
  28. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/ms.json
  29. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/nb.json
  30. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/nl.json
  31. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
  32. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
  33. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/ru.json
  34. 16 1
      MediaBrowser.Server.Implementations/Localization/Server/server.json
  35. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/sv.json
  36. 0 0
      MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
  37. 2 0
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

+ 4 - 4
MediaBrowser.Controller/Entities/TV/Season.cs

@@ -196,19 +196,19 @@ namespace MediaBrowser.Controller.Entities.TV
 
         public IEnumerable<Episode> GetEpisodes(User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
         {
+            var episodes = GetRecursiveChildren(user)
+                .OfType<Episode>();
+
             if (IndexNumber.HasValue)
             {
                 var series = Series;
 
                 if (series != null)
                 {
-                    return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes);
+                    return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
                 }
             }
 
-            var episodes = GetRecursiveChildren(user)
-                .OfType<Episode>();
-
             if (!includeMissingEpisodes)
             {
                 episodes = episodes.Where(i => !i.IsMissingEpisode);

+ 8 - 0
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -167,12 +167,20 @@ namespace MediaBrowser.Controller.Entities.TV
         }
 
         public IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
+        {
+            return GetEpisodes(user, seasonNumber, includeMissingEpisodes, includeVirtualUnairedEpisodes,
+                new List<Episode>());
+        }
+
+        internal IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> additionalEpisodes)
         {
             var episodes = GetRecursiveChildren(user)
                 .OfType<Episode>();
 
             episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons);
 
+            episodes = episodes.Concat(additionalEpisodes).Distinct();
+
             if (!includeMissingEpisodes)
             {
                 episodes = episodes.Where(i => !i.IsMissingEpisode);

+ 4 - 3
MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs

@@ -103,9 +103,10 @@ namespace MediaBrowser.Controller.Resolvers
             ".wav",
             ".ape",
             ".ogg",
-            ".oga",
-            ".asf",
-            ".mp4"
+            ".oga"
+
+            //".asf",
+            //".mp4"
         };
 
         private static readonly Dictionary<string, string> AudioFileExtensionsDictionary = AudioFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);

+ 22 - 16
MediaBrowser.Dlna/PlayTo/Device.cs

@@ -66,8 +66,8 @@ namespace MediaBrowser.Dlna.PlayTo
             }
         }
 
-        private string _transportState = String.Empty;
-        public string TransportState
+        private TRANSPORTSTATE _transportState = TRANSPORTSTATE.STOPPED;
+        public TRANSPORTSTATE TransportState
         {
             get
             {
@@ -80,8 +80,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
                 _transportState = value;
 
-                if (value == TRANSPORTSTATE.PLAYING || value == TRANSPORTSTATE.STOPPED)
-                    NotifyPlaybackChanged(value == TRANSPORTSTATE.STOPPED);
+                NotifyPlaybackChanged(value);
             }
         }
 
@@ -374,7 +373,7 @@ namespace MediaBrowser.Dlna.PlayTo
                 .ConfigureAwait(false);
 
             await Task.Delay(50).ConfigureAwait(false);
-            TransportState = "PAUSED_PLAYBACK";
+            TransportState = TRANSPORTSTATE.PAUSED_PLAYBACK;
             return true;
         }
 
@@ -492,7 +491,14 @@ namespace MediaBrowser.Dlna.PlayTo
             var transportStateValue = transportState == null ? null : transportState.Value;
 
             if (transportStateValue != null)
-                TransportState = transportStateValue;
+            {
+                TRANSPORTSTATE state;
+
+                if (Enum.TryParse(transportStateValue, true, out state))
+                {
+                    TransportState = state;
+                }
+            }
 
             UpdateTime = DateTime.UtcNow;
         }
@@ -857,13 +863,13 @@ namespace MediaBrowser.Dlna.PlayTo
         public event EventHandler<TransportStateEventArgs> PlaybackChanged;
         public event EventHandler<CurrentIdEventArgs> CurrentIdChanged;
 
-        private void NotifyPlaybackChanged(bool value)
+        private void NotifyPlaybackChanged(TRANSPORTSTATE state)
         {
             if (PlaybackChanged != null)
             {
                 PlaybackChanged.Invoke(this, new TransportStateEventArgs
                 {
-                    Stopped = IsStopped
+                    State = state
                 });
             }
         }
@@ -895,14 +901,14 @@ namespace MediaBrowser.Dlna.PlayTo
             return String.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);
         }
 
-        private class TRANSPORTSTATE
-        {
-            public const string STOPPED = "STOPPED";
-            public const string PLAYING = "PLAYING";
-            public const string TRANSITIONING = "TRANSITIONING";
-            public const string PAUSED_PLAYBACK = "PAUSED_PLAYBACK";
-            public const string PAUSED = "PAUSED";
-        }
+    }
 
+    public enum TRANSPORTSTATE
+    {
+        STOPPED,
+        PLAYING,
+        TRANSITIONING,
+        PAUSED_PLAYBACK,
+        PAUSED
     }
 }

+ 2 - 2
MediaBrowser.Dlna/PlayTo/DlnaController.cs

@@ -88,10 +88,10 @@ namespace MediaBrowser.Dlna.PlayTo
             if (_currentItem == null)
                 return;
 
-            if (e.Stopped == false)
+            if (e.State == TRANSPORTSTATE.STOPPED)
                 await ReportProgress().ConfigureAwait(false);
 
-            else if (e.Stopped && _playbackStarted)
+            else if (e.State == TRANSPORTSTATE.STOPPED && _playbackStarted)
             {
                 _playbackStarted = false;
 

+ 1 - 1
MediaBrowser.Dlna/PlayTo/TransportStateEventArgs.cs

@@ -4,6 +4,6 @@ namespace MediaBrowser.Dlna.PlayTo
 {
     public class TransportStateEventArgs : EventArgs
     {
-        public bool Stopped { get; set; }
+        public TRANSPORTSTATE State { get; set; }
     }
 }

+ 13 - 4
MediaBrowser.Dlna/Server/ControlHandler.cs

@@ -185,7 +185,7 @@ namespace MediaBrowser.Dlna.Server
         {
             var id = sparams["ObjectID"];
 
-            var item = _libraryManager.GetItemById(new Guid(id));
+            var item = GetItemFromObjectId(id, user);
 
             var newbookmark = int.Parse(sparams["PosSecond"], _usCulture);
 
@@ -265,9 +265,7 @@ namespace MediaBrowser.Dlna.Server
             didl.SetAttribute("xmlns:sec", NS_SEC);
             result.AppendChild(didl);
 
-            var folder = string.IsNullOrWhiteSpace(id) || string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
-                ? user.RootFolder
-                : (Folder)_libraryManager.GetItemById(new Guid(id));
+            var folder = (Folder)GetItemFromObjectId(id, user);
 
             var children = GetChildrenSorted(folder, user).ToList();
 
@@ -328,6 +326,17 @@ namespace MediaBrowser.Dlna.Server
             return _libraryManager.Sort(children, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending);
         }
 
+        private BaseItem GetItemFromObjectId(string id, User user)
+        {
+           return string.IsNullOrWhiteSpace(id) || string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
+
+                // Samsung sometimes uses 1 as root
+                || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase)
+
+                ? user.RootFolder
+                : _libraryManager.GetItemById(new Guid(id));
+        }
+
         private void Browse_AddFolder(XmlDocument result, Folder f, int childCount)
         {
             var container = result.CreateElement(string.Empty, "container", NS_DIDL);

+ 170 - 1
MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs

@@ -12,9 +12,11 @@ namespace MediaBrowser.Dlna.Server
                 GetGetSystemUpdateIDAction(),
                 GetSearchCapabilitiesAction(),
                 GetSortCapabilitiesAction(),
+                GetSearchAction(),
                 GetBrowseAction(),
                 GetX_GetFeatureListAction(),
-                GetXSetBookmarkAction()
+                GetXSetBookmarkAction(),
+                GetBrowseByLetterAction()
             };
 
             return list;
@@ -88,6 +90,86 @@ namespace MediaBrowser.Dlna.Server
             return action;
         }
 
+        private ServiceAction GetSearchAction()
+        {
+            var action = new ServiceAction
+            {
+                Name = "Search"
+            };
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "ContainerID",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_ObjectID"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "SearchCriteria",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_SearchCriteria"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "Filter",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_Filter"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "StartingIndex",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_Index"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "RequestedCount",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_Count"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "SortCriteria",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "Result",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Result"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "NumberReturned",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Count"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "TotalMatches",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Count"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "UpdateID",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_UpdateID"
+            });
+
+            return action;
+        }
+
         private ServiceAction GetBrowseAction()
         {
             var action = new ServiceAction
@@ -168,6 +250,93 @@ namespace MediaBrowser.Dlna.Server
             return action;
         }
 
+        private ServiceAction GetBrowseByLetterAction()
+        {
+            var action = new ServiceAction
+            {
+                Name = "X_BrowseByLetter"
+            };
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "ObjectID",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_ObjectID"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "BrowseFlag",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_BrowseFlag"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "Filter",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_Filter"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "StartingLetter",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_BrowseLetter"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "RequestedCount",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_Count"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "SortCriteria",
+                Direction = "in",
+                RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "Result",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Result"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "NumberReturned",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Count"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "TotalMatches",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Count"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "UpdateID",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_UpdateID"
+            });
+
+            action.ArgumentList.Add(new Argument
+            {
+                Name = "StartingIndex",
+                Direction = "out",
+                RelatedStateVariable = "A_ARG_TYPE_Index"
+            });
+
+            return action;
+        }
+        
         private ServiceAction GetXSetBookmarkAction()
         {
             var action = new ServiceAction

+ 2 - 2
MediaBrowser.Dlna/Server/SsdpHandler.cs

@@ -135,7 +135,7 @@ namespace MediaBrowser.Dlna.Server
 
         private void RespondToSearch(IPEndPoint endpoint, string req)
         {
-            if (req == "ssdp:all")
+            if (string.Equals(req, "ssdp:all", StringComparison.OrdinalIgnoreCase))
             {
                 req = null;
             }
@@ -171,7 +171,7 @@ namespace MediaBrowser.Dlna.Server
 
             SendDatagram(endpoint, dev.Address, msg, false);
 
-            _logger.Info("{1} - Responded to a {0} request", dev.Type, endpoint);
+            _logger.Info("{1} - Responded to a {0} request to {2}", dev.Type, endpoint, dev.Address.ToString());
         }
 
         private void SendDatagram(IPEndPoint endpoint, IPAddress localAddress, string msg, bool sticky)

+ 2 - 1
MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs

@@ -37,7 +37,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
                     var isStandalone = args.Parent == null;
 
                     if (isStandalone ||
-                        string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
+                        string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) ||
+                        string.IsNullOrEmpty(collectionType))
                     {
                         return new Controller.Entities.Audio.Audio();
                     }

+ 1 - 0
MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json

@@ -0,0 +1 @@
+{"SettingsSaved":"Settings saved.","AddUser":"Add User","Users":"Users","Delete":"Delete","Administrator":"Administrator","Password":"Password","DeleteImage":"Delete Image","DeleteImageConfirmation":"Are you sure you wish to delete this image?","FileReadCancelled":"The file read has been cancelled.","FileNotFound":"File not found.","FileReadError":"An error occurred while reading the file.","DeleteUser":"Delete User","DeleteUserConfirmation":"Are you sure you wish to delete {0}?","PasswordResetHeader":"Password Reset","PasswordResetComplete":"The password has been reset.","PasswordResetConfirmation":"Are you sure you wish to reset the password?","PasswordSaved":"Password saved.","PasswordMatchError":"Password and password confirmation must match.","OptionOff":"Off","OptionOn":"On","OptionRelease":"Official Release","OptionBeta":"Beta","OptionDev":"Dev (Unstable)","UninstallPluginHeader":"Uninstall Plugin","UninstallPluginConfirmation":"Are you sure you wish to uninstall {0}?","NoPluginConfigurationMessage":"This plugin has nothing to configure.","NoPluginsInstalledMessage":"You have no plugins installed.","BrowsePluginCatalogMessage":"Browse our plugin catalog to view available plugins."}

+ 1 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json

@@ -1 +1 @@
-{"SettingsSaved":"Configuraci\u00f3n guardada.","AddUser":"Agregar usuario","Users":"Usuarios","Delete":"Eliminar","Administrator":"Administrador","Password":"Contrase\u00f1a","DeleteImage":"Eliminar imagen","DeleteImageConfirmation":"\u00bfEst\u00e1 seguro que desea eliminar esta imagen?","FileReadCancelled":"La lectura del archivo ha sido cancelada.","FileNotFound":"Archivo no encontrado.","FileReadError":"Ha ocurrido un error al leer el archivo.","DeleteUser":"Eliminar Usuario","DeleteUserConfirmation":"\u00bfEsta seguro que desea eliminar a {0}?","PasswordResetHeader":"Restablecer Contrase\u00f1a","PasswordResetComplete":"La contrase\u00f1a ha sido restablecida.","PasswordResetConfirmation":"\u00bfEst\u00e1 seguro que desea restablecer la contrase\u00f1a?","PasswordSaved":"Contrase\u00f1a guardada.","PasswordMatchError":"La Contrase\u00f1a y la confirmaci\u00f3n de la contrase\u00f1a deben coincidir.","OptionOff":"Apagado","OptionOn":"Encendido","OptionRelease":"Versi\u00f3n Oficial","OptionBeta":"Beta","OptionDev":"Desarrollo (Inestable)","UninstallPluginHeader":"Desinstalar Complemento","UninstallPluginConfirmation":"\u00bfEst\u00e1 seguro que desea desinstalar {0}?","NoPluginConfigurationMessage":"El complemento no requiere configuraci\u00f3n","NoPluginsInstalledMessage":"No tiene complementos instalados.","BrowsePluginCatalogMessage":"Navege en el catalogo de complementos para ver los complementos disponibles."}
+{"SettingsSaved":"Configuraci\u00f3n guardada.","AddUser":"Agregar usuario","Users":"Usuarios","Delete":"Eliminar","Administrator":"Administrador","Password":"Contrase\u00f1a","DeleteImage":"Eliminar imagen","DeleteImageConfirmation":"\u00bfEst\u00e1 seguro que desea eliminar esta imagen?","FileReadCancelled":"La lectura del archivo ha sido cancelada.","FileNotFound":"Archivo no encontrado.","FileReadError":"Ha ocurrido un error al leer el archivo.","DeleteUser":"Eliminar Usuario","DeleteUserConfirmation":"\u00bfEsta seguro que desea eliminar a {0}?","PasswordResetHeader":"Restablecer Contrase\u00f1a","PasswordResetComplete":"La contrase\u00f1a ha sido restablecida.","PasswordResetConfirmation":"\u00bfEst\u00e1 seguro que desea restablecer la contrase\u00f1a?","PasswordSaved":"Contrase\u00f1a guardada.","PasswordMatchError":"La Contrase\u00f1a y la confirmaci\u00f3n de la contrase\u00f1a deben coincidir.","OptionOff":"No","OptionOn":"Si","OptionRelease":"Versi\u00f3n Oficial","OptionBeta":"Beta","OptionDev":"Desarrollo (Inestable)","UninstallPluginHeader":"Desinstalar Complemento","UninstallPluginConfirmation":"\u00bfEst\u00e1 seguro que desea desinstalar {0}?","NoPluginConfigurationMessage":"El complemento no requiere configuraci\u00f3n","NoPluginsInstalledMessage":"No tiene complementos instalados.","BrowsePluginCatalogMessage":"Navege en el catalogo de complementos para ver los complementos disponibles."}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json


+ 1 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json

@@ -1 +1 @@
-{"SettingsSaved":"Configura\u00e7\u00f5es guardadas.","AddUser":"Adicionar Utilizador","Users":"Utilizadores","Delete":"Apagar","Administrator":"Administrador","Password":"Senha","DeleteImage":"Apagar Imagem","DeleteImageConfirmation":"Tem a certeza que deseja apagar a imagem?","FileReadCancelled":"A leitura do ficheiro foi cancelada.","FileNotFound":"Ficheiro n\u00e3o encontrado.","FileReadError":"Ocorreu um erro ao ler o ficheiro.","DeleteUser":"Apagar Utilizador","DeleteUserConfirmation":"Tem a certeza que deseja apagar {0}?","PasswordResetHeader":"Redefinir Senha","PasswordResetComplete":"A senha foi redefinida.","PasswordResetConfirmation":"Tem a certeza que deseja redefinir a senha?","PasswordSaved":"Senha guardada.","PasswordMatchError":"A senha e a confirma\u00e7\u00e3o da senha devem coincidir.","OptionOff":"Desligar","OptionOn":"Ligar","OptionRelease":"Lan\u00e7amento Oficial","OptionBeta":"Beta","OptionDev":"Dev (Inst\u00e1vel)","UninstallPluginHeader":"Desinstalar extens\u00e3o","UninstallPluginConfirmation":"Tem a certeza que deseja desinstalar {0}?","NoPluginConfigurationMessage":"Esta extens\u00e3o n\u00e3o \u00e9 configur\u00e1vel.","NoPluginsInstalledMessage":"N\u00e3o tem extens\u00f5es instaladas.","BrowsePluginCatalogMessage":"Navegue o nosso cat\u00e1logo de extens\u00f5es, para ver as extens\u00f5es dispon\u00edveis."}
+{"SettingsSaved":"Configura\u00e7\u00f5es guardadas.","AddUser":"Adicionar Utilizador","Users":"Utilizadores","Delete":"Apagar","Administrator":"Administrador","Password":"Senha","DeleteImage":"Apagar Imagem","DeleteImageConfirmation":"Tem a certeza que deseja apagar a imagem?","FileReadCancelled":"A leitura do ficheiro foi cancelada.","FileNotFound":"Ficheiro n\u00e3o encontrado.","FileReadError":"Ocorreu um erro ao ler o ficheiro.","DeleteUser":"Apagar Utilizador","DeleteUserConfirmation":"Tem a certeza que deseja apagar {0}?","PasswordResetHeader":"Redefinir Senha","PasswordResetComplete":"A senha foi redefinida.","PasswordResetConfirmation":"Tem a certeza que deseja redefinir a senha?","PasswordSaved":"Senha guardada.","PasswordMatchError":"A senha e a confirma\u00e7\u00e3o da senha devem coincidir.","OptionOff":"Desligado","OptionOn":"Ligado","OptionRelease":"Lan\u00e7amento Oficial","OptionBeta":"Beta","OptionDev":"Dev (Inst\u00e1vel)","UninstallPluginHeader":"Desinstalar extens\u00e3o","UninstallPluginConfirmation":"Tem a certeza que deseja desinstalar {0}?","NoPluginConfigurationMessage":"Esta extens\u00e3o n\u00e3o \u00e9 configur\u00e1vel.","NoPluginsInstalledMessage":"N\u00e3o tem extens\u00f5es instaladas.","BrowsePluginCatalogMessage":"Navegue o nosso cat\u00e1logo de extens\u00f5es, para ver as extens\u00f5es dispon\u00edveis."}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/ar.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/ca.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/cs.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/de.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/el.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/en_GB.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/en_US.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/es.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/es_MX.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/fr.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/he.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/it.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/kk.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/ms.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/nb.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/nl.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/ru.json


+ 16 - 1
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -517,5 +517,20 @@
 	"LabelComponentsUpdated": "The following components have been installed or updated:",
 	"MessagePleaseRestartServerToFinishUpdating": "Please restart the server to finish applying updates.",
 	"LabelDownMixAudioScale": "Down mix audio boost scale:",
-	"LabelDownMixAudioScaleHelp": "Boost audio when downmixing. Set to 1 to preserve original volume value."
+	"LabelDownMixAudioScaleHelp": "Boost audio when downmixing. Set to 1 to preserve original volume value.",
+	"ButtonLinkKeys": "Link Keys",
+	"LabelOldSupporterKey": "Old supporter key",
+	"LabelNewSupporterKey": "New supporter key",
+	"HeaderMultipleKeyLinking": "Multiple Key Linking",
+	"MultipleKeyLinkingHelp": "If you have more than one supporter key, use this form to link the old key's registrations with your new one.",
+	"LabelCurrentEmailAddress": "Current email address",
+	"LabelCurrentEmailAddressHelp": "The current email address to which your new key was sent.",
+	"HeaderForgotKey": "Forgot Key",
+	"LabelEmailAddress": "Email address",
+	"LabelSupporterEmailAddress": "The email address that was used to purchase the key.",
+	"ButtonRetrieveKey": "Retrieve Key",
+	"LabelSupporterKey": "Supporter Key (paste from email)",
+	"LabelSupporterKeyHelp": "Enter your supporter key to start enjoying additional benefits the community has developed for Media Browser.",
+	"MessageInvalidKey": "MB3 Key Missing or Invalid",
+	"ErrorMessageInvalidKey": "In order for any premium content to be registered, you must also be an MB3 Supporter. Please donate and support the continued development of the core product. Thank you."
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/sv.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json


+ 2 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -323,6 +323,8 @@
     <EmbeddedResource Include="Localization\JavaScript\ms.json" />
     <EmbeddedResource Include="Localization\Server\ca.json" />
     <EmbeddedResource Include="Localization\Server\ms.json" />
+    <EmbeddedResource Include="Localization\JavaScript\kk.json" />
+    <EmbeddedResource Include="Localization\Server\kk.json" />
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác