aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines.yml131
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs40
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt.json97
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs8
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs13
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs4
7 files changed, 183 insertions, 114 deletions
diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index 13cc67528..143873266 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -19,9 +19,9 @@ jobs:
vmImage: ubuntu-latest
strategy:
matrix:
- release:
+ Release:
BuildConfiguration: Release
- debug:
+ Debug:
BuildConfiguration: Debug
maxParallel: 2
steps:
@@ -31,32 +31,32 @@ jobs:
persistCredentials: true
- task: CmdLine@2
- displayName: "Check out web"
+ displayName: "Clone Web Client (Master, Release, or Tag)"
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
- task: CmdLine@2
- displayName: "Check out web (PR)"
+ displayName: "Clone Web Client (PR)"
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
inputs:
script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
- task: NodeTool@0
- displayName: 'Install Node.js'
+ displayName: 'Install Node'
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
versionSpec: '10.x'
- task: CmdLine@2
- displayName: "Build Web UI"
+ displayName: "Build Web Client"
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
script: yarn install
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
- task: CopyFiles@2
- displayName: Copy the web UI
+ displayName: 'Copy Web Client'
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
@@ -66,8 +66,14 @@ jobs:
overWrite: true # Optional
flattenFolders: false # Optional
+ - task: UseDotNet@2
+ displayName: 'Update DotNet'
+ inputs:
+ packageType: sdk
+ version: 3.1.100
+
- task: DotNetCoreCLI@2
- displayName: Publish
+ displayName: 'Publish Server'
inputs:
command: publish
publishWebProjects: false
@@ -135,62 +141,20 @@ jobs:
!**\obj\**
!**\xunit.runner.visualstudio.testadapter.dll
!**\xunit.runner.visualstudio.dotnetcore.testadapter.dll
- #testPlan: # Required when testSelector == TestPlan
- #testSuite: # Required when testSelector == TestPlan
- #testConfiguration: # Required when testSelector == TestPlan
- #tcmTestRun: '$(test.RunId)' # Optional
searchFolder: '$(System.DefaultWorkingDirectory)'
- #testFiltercriteria: # Optional
- #runOnlyImpactedTests: False # Optional
- #runAllTestsAfterXBuilds: '50' # Optional
- #uiTests: false # Optional
- #vstestLocationMethod: 'version' # Optional. Options: version, location
- #vsTestVersion: 'latest' # Optional. Options: latest, 16.0, 15.0, 14.0, toolsInstaller
- #vstestLocation: # Optional
- #runSettingsFile: # Optional
- #overrideTestrunParameters: # Optional
- #pathtoCustomTestAdapters: # Optional
runInParallel: True # Optional
runTestsInIsolation: True # Optional
codeCoverageEnabled: True # Optional
- #otherConsoleOptions: # Optional
- #distributionBatchType: 'basedOnTestCases' # Optional. Options: basedOnTestCases, basedOnExecutionTime, basedOnAssembly
- #batchingBasedOnAgentsOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customBatchSize
- #customBatchSizeValue: '10' # Required when distributionBatchType == BasedOnTestCases && BatchingBasedOnAgentsOption == CustomBatchSize
- #batchingBasedOnExecutionTimeOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customTimeBatchSize
- #customRunTimePerBatchValue: '60' # Required when distributionBatchType == BasedOnExecutionTime && BatchingBasedOnExecutionTimeOption == CustomTimeBatchSize
- #dontDistribute: False # Optional
- #testRunTitle: # Optional
- #platform: # Optional
configuration: 'Debug' # Optional
publishRunAttachments: true # Optional
- #diagnosticsEnabled: false # Optional
- #collectDumpOn: 'onAbortOnly' # Optional. Options: onAbortOnly, always, never
- #rerunFailedTests: False # Optional
- #rerunType: 'basedOnTestFailurePercentage' # Optional. Options: basedOnTestFailurePercentage, basedOnTestFailureCount
- #rerunFailedThreshold: '30' # Optional
- #rerunFailedTestCasesMaxLimit: '5' # Optional
- #rerunMaxAttempts: '3' # Optional
-
- # - task: PublishTestResults@2
- # inputs:
- # testResultsFormat: 'VSTest' # Options: JUnit, NUnit, VSTest, xUnit, cTest
- # testResultsFiles: '**/*.trx'
- # #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional
- # mergeTestResults: true # Optional
- # #failTaskOnFailedTests: false # Optional
- # #testRunTitle: # Optional
- # #buildPlatform: # Optional
- # #buildConfiguration: # Optional
- # #publishRunAttachments: true # Optional
- job: main_build_win
- displayName: Main Build Windows
+ displayName: Publish Windows
pool:
vmImage: windows-latest
strategy:
matrix:
- release:
+ Release:
BuildConfiguration: Release
maxParallel: 2
steps:
@@ -200,32 +164,32 @@ jobs:
persistCredentials: true
- task: CmdLine@2
- displayName: "Check out web (master, release or tag)"
+ displayName: "Clone Web Client (Master, Release, or Tag)"
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'tag')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
- task: CmdLine@2
- displayName: "Check out web (PR)"
+ displayName: "Clone Web Client (PR)"
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
inputs:
script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
- task: NodeTool@0
- displayName: 'Install Node.js'
+ displayName: 'Install Node'
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
versionSpec: '10.x'
- task: CmdLine@2
- displayName: "Build Web UI"
+ displayName: "Build Web Client"
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
script: yarn install
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
- task: CopyFiles@2
- displayName: Copy the web UI
+ displayName: 'Copy Web Client'
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
@@ -236,25 +200,21 @@ jobs:
flattenFolders: false # Optional
- task: CmdLine@2
- displayName: Clone the UX repository
+ displayName: 'Clone UX Repository'
inputs:
script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
- task: PowerShell@2
- displayName: Build the NSIS Installer
+ displayName: 'Build NSIS Installer'
inputs:
targetType: 'filePath' # Optional. Options: filePath, inline
filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
- #script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
- #failOnStderr: false # Optional
- #ignoreLASTEXITCODE: false # Optional
- #pwsh: false # Optional
workingDirectory: $(Build.SourcesDirectory) # Optional
- task: CopyFiles@2
- displayName: Copy the NSIS Installer to the artifact directory
+ displayName: 'Copy NSIS Installer'
inputs:
sourceFolder: $(Build.SourcesDirectory)/deployment/windows/ # Optional
contents: 'jellyfin*.exe'
@@ -264,7 +224,7 @@ jobs:
flattenFolders: true # Optional
- task: PublishPipelineArtifact@0
- displayName: 'Publish Setup Artifact'
+ displayName: 'Publish Artifact Setup'
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
inputs:
targetPath: '$(build.artifactstagingdirectory)/setup'
@@ -275,7 +235,8 @@ jobs:
pool:
vmImage: ubuntu-latest
dependsOn: main_build
- condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) # Only execute if the pullrequest numer is defined. (So not for normal CI builds)
+ # only execute for pull requests
+ condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber'])
strategy:
matrix:
Naming:
@@ -293,24 +254,23 @@ jobs:
maxParallel: 2
steps:
- checkout: none
+
+ - task: UseDotNet@2
+ displayName: 'Update DotNet'
+ inputs:
+ packageType: sdk
+ version: 3.1.100
- task: DownloadPipelineArtifact@2
- displayName: Download the New Assembly Build Artifact
+ displayName: 'Download New Assembly Build Artifact'
inputs:
source: 'current' # Options: current, specific
- #preferTriggeringPipeline: false # Optional
- #tags: # Optional
artifact: '$(NugetPackageName)' # Optional
- #patterns: '**' # Optional
path: '$(System.ArtifactsDirectory)/new-artifacts'
- #project: # Required when source == Specific
- #pipeline: # Required when source == Specific
runVersion: 'latest' # Required when source == Specific. Options: latest, latestFromBranch, specific
- #runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch
- #runId: # Required when source == Specific && runVersion == Specific
- task: CopyFiles@2
- displayName: Copy New Assembly to new-release folder
+ displayName: 'Copy New Assembly Build Artifact'
inputs:
sourceFolder: $(System.ArtifactsDirectory)/new-artifacts # Optional
contents: '**/*.dll'
@@ -320,22 +280,18 @@ jobs:
flattenFolders: true # Optional
- task: DownloadPipelineArtifact@2
- displayName: Download the Reference Assembly Build Artifact
+ displayName: 'Download Reference Assembly Build Artifact'
inputs:
source: 'specific' # Options: current, specific
- #preferTriggeringPipeline: false # Optional
- #tags: # Optional
artifact: '$(NugetPackageName)' # Optional
- #patterns: '**' # Optional
path: '$(System.ArtifactsDirectory)/current-artifacts'
project: '$(System.TeamProjectId)' # Required when source == Specific
pipeline: '$(System.DefinitionId)' # Required when source == Specific
runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific
runBranch: 'refs/heads/$(System.PullRequest.TargetBranch)' # Required when source == Specific && runVersion == LatestFromBranch
- #runId: # Required when source == Specific && runVersion == Specific
- task: CopyFiles@2
- displayName: Copy Reference Assembly to current-release folder
+ displayName: 'Copy Reference Assembly Build Artifact'
inputs:
sourceFolder: $(System.ArtifactsDirectory)/current-artifacts # Optional
contents: '**/*.dll'
@@ -345,27 +301,24 @@ jobs:
flattenFolders: true # Optional
- task: DownloadGitHubRelease@0
- displayName: Download ABI compatibility check tool from GitHub
+ displayName: 'Download ABI Compatibility Check Tool'
inputs:
connection: Jellyfin Release Download
userRepository: EraYaN/dotnet-compatibility
defaultVersionType: 'latest' # Options: latest, specificVersion, specificTag
- #version: # Required when defaultVersionType != Latest
itemPattern: '**-ci.zip' # Optional
downloadPath: '$(System.ArtifactsDirectory)'
- task: ExtractFiles@1
- displayName: Extract ABI compatibility check tool
+ displayName: 'Extract ABI Compatibility Check Tool'
inputs:
archiveFilePatterns: '$(System.ArtifactsDirectory)/*-ci.zip'
destinationFolder: $(System.ArtifactsDirectory)/tools
cleanDestinationFolder: true
+ # The `--warnings-only` switch will swallow the return code and not emit any errors.
- task: CmdLine@2
- displayName: Execute ABI compatibility check tool
+ displayName: 'Execute ABI Compatibility Check Tool'
inputs:
- script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines'
+ script: 'dotnet tools/CompatibilityCheckerCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only'
workingDirectory: $(System.ArtifactsDirectory) # Optional
- #failOnStderr: false # Optional
-
-
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index c5ac27ed4..a179c1b15 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -103,14 +103,11 @@ using MediaBrowser.Providers.Subtitles;
using MediaBrowser.Providers.TV.TheTVDB;
using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.OpenApi.Models;
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
namespace Emby.Server.Implementations
@@ -1480,7 +1477,7 @@ namespace Emby.Server.Implementations
/// </summary>
/// <param name="address">The IPv6 address.</param>
/// <returns>The IPv6 address without the scope id.</returns>
- private string RemoveScopeId(string address)
+ private ReadOnlySpan<char> RemoveScopeId(ReadOnlySpan<char> address)
{
var index = address.IndexOf('%');
if (index == -1)
@@ -1488,33 +1485,50 @@ namespace Emby.Server.Implementations
return address;
}
- return address.Substring(0, index);
+ return address.Slice(0, index);
}
+ /// <inheritdoc />
public string GetLocalApiUrl(IPAddress ipAddress)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
var str = RemoveScopeId(ipAddress.ToString());
+ Span<char> span = new char[str.Length + 2];
+ span[0] = '[';
+ str.CopyTo(span.Slice(1));
+ span[^1] = ']';
- return GetLocalApiUrl("[" + str + "]");
+ return GetLocalApiUrl(span);
}
return GetLocalApiUrl(ipAddress.ToString());
}
- public string GetLocalApiUrl(string host)
+ /// <inheritdoc />
+ public string GetLocalApiUrl(ReadOnlySpan<char> host)
{
+ var url = new StringBuilder(64);
if (EnableHttps)
{
- return string.Format("https://{0}:{1}",
- host,
- HttpsPort.ToString(CultureInfo.InvariantCulture));
+ url.Append("https://");
+ }
+ else
+ {
+ url.Append("http://");
+ }
+
+ url.Append(host)
+ .Append(':')
+ .Append(HttpPort);
+
+ string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
+ if (baseUrl.Length != 0)
+ {
+ url.Append('/').Append(baseUrl);
}
- return string.Format("http://{0}:{1}",
- host,
- HttpPort.ToString(CultureInfo.InvariantCulture));
+ return url.ToString();
}
public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json
index 9805992be..e1dce82ff 100644
--- a/Emby.Server.Implementations/Localization/Core/fr.json
+++ b/Emby.Server.Implementations/Localization/Core/fr.json
@@ -19,10 +19,10 @@
"HeaderCameraUploads": "Photos transférées",
"HeaderContinueWatching": "Continuer à regarder",
"HeaderFavoriteAlbums": "Albums favoris",
- "HeaderFavoriteArtists": "Artistes favoris",
+ "HeaderFavoriteArtists": "Artistes préférés",
"HeaderFavoriteEpisodes": "Épisodes favoris",
"HeaderFavoriteShows": "Séries favorites",
- "HeaderFavoriteSongs": "Chansons favorites",
+ "HeaderFavoriteSongs": "Chansons préférées",
"HeaderLiveTV": "TV en direct",
"HeaderNextUp": "À suivre",
"HeaderRecordingGroups": "Groupes d'enregistrements",
diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json
index 0967ef424..ef8d988c8 100644
--- a/Emby.Server.Implementations/Localization/Core/pt.json
+++ b/Emby.Server.Implementations/Localization/Core/pt.json
@@ -1 +1,96 @@
-{}
+{
+ "HeaderLiveTV": "TV ao Vivo",
+ "Collections": "Colecções",
+ "Books": "Livros",
+ "Artists": "Artistas",
+ "Albums": "Álbuns",
+ "HeaderNextUp": "A Seguir",
+ "HeaderFavoriteSongs": "Músicas Favoritas",
+ "HeaderFavoriteArtists": "Artistas Favoritos",
+ "HeaderFavoriteAlbums": "Álbuns Favoritos",
+ "HeaderFavoriteEpisodes": "Episódios Favoritos",
+ "HeaderFavoriteShows": "Séries Favoritas",
+ "HeaderContinueWatching": "Continuar a Ver",
+ "HeaderAlbumArtists": "Artistas do Álbum",
+ "Genres": "Géneros",
+ "Folders": "Pastas",
+ "Favorites": "Favoritos",
+ "Channels": "Canais",
+ "UserDownloadingItemWithValues": "{0} está a transferir {1}",
+ "VersionNumber": "Versão {0}",
+ "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua biblioteca multimédia",
+ "UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}",
+ "UserStartedPlayingItemWithValues": "{0} está a reproduzir {1} em {2}",
+ "UserPolicyUpdatedWithName": "A política do utilizador {0} foi alterada",
+ "UserPasswordChangedWithName": "A palavra-passe do utilizador {0} foi alterada",
+ "UserOnlineFromDevice": "{0} ligou-se a partir de {1}",
+ "UserOfflineFromDevice": "{0} desligou-se a partir de {1}",
+ "UserLockedOutWithName": "Utilizador {0} bloqueado",
+ "UserDeletedWithName": "Utilizador {0} removido",
+ "UserCreatedWithName": "Utilizador {0} criado",
+ "User": "Utilizador",
+ "TvShows": "Programas",
+ "System": "Sistema",
+ "SubtitlesDownloadedForItem": "Legendas transferidas para {0}",
+ "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}",
+ "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente dentro de momentos.",
+ "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado",
+ "ScheduledTaskStartedWithName": "{0} iniciou",
+ "ScheduledTaskFailedWithName": "{0} falhou",
+ "ProviderValue": "Fornecedor: {0}",
+ "PluginUpdatedWithName": "{0} foi actualizado",
+ "PluginUninstalledWithName": "{0} foi desinstalado",
+ "PluginInstalledWithName": "{0} foi instalado",
+ "Plugin": "Extensão",
+ "NotificationOptionVideoPlaybackStopped": "Reprodução de vídeo parada",
+ "NotificationOptionVideoPlayback": "Reprodução de vídeo iniciada",
+ "NotificationOptionUserLockedOut": "Utilizador bloqueado",
+ "NotificationOptionTaskFailed": "Falha em tarefa agendada",
+ "NotificationOptionServerRestartRequired": "É necessário reiniciar o servidor",
+ "NotificationOptionPluginUpdateInstalled": "Extensão actualizada",
+ "NotificationOptionPluginUninstalled": "Extensão desinstalada",
+ "NotificationOptionPluginInstalled": "Extensão instalada",
+ "NotificationOptionPluginError": "Falha na extensão",
+ "NotificationOptionNewLibraryContent": "Novo conteúdo adicionado",
+ "NotificationOptionInstallationFailed": "Falha de instalação",
+ "NotificationOptionCameraImageUploaded": "Imagem da câmara enviada",
+ "NotificationOptionAudioPlaybackStopped": "Reprodução Parada",
+ "NotificationOptionAudioPlayback": "Reprodução Iniciada",
+ "NotificationOptionApplicationUpdateInstalled": "A actualização da aplicação foi instalada",
+ "NotificationOptionApplicationUpdateAvailable": "Uma actualização da aplicação está disponível",
+ "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para transferência.",
+ "NameSeasonUnknown": "Temporada Desconhecida",
+ "NameSeasonNumber": "Temporada {0}",
+ "NameInstallFailed": "Falha na instalação de {0}",
+ "MusicVideos": "Videoclips",
+ "Music": "Música",
+ "MixedContent": "Conteúdo Misto",
+ "MessageServerConfigurationUpdated": "A configuração do servidor foi actualizada",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Configurações do servidor na secção {0} foram atualizadas",
+ "MessageApplicationUpdatedTo": "O servidor Jellyfin foi actualizado para a versão {0}",
+ "MessageApplicationUpdated": "O servidor Jellyfin foi actualizado",
+ "Latest": "Mais Recente",
+ "LabelRunningTimeValue": "Duração: {0}",
+ "LabelIpAddressValue": "Endereço IP: {0}",
+ "ItemRemovedWithName": "{0} foi removido da biblioteca",
+ "ItemAddedWithName": "{0} foi adicionado à biblioteca",
+ "Inherit": "Herdar",
+ "HomeVideos": "Vídeos Caseiros",
+ "HeaderRecordingGroups": "Grupos de Gravação",
+ "ValueSpecialEpisodeName": "Especial - {0}",
+ "Sync": "Sincronização",
+ "Songs": "Músicas",
+ "Shows": "Séries",
+ "Playlists": "Listas de Reprodução",
+ "Photos": "Fotografias",
+ "Movies": "Filmes",
+ "HeaderCameraUploads": "Envios a partir da câmara",
+ "FailedLoginAttemptWithUserName": "Tentativa de ligação a partir de {0} falhou",
+ "DeviceOnlineWithName": "{0} ligou-se",
+ "DeviceOfflineWithName": "{0} desligou-se",
+ "ChapterNameValue": "Capítulo {0}",
+ "CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}",
+ "AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
+ "Application": "Aplicação",
+ "AppDeviceValues": "Aplicação {0}, Dispositivo: {1}"
+}
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index b3c56bdd5..25f0905eb 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -71,13 +71,15 @@ namespace MediaBrowser.Controller
/// <summary>
/// Gets the local API URL.
/// </summary>
- /// <param name="host">The host.</param>
- /// <returns>System.String.</returns>
- string GetLocalApiUrl(string host);
+ /// <param name="hostname">The hostname.</param>
+ /// <returns>The local API URL.</returns>
+ string GetLocalApiUrl(ReadOnlySpan<char> hostname);
/// <summary>
/// Gets the local API URL.
/// </summary>
+ /// <param name="address">The IP address.</param>
+ /// <returns>The local API URL.</returns>
string GetLocalApiUrl(IPAddress address);
void LaunchUrl(string url);
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 6664b34a5..a46aa38d8 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -1371,24 +1371,25 @@ namespace MediaBrowser.MediaEncoding.Probing
{
video.Timestamp = GetMpegTimestamp(video.Path);
- _logger.LogDebug("Video has {timestamp} timestamp", video.Timestamp);
+ _logger.LogDebug("Video has {Timestamp} timestamp", video.Timestamp);
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error extracting timestamp info from {path}", video.Path);
+ _logger.LogError(ex, "Error extracting timestamp info from {Path}", video.Path);
video.Timestamp = null;
}
}
}
}
+ // REVIEW: find out why the byte array needs to be 197 bytes long and comment the reason
private TransportStreamTimestamp GetMpegTimestamp(string path)
{
- var packetBuffer = new byte['Å'];
+ var packetBuffer = new byte[197];
- using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
+ using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- fs.Read(packetBuffer, 0, packetBuffer.Length);
+ fs.Read(packetBuffer);
}
if (packetBuffer[0] == 71)
@@ -1396,7 +1397,7 @@ namespace MediaBrowser.MediaEncoding.Probing
return TransportStreamTimestamp.None;
}
- if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71))
+ if ((packetBuffer[4] == 71) && (packetBuffer[196] == 71))
{
if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0))
{
diff --git a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
index 241ebc6df..1b452b0ce 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
@@ -16,6 +16,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
using (var writer = new Utf8JsonWriter(stream))
{
var trackevents = info.TrackEvents;
+ writer.WriteStartObject();
writer.WriteStartArray("TrackEvents");
for (int i = 0; i < trackevents.Count; i++)
@@ -33,7 +34,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
writer.WriteEndObject();
}
+ writer.WriteEndArray();
writer.WriteEndObject();
+
+ writer.Flush();
}
}
}