mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-07 10:14:14 -04:00
Merge branch 'master' into Comment4
This commit is contained in:
commit
0f47b3ec2d
72
.ci/azure-pipelines-api-client.yml
Normal file
72
.ci/azure-pipelines-api-client.yml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
parameters:
|
||||||
|
- name: LinuxImage
|
||||||
|
type: string
|
||||||
|
default: "ubuntu-latest"
|
||||||
|
- name: GeneratorVersion
|
||||||
|
type: string
|
||||||
|
default: "5.0.0-beta2"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- job: GenerateApiClients
|
||||||
|
displayName: 'Generate Api Clients'
|
||||||
|
dependsOn: Test
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: "${{ parameters.LinuxImage }}"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: DownloadPipelineArtifact@2
|
||||||
|
displayName: 'Download OpenAPI Spec Artifact'
|
||||||
|
inputs:
|
||||||
|
source: 'current'
|
||||||
|
artifact: "OpenAPI Spec"
|
||||||
|
path: "$(System.ArtifactsDirectory)/openapispec"
|
||||||
|
runVersion: "latest"
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: 'Download OpenApi Generator'
|
||||||
|
inputs:
|
||||||
|
script: "wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/${{ parameters.GeneratorVersion }}/openapi-generator-cli-${{ parameters.GeneratorVersion }}.jar -O openapi-generator-cli.jar"
|
||||||
|
|
||||||
|
## Generate npm api client
|
||||||
|
# Unstable
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: 'Build unstable typescript axios client'
|
||||||
|
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||||
|
inputs:
|
||||||
|
script: "bash ./apiclient/templates/typescript/axios/generate.sh $(System.ArtifactsDirectory) $(Build.BuildNumber)"
|
||||||
|
|
||||||
|
# Stable
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: 'Build stable typescript axios client'
|
||||||
|
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||||
|
inputs:
|
||||||
|
script: "bash ./apiclient/templates/typescript/axios/generate.sh $(System.ArtifactsDirectory)"
|
||||||
|
|
||||||
|
## Run npm install
|
||||||
|
- task: Npm@1
|
||||||
|
displayName: 'Install npm dependencies'
|
||||||
|
inputs:
|
||||||
|
command: install
|
||||||
|
workingDir: ./apiclient/generated/typescript/axios
|
||||||
|
|
||||||
|
## Publish npm packages
|
||||||
|
# Unstable
|
||||||
|
- task: Npm@1
|
||||||
|
displayName: 'Publish unstable typescript axios client'
|
||||||
|
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||||
|
inputs:
|
||||||
|
command: publish
|
||||||
|
publishRegistry: useFeed
|
||||||
|
publishFeed: 'jellyfin/unstable'
|
||||||
|
workingDir: ./apiclient/generated/typescript/axios
|
||||||
|
|
||||||
|
# Stable
|
||||||
|
- task: Npm@1
|
||||||
|
displayName: 'Publish stable typescript axios client'
|
||||||
|
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||||
|
inputs:
|
||||||
|
command: publish
|
||||||
|
publishRegistry: useExternalRegistry
|
||||||
|
publishEndpoint: 'jellyfin-bot for NPM'
|
||||||
|
workingDir: ./apiclient/generated/typescript/axios
|
@ -63,7 +63,38 @@ jobs:
|
|||||||
sshEndpoint: repository
|
sshEndpoint: repository
|
||||||
sourceFolder: '$(Build.SourcesDirectory)/deployment/dist'
|
sourceFolder: '$(Build.SourcesDirectory)/deployment/dist'
|
||||||
contents: '**'
|
contents: '**'
|
||||||
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
|
|
||||||
|
- job: OpenAPISpec
|
||||||
|
dependsOn: Test
|
||||||
|
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/heads/master'),startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||||
|
displayName: 'Push OpenAPI Spec to repository'
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: DownloadPipelineArtifact@2
|
||||||
|
displayName: 'Download OpenAPI Spec'
|
||||||
|
inputs:
|
||||||
|
source: 'current'
|
||||||
|
artifact: "OpenAPI Spec"
|
||||||
|
path: "$(System.ArtifactsDirectory)/openapispec"
|
||||||
|
runVersion: "latest"
|
||||||
|
|
||||||
|
- task: SSH@0
|
||||||
|
displayName: 'Create target directory on repository server'
|
||||||
|
inputs:
|
||||||
|
sshEndpoint: repository
|
||||||
|
runOptions: 'inline'
|
||||||
|
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)'
|
||||||
|
|
||||||
|
- task: CopyFilesOverSSH@0
|
||||||
|
displayName: 'Upload artifacts to repository server'
|
||||||
|
inputs:
|
||||||
|
sshEndpoint: repository
|
||||||
|
sourceFolder: '$(System.ArtifactsDirectory)/openapispec'
|
||||||
|
contents: 'openapi.json'
|
||||||
|
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)'
|
||||||
|
|
||||||
- job: BuildDocker
|
- job: BuildDocker
|
||||||
displayName: 'Build Docker'
|
displayName: 'Build Docker'
|
||||||
|
@ -56,7 +56,7 @@ jobs:
|
|||||||
inputs:
|
inputs:
|
||||||
command: "test"
|
command: "test"
|
||||||
projects: ${{ parameters.TestProjects }}
|
projects: ${{ parameters.TestProjects }}
|
||||||
arguments: '--configuration Release --collect:"XPlat Code Coverage" --settings tests/coverletArgs.runsettings --verbosity minimal "-p:GenerateDocumentationFile=False"'
|
arguments: '--configuration Release --collect:"XPlat Code Coverage" --settings tests/coverletArgs.runsettings --verbosity minimal'
|
||||||
publishTestResults: true
|
publishTestResults: true
|
||||||
testRunTitle: $(Agent.JobName)
|
testRunTitle: $(Agent.JobName)
|
||||||
workingDirectory: "$(Build.SourcesDirectory)"
|
workingDirectory: "$(Build.SourcesDirectory)"
|
||||||
|
@ -35,6 +35,12 @@ jobs:
|
|||||||
Windows: 'windows-latest'
|
Windows: 'windows-latest'
|
||||||
macOS: 'macos-latest'
|
macOS: 'macos-latest'
|
||||||
|
|
||||||
|
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
|
||||||
|
- template: azure-pipelines-test.yml
|
||||||
|
parameters:
|
||||||
|
ImageNames:
|
||||||
|
Linux: 'ubuntu-latest'
|
||||||
|
|
||||||
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
|
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
|
||||||
- template: azure-pipelines-abi.yml
|
- template: azure-pipelines-abi.yml
|
||||||
parameters:
|
parameters:
|
||||||
@ -55,3 +61,6 @@ jobs:
|
|||||||
|
|
||||||
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
|
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
|
||||||
- template: azure-pipelines-package.yml
|
- template: azure-pipelines-package.yml
|
||||||
|
|
||||||
|
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
|
||||||
|
- template: azure-pipelines-api-client.yml
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -276,3 +276,4 @@ BenchmarkDotNet.Artifacts
|
|||||||
web/
|
web/
|
||||||
web-src.*
|
web-src.*
|
||||||
MediaBrowser.WebDashboard/jellyfin-web
|
MediaBrowser.WebDashboard/jellyfin-web
|
||||||
|
apiclient/generated
|
||||||
|
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@ -11,7 +11,11 @@
|
|||||||
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
||||||
"console": "internalConsole",
|
"console": "internalConsole",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"internalConsoleOptions": "openOnSessionStart"
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "openExternally",
|
||||||
|
"pattern": "Overriding address\\(es\\) \\'(https?:\\S+)\\'",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": ".NET Core Launch (nowebclient)",
|
"name": ".NET Core Launch (nowebclient)",
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
- [sl1288](https://github.com/sl1288)
|
- [sl1288](https://github.com/sl1288)
|
||||||
- [sorinyo2004](https://github.com/sorinyo2004)
|
- [sorinyo2004](https://github.com/sorinyo2004)
|
||||||
- [sparky8251](https://github.com/sparky8251)
|
- [sparky8251](https://github.com/sparky8251)
|
||||||
|
- [spookbits](https://github.com/spookbits)
|
||||||
- [stanionascu](https://github.com/stanionascu)
|
- [stanionascu](https://github.com/stanionascu)
|
||||||
- [stevehayles](https://github.com/stevehayles)
|
- [stevehayles](https://github.com/stevehayles)
|
||||||
- [SuperSandro2000](https://github.com/SuperSandro2000)
|
- [SuperSandro2000](https://github.com/SuperSandro2000)
|
||||||
@ -135,6 +136,8 @@
|
|||||||
- [YouKnowBlom](https://github.com/YouKnowBlom)
|
- [YouKnowBlom](https://github.com/YouKnowBlom)
|
||||||
- [KristupasSavickas](https://github.com/KristupasSavickas)
|
- [KristupasSavickas](https://github.com/KristupasSavickas)
|
||||||
- [Pusta](https://github.com/pusta)
|
- [Pusta](https://github.com/pusta)
|
||||||
|
- [nielsvanvelzen](https://github.com/nielsvanvelzen)
|
||||||
|
- [skyfrk](https://github.com/skyfrk)
|
||||||
|
|
||||||
# Emby Contributors
|
# Emby Contributors
|
||||||
|
|
||||||
@ -198,3 +201,4 @@
|
|||||||
- [tikuf](https://github.com/tikuf/)
|
- [tikuf](https://github.com/tikuf/)
|
||||||
- [Tim Hobbs](https://github.com/timhobbs)
|
- [Tim Hobbs](https://github.com/timhobbs)
|
||||||
- [SvenVandenbrande](https://github.com/SvenVandenbrande)
|
- [SvenVandenbrande](https://github.com/SvenVandenbrande)
|
||||||
|
- [olsh](https://github.com/olsh)
|
||||||
|
@ -126,14 +126,14 @@ namespace Emby.Dlna
|
|||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
builder.AppendLine("No matching device profile found. The default will need to be used.");
|
builder.AppendLine("No matching device profile found. The default will need to be used.");
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "FriendlyName:{0}", profile.FriendlyName ?? string.Empty).AppendLine();
|
builder.Append("FriendlyName:").AppendLine(profile.FriendlyName);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "Manufacturer:{0}", profile.Manufacturer ?? string.Empty).AppendLine();
|
builder.Append("Manufacturer:").AppendLine(profile.Manufacturer);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "ManufacturerUrl:{0}", profile.ManufacturerUrl ?? string.Empty).AppendLine();
|
builder.Append("ManufacturerUrl:").AppendLine(profile.ManufacturerUrl);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "ModelDescription:{0}", profile.ModelDescription ?? string.Empty).AppendLine();
|
builder.Append("ModelDescription:").AppendLine(profile.ModelDescription);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "ModelName:{0}", profile.ModelName ?? string.Empty).AppendLine();
|
builder.Append("ModelName:").AppendLine(profile.ModelName);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "ModelNumber:{0}", profile.ModelNumber ?? string.Empty).AppendLine();
|
builder.Append("ModelNumber:").AppendLine(profile.ModelNumber);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "ModelUrl:{0}", profile.ModelUrl ?? string.Empty).AppendLine();
|
builder.Append("ModelUrl:").AppendLine(profile.ModelUrl);
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, "SerialNumber:{0}", profile.SerialNumber ?? string.Empty).AppendLine();
|
builder.Append("SerialNumber:").AppendLine(profile.SerialNumber);
|
||||||
|
|
||||||
_logger.LogInformation(builder.ToString());
|
_logger.LogInformation(builder.ToString());
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 278 B |
@ -669,9 +669,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
private Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
private Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (Enum.TryParse(command.Name, true, out GeneralCommandType commandType))
|
switch (command.Name)
|
||||||
{
|
|
||||||
switch (commandType)
|
|
||||||
{
|
{
|
||||||
case GeneralCommandType.VolumeDown:
|
case GeneralCommandType.VolumeDown:
|
||||||
return _device.VolumeDown(cancellationToken);
|
return _device.VolumeDown(cancellationToken);
|
||||||
@ -724,9 +722,6 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetAudioStreamIndex(int? newIndex)
|
private async Task SetAudioStreamIndex(int? newIndex)
|
||||||
{
|
{
|
||||||
var media = _device.CurrentMediaInfo;
|
var media = _device.CurrentMediaInfo;
|
||||||
@ -816,7 +811,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task SendMessage<T>(string name, Guid messageId, T data, CancellationToken cancellationToken)
|
public Task SendMessage<T>(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
@ -828,17 +823,17 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(name, "Play", StringComparison.OrdinalIgnoreCase))
|
if (name == SessionMessageType.Play)
|
||||||
{
|
{
|
||||||
return SendPlayCommand(data as PlayRequest, cancellationToken);
|
return SendPlayCommand(data as PlayRequest, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(name, "PlayState", StringComparison.OrdinalIgnoreCase))
|
if (name == SessionMessageType.PlayState)
|
||||||
{
|
{
|
||||||
return SendPlaystateCommand(data as PlaystateRequest, cancellationToken);
|
return SendPlaystateCommand(data as PlaystateRequest, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(name, "GeneralCommand", StringComparison.OrdinalIgnoreCase))
|
if (name == SessionMessageType.GeneralCommand)
|
||||||
{
|
{
|
||||||
return SendGeneralCommand(data as GeneralCommand, cancellationToken);
|
return SendGeneralCommand(data as GeneralCommand, cancellationToken);
|
||||||
}
|
}
|
||||||
@ -886,7 +881,10 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_mediaSourceManager != null)
|
||||||
|
{
|
||||||
mediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false);
|
mediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
return mediaSource;
|
return mediaSource;
|
||||||
}
|
}
|
||||||
|
@ -217,15 +217,15 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
SupportedCommands = new[]
|
SupportedCommands = new[]
|
||||||
{
|
{
|
||||||
GeneralCommandType.VolumeDown.ToString(),
|
GeneralCommandType.VolumeDown,
|
||||||
GeneralCommandType.VolumeUp.ToString(),
|
GeneralCommandType.VolumeUp,
|
||||||
GeneralCommandType.Mute.ToString(),
|
GeneralCommandType.Mute,
|
||||||
GeneralCommandType.Unmute.ToString(),
|
GeneralCommandType.Unmute,
|
||||||
GeneralCommandType.ToggleMute.ToString(),
|
GeneralCommandType.ToggleMute,
|
||||||
GeneralCommandType.SetVolume.ToString(),
|
GeneralCommandType.SetVolume,
|
||||||
GeneralCommandType.SetAudioStreamIndex.ToString(),
|
GeneralCommandType.SetAudioStreamIndex,
|
||||||
GeneralCommandType.SetSubtitleStreamIndex.ToString(),
|
GeneralCommandType.SetSubtitleStreamIndex,
|
||||||
GeneralCommandType.PlayMediaSource.ToString()
|
GeneralCommandType.PlayMediaSource
|
||||||
},
|
},
|
||||||
|
|
||||||
SupportsMediaControl = true
|
SupportsMediaControl = true
|
||||||
|
@ -146,12 +146,12 @@ namespace Emby.Dlna.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ControlRequestInfo();
|
throw new EndOfStreamException("Stream ended but no body tag found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
|
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
|
||||||
{
|
{
|
||||||
var result = new ControlRequestInfo();
|
string namespaceURI = null, localName = null;
|
||||||
|
|
||||||
await reader.MoveToContentAsync().ConfigureAwait(false);
|
await reader.MoveToContentAsync().ConfigureAwait(false);
|
||||||
await reader.ReadAsync().ConfigureAwait(false);
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
@ -161,14 +161,14 @@ namespace Emby.Dlna.Service
|
|||||||
{
|
{
|
||||||
if (reader.NodeType == XmlNodeType.Element)
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
{
|
{
|
||||||
result.LocalName = reader.LocalName;
|
localName = reader.LocalName;
|
||||||
result.NamespaceURI = reader.NamespaceURI;
|
namespaceURI = reader.NamespaceURI;
|
||||||
|
|
||||||
if (!reader.IsEmptyElement)
|
if (!reader.IsEmptyElement)
|
||||||
{
|
{
|
||||||
|
var result = new ControlRequestInfo(localName, namespaceURI);
|
||||||
using var subReader = reader.ReadSubtree();
|
using var subReader = reader.ReadSubtree();
|
||||||
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
|
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -181,7 +181,12 @@ namespace Emby.Dlna.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
if (localName != null && namespaceURI != null)
|
||||||
|
{
|
||||||
|
return new ControlRequestInfo(localName, namespaceURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new EndOfStreamException("Stream ended but no control found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers)
|
private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers)
|
||||||
@ -228,11 +233,18 @@ namespace Emby.Dlna.Service
|
|||||||
|
|
||||||
private class ControlRequestInfo
|
private class ControlRequestInfo
|
||||||
{
|
{
|
||||||
|
public ControlRequestInfo(string localName, string namespaceUri)
|
||||||
|
{
|
||||||
|
LocalName = localName;
|
||||||
|
NamespaceURI = namespaceUri;
|
||||||
|
Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
public string LocalName { get; set; }
|
public string LocalName { get; set; }
|
||||||
|
|
||||||
public string NamespaceURI { get; set; }
|
public string NamespaceURI { get; set; }
|
||||||
|
|
||||||
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
public Dictionary<string, string> Headers { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ namespace Emby.Drawing
|
|||||||
throw new ArgumentException("Path can't be empty.", nameof(path));
|
throw new ArgumentException("Path can't be empty.", nameof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.IsEmpty)
|
if (filename.IsEmpty)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Filename can't be empty.", nameof(filename));
|
throw new ArgumentException("Filename can't be empty.", nameof(filename));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
#nullable enable
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@ -19,12 +19,7 @@ namespace Emby.Naming.AudioBook
|
|||||||
|
|
||||||
public AudioBookFilePathParserResult Parse(string path)
|
public AudioBookFilePathParserResult Parse(string path)
|
||||||
{
|
{
|
||||||
if (path == null)
|
AudioBookFilePathParserResult result = default;
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = new AudioBookFilePathParserResult();
|
|
||||||
var fileName = Path.GetFileNameWithoutExtension(path);
|
var fileName = Path.GetFileNameWithoutExtension(path);
|
||||||
foreach (var expression in _options.AudioBookPartsExpressions)
|
foreach (var expression in _options.AudioBookPartsExpressions)
|
||||||
{
|
{
|
||||||
@ -50,27 +45,14 @@ namespace Emby.Naming.AudioBook
|
|||||||
{
|
{
|
||||||
if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
|
if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
|
||||||
{
|
{
|
||||||
result.ChapterNumber = intValue;
|
result.PartNumber = intValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*var matches = _iRegexProvider.GetRegex("\\d+", RegexOptions.IgnoreCase).Matches(fileName);
|
result.Success = result.ChapterNumber.HasValue || result.PartNumber.HasValue;
|
||||||
if (matches.Count > 0)
|
|
||||||
{
|
|
||||||
if (!result.ChapterNumber.HasValue)
|
|
||||||
{
|
|
||||||
result.ChapterNumber = int.Parse(matches[0].Groups[0].Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matches.Count > 1)
|
|
||||||
{
|
|
||||||
result.PartNumber = int.Parse(matches[matches.Count - 1].Groups[0].Value);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
result.Success = result.PartNumber.HasValue || result.ChapterNumber.HasValue;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
#nullable enable
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
namespace Emby.Naming.AudioBook
|
namespace Emby.Naming.AudioBook
|
||||||
{
|
{
|
||||||
public class AudioBookFilePathParserResult
|
public struct AudioBookFilePathParserResult
|
||||||
{
|
{
|
||||||
public int? PartNumber { get; set; }
|
public int? PartNumber { get; set; }
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ namespace Emby.Naming.AudioBook
|
|||||||
{
|
{
|
||||||
Path = path,
|
Path = path,
|
||||||
Container = container,
|
Container = container,
|
||||||
PartNumber = parsingResult.PartNumber,
|
|
||||||
ChapterNumber = parsingResult.ChapterNumber,
|
ChapterNumber = parsingResult.ChapterNumber,
|
||||||
|
PartNumber = parsingResult.PartNumber,
|
||||||
IsDirectory = isDirectory
|
IsDirectory = isDirectory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@ -37,6 +38,7 @@ using Emby.Server.Implementations.LiveTv;
|
|||||||
using Emby.Server.Implementations.Localization;
|
using Emby.Server.Implementations.Localization;
|
||||||
using Emby.Server.Implementations.Net;
|
using Emby.Server.Implementations.Net;
|
||||||
using Emby.Server.Implementations.Playlists;
|
using Emby.Server.Implementations.Playlists;
|
||||||
|
using Emby.Server.Implementations.Plugins;
|
||||||
using Emby.Server.Implementations.QuickConnect;
|
using Emby.Server.Implementations.QuickConnect;
|
||||||
using Emby.Server.Implementations.ScheduledTasks;
|
using Emby.Server.Implementations.ScheduledTasks;
|
||||||
using Emby.Server.Implementations.Security;
|
using Emby.Server.Implementations.Security;
|
||||||
@ -95,6 +97,7 @@ using MediaBrowser.Model.Tasks;
|
|||||||
using MediaBrowser.Providers.Chapters;
|
using MediaBrowser.Providers.Chapters;
|
||||||
using MediaBrowser.Providers.Manager;
|
using MediaBrowser.Providers.Manager;
|
||||||
using MediaBrowser.Providers.Plugins.TheTvdb;
|
using MediaBrowser.Providers.Plugins.TheTvdb;
|
||||||
|
using MediaBrowser.Providers.Plugins.Tmdb;
|
||||||
using MediaBrowser.Providers.Subtitles;
|
using MediaBrowser.Providers.Subtitles;
|
||||||
using MediaBrowser.XbmcMetadata.Providers;
|
using MediaBrowser.XbmcMetadata.Providers;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -119,6 +122,7 @@ namespace Emby.Server.Implementations
|
|||||||
private readonly IFileSystem _fileSystemManager;
|
private readonly IFileSystem _fileSystemManager;
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
private readonly IXmlSerializer _xmlSerializer;
|
private readonly IXmlSerializer _xmlSerializer;
|
||||||
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IStartupOptions _startupOptions;
|
private readonly IStartupOptions _startupOptions;
|
||||||
|
|
||||||
private IMediaEncoder _mediaEncoder;
|
private IMediaEncoder _mediaEncoder;
|
||||||
@ -255,6 +259,8 @@ namespace Emby.Server.Implementations
|
|||||||
IServiceCollection serviceCollection)
|
IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
_xmlSerializer = new MyXmlSerializer();
|
_xmlSerializer = new MyXmlSerializer();
|
||||||
|
_jsonSerializer = new JsonSerializer();
|
||||||
|
|
||||||
ServiceCollection = serviceCollection;
|
ServiceCollection = serviceCollection;
|
||||||
|
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
@ -532,6 +538,7 @@ namespace Emby.Server.Implementations
|
|||||||
|
|
||||||
ServiceCollection.AddSingleton(_fileSystemManager);
|
ServiceCollection.AddSingleton(_fileSystemManager);
|
||||||
ServiceCollection.AddSingleton<TvdbClientManager>();
|
ServiceCollection.AddSingleton<TvdbClientManager>();
|
||||||
|
ServiceCollection.AddSingleton<TmdbClientManager>();
|
||||||
|
|
||||||
ServiceCollection.AddSingleton(_networkManager);
|
ServiceCollection.AddSingleton(_networkManager);
|
||||||
|
|
||||||
@ -1021,6 +1028,119 @@ namespace Emby.Server.Implementations
|
|||||||
|
|
||||||
protected abstract void RestartInternal();
|
protected abstract void RestartInternal();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Comparison function used in <see cref="GetPlugins" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">Item to compare.</param>
|
||||||
|
/// <param name="b">Item to compare with.</param>
|
||||||
|
/// <returns>Boolean result of the operation.</returns>
|
||||||
|
private static int VersionCompare(
|
||||||
|
(Version PluginVersion, string Name, string Path) a,
|
||||||
|
(Version PluginVersion, string Name, string Path) b)
|
||||||
|
{
|
||||||
|
int compare = string.Compare(a.Name, b.Name, true, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
if (compare == 0)
|
||||||
|
{
|
||||||
|
return a.PluginVersion.CompareTo(b.PluginVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of plugins to install.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">Path to check.</param>
|
||||||
|
/// <param name="cleanup">True if an attempt should be made to delete old plugs.</param>
|
||||||
|
/// <returns>Enumerable list of dlls to load.</returns>
|
||||||
|
private IEnumerable<string> GetPlugins(string path, bool cleanup = true)
|
||||||
|
{
|
||||||
|
var dllList = new List<string>();
|
||||||
|
var versions = new List<(Version PluginVersion, string Name, string Path)>();
|
||||||
|
var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
|
||||||
|
string metafile;
|
||||||
|
|
||||||
|
foreach (var dir in directories)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
metafile = Path.Combine(dir, "meta.json");
|
||||||
|
if (File.Exists(metafile))
|
||||||
|
{
|
||||||
|
var manifest = _jsonSerializer.DeserializeFromFile<PluginManifest>(metafile);
|
||||||
|
|
||||||
|
if (!Version.TryParse(manifest.TargetAbi, out var targetAbi))
|
||||||
|
{
|
||||||
|
targetAbi = new Version(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Version.TryParse(manifest.Version, out var version))
|
||||||
|
{
|
||||||
|
version = new Version(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ApplicationVersion >= targetAbi)
|
||||||
|
{
|
||||||
|
// Only load Plugins if the plugin is built for this version or below.
|
||||||
|
versions.Add((version, manifest.Name, dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No metafile, so lets see if the folder is versioned.
|
||||||
|
metafile = dir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries)[^1];
|
||||||
|
|
||||||
|
int versionIndex = dir.LastIndexOf('_');
|
||||||
|
if (versionIndex != -1 && Version.TryParse(dir.Substring(versionIndex + 1), out Version ver))
|
||||||
|
{
|
||||||
|
// Versioned folder.
|
||||||
|
versions.Add((ver, metafile, dir));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Un-versioned folder - Add it under the path name and version 0.0.0.1.
|
||||||
|
versions.Add((new Version(0, 0, 0, 1), metafile, dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string lastName = string.Empty;
|
||||||
|
versions.Sort(VersionCompare);
|
||||||
|
// Traverse backwards through the list.
|
||||||
|
// The first item will be the latest version.
|
||||||
|
for (int x = versions.Count - 1; x >= 0; x--)
|
||||||
|
{
|
||||||
|
if (!string.Equals(lastName, versions[x].Name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
dllList.AddRange(Directory.EnumerateFiles(versions[x].Path, "*.dll", SearchOption.AllDirectories));
|
||||||
|
lastName = versions[x].Name;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(lastName) && cleanup)
|
||||||
|
{
|
||||||
|
// Attempt a cleanup of old folders.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.LogDebug("Deleting {Path}", versions[x].Path);
|
||||||
|
Directory.Delete(versions[x].Path, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(e, "Unable to delete {Path}", versions[x].Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dllList;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the composable part assemblies.
|
/// Gets the composable part assemblies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1029,7 +1149,7 @@ namespace Emby.Server.Implementations
|
|||||||
{
|
{
|
||||||
if (Directory.Exists(ApplicationPaths.PluginsPath))
|
if (Directory.Exists(ApplicationPaths.PluginsPath))
|
||||||
{
|
{
|
||||||
foreach (var file in Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories))
|
foreach (var file in GetPlugins(ApplicationPaths.PluginsPath))
|
||||||
{
|
{
|
||||||
Assembly plugAss;
|
Assembly plugAss;
|
||||||
try
|
try
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Browser
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Assists in opening application URLs in an external browser.
|
|
||||||
/// </summary>
|
|
||||||
public static class BrowserLauncher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Opens the home page of the web client.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="appHost">The app host.</param>
|
|
||||||
public static void OpenWebApp(IServerApplicationHost appHost)
|
|
||||||
{
|
|
||||||
TryOpenUrl(appHost, "/web/index.html");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Opens the swagger API page.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="appHost">The app host.</param>
|
|
||||||
public static void OpenSwaggerPage(IServerApplicationHost appHost)
|
|
||||||
{
|
|
||||||
TryOpenUrl(appHost, "/api-docs/swagger");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Opens the specified URL in an external browser window. Any exceptions will be logged, but ignored.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="appHost">The application host.</param>
|
|
||||||
/// <param name="relativeUrl">The URL to open, relative to the server base URL.</param>
|
|
||||||
private static void TryOpenUrl(IServerApplicationHost appHost, string relativeUrl)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string baseUrl = appHost.GetLocalApiUrl("localhost");
|
|
||||||
appHost.LaunchUrl(baseUrl + relativeUrl);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var logger = appHost.Resolve<ILogger<IServerApplicationHost>>();
|
|
||||||
logger?.LogError(ex, "Failed to open browser window with URL {URL}", relativeUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -234,7 +234,9 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam))
|
if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam))
|
||||||
{
|
{
|
||||||
bindParam.Bind(value.ToByteArray());
|
Span<byte> byteValue = stackalloc byte[16];
|
||||||
|
value.TryWriteBytes(byteValue);
|
||||||
|
bindParam.Bind(byteValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2263,7 +2263,6 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return query.IncludeItemTypes.Contains("Trailer", StringComparer.OrdinalIgnoreCase);
|
return query.IncludeItemTypes.Contains("Trailer", StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static readonly HashSet<string> _artistExcludeParentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
private static readonly HashSet<string> _artistExcludeParentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
"Series",
|
"Series",
|
||||||
@ -3291,7 +3290,6 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
|
var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
|
||||||
|
|
||||||
var statementTexts = new List<string>();
|
var statementTexts = new List<string>();
|
||||||
@ -6006,7 +6004,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the chapter.
|
/// Gets the chapter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -468,7 +468,6 @@ namespace Emby.Server.Implementations.Dto
|
|||||||
IncludeItemTypes = new[] { typeof(MusicAlbum).Name },
|
IncludeItemTypes = new[] { typeof(MusicAlbum).Name },
|
||||||
Name = item.Album,
|
Name = item.Album,
|
||||||
Limit = 1
|
Limit = 1
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (parentAlbumIds.Count > 0)
|
if (parentAlbumIds.Count > 0)
|
||||||
@ -1139,6 +1138,7 @@ namespace Emby.Server.Implementations.Dto
|
|||||||
if (episodeSeries != null)
|
if (episodeSeries != null)
|
||||||
{
|
{
|
||||||
dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, episodeSeries, ImageType.Primary);
|
dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, episodeSeries, ImageType.Primary);
|
||||||
|
AttachPrimaryImageAspectRatio(dto, episodeSeries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1185,6 +1185,7 @@ namespace Emby.Server.Implementations.Dto
|
|||||||
if (series != null)
|
if (series != null)
|
||||||
{
|
{
|
||||||
dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, series, ImageType.Primary);
|
dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, series, ImageType.Primary);
|
||||||
|
AttachPrimaryImageAspectRatio(dto, series);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1431,7 +1432,7 @@ namespace Emby.Server.Implementations.Dto
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return width / height;
|
return (double)width / height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="IPNetwork2" Version="2.5.224" />
|
<PackageReference Include="IPNetwork2" Version="2.5.226" />
|
||||||
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
|
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
|
||||||
@ -32,11 +32,11 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.7" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.7" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.7" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.8" />
|
||||||
<PackageReference Include="Mono.Nat" Version="2.0.2" />
|
<PackageReference Include="Mono.Nat" Version="3.0.0" />
|
||||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.0" />
|
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.0" />
|
||||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
|
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
|
||||||
<PackageReference Include="sharpcompress" Version="0.26.0" />
|
<PackageReference Include="sharpcompress" Version="0.26.0" />
|
||||||
|
@ -16,6 +16,7 @@ using MediaBrowser.Controller.Plugins;
|
|||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.EntryPoints
|
namespace Emby.Server.Implementations.EntryPoints
|
||||||
@ -105,7 +106,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_sessionManager.SendMessageToAdminSessions("RefreshProgress", dict, CancellationToken.None);
|
_sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, dict, CancellationToken.None);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_sessionManager.SendMessageToAdminSessions("RefreshProgress", collectionFolderDict, CancellationToken.None);
|
_sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, collectionFolderDict, CancellationToken.None);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -345,7 +346,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _sessionManager.SendMessageToUserSessions(new List<Guid> { userId }, "LibraryChanged", info, cancellationToken).ConfigureAwait(false);
|
await _sessionManager.SendMessageToUserSessions(new List<Guid> { userId }, SessionMessageType.LibraryChanged, info, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@ using MediaBrowser.Controller.Library;
|
|||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.EntryPoints
|
namespace Emby.Server.Implementations.EntryPoints
|
||||||
@ -46,25 +47,25 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
private async void OnLiveTvManagerSeriesTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e)
|
private async void OnLiveTvManagerSeriesTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||||
{
|
{
|
||||||
await SendMessage("SeriesTimerCreated", e.Argument).ConfigureAwait(false);
|
await SendMessage(SessionMessageType.SeriesTimerCreated, e.Argument).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnLiveTvManagerTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e)
|
private async void OnLiveTvManagerTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||||
{
|
{
|
||||||
await SendMessage("TimerCreated", e.Argument).ConfigureAwait(false);
|
await SendMessage(SessionMessageType.TimerCreated, e.Argument).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnLiveTvManagerSeriesTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e)
|
private async void OnLiveTvManagerSeriesTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||||
{
|
{
|
||||||
await SendMessage("SeriesTimerCancelled", e.Argument).ConfigureAwait(false);
|
await SendMessage(SessionMessageType.SeriesTimerCancelled, e.Argument).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnLiveTvManagerTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e)
|
private async void OnLiveTvManagerTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||||
{
|
{
|
||||||
await SendMessage("TimerCancelled", e.Argument).ConfigureAwait(false);
|
await SendMessage(SessionMessageType.TimerCancelled, e.Argument).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendMessage(string name, TimerEventInfo info)
|
private async Task SendMessage(SessionMessageType name, TimerEventInfo info)
|
||||||
{
|
{
|
||||||
var users = _userManager.Users.Where(i => i.HasPermission(PermissionKind.EnableLiveTvAccess)).Select(i => i.Id).ToList();
|
var users = _userManager.Users.Where(i => i.HasPermission(PermissionKind.EnableLiveTvAccess)).Select(i => i.Id).ToList();
|
||||||
|
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Emby.Server.Implementations.Browser;
|
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Extensions;
|
|
||||||
using MediaBrowser.Controller.Plugins;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.EntryPoints
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class StartupWizard.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class StartupWizard : IServerEntryPoint
|
|
||||||
{
|
|
||||||
private readonly IServerApplicationHost _appHost;
|
|
||||||
private readonly IConfiguration _appConfig;
|
|
||||||
private readonly IServerConfigurationManager _config;
|
|
||||||
private readonly IStartupOptions _startupOptions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="StartupWizard"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="appHost">The application host.</param>
|
|
||||||
/// <param name="appConfig">The application configuration.</param>
|
|
||||||
/// <param name="config">The configuration manager.</param>
|
|
||||||
/// <param name="startupOptions">The application startup options.</param>
|
|
||||||
public StartupWizard(
|
|
||||||
IServerApplicationHost appHost,
|
|
||||||
IConfiguration appConfig,
|
|
||||||
IServerConfigurationManager config,
|
|
||||||
IStartupOptions startupOptions)
|
|
||||||
{
|
|
||||||
_appHost = appHost;
|
|
||||||
_appConfig = appConfig;
|
|
||||||
_config = config;
|
|
||||||
_startupOptions = startupOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task RunAsync()
|
|
||||||
{
|
|
||||||
Run();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Run()
|
|
||||||
{
|
|
||||||
if (!_appHost.CanLaunchWebBrowser)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always launch the startup wizard if possible when it has not been completed
|
|
||||||
if (!_config.Configuration.IsStartupWizardCompleted && _appConfig.HostWebClient())
|
|
||||||
{
|
|
||||||
BrowserLauncher.OpenWebApp(_appHost);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing if the web app is configured to not run automatically
|
|
||||||
if (!_config.Configuration.AutoRunWebApp || _startupOptions.NoAutoRunWebApp)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Launch the swagger page if the web client is not hosted, otherwise open the web client
|
|
||||||
if (_appConfig.HostWebClient())
|
|
||||||
{
|
|
||||||
BrowserLauncher.OpenWebApp(_appHost);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BrowserLauncher.OpenSwaggerPage(_appHost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
private readonly object _syncLock = new object();
|
private readonly object _syncLock = new object();
|
||||||
private Timer _updateTimer;
|
private Timer _updateTimer;
|
||||||
|
|
||||||
|
|
||||||
public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, IUserManager userManager)
|
public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, IUserManager userManager)
|
||||||
{
|
{
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
@ -116,7 +115,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
private Task SendNotifications(Guid userId, List<BaseItem> changedItems, CancellationToken cancellationToken)
|
private Task SendNotifications(Guid userId, List<BaseItem> changedItems, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return _sessionManager.SendMessageToUserSessions(new List<Guid> { userId }, "UserDataChanged", () => GetUserDataChangeInfo(userId, changedItems), cancellationToken);
|
return _sessionManager.SendMessageToUserSessions(new List<Guid> { userId }, SessionMessageType.UserDataChanged, () => GetUserDataChangeInfo(userId, changedItems), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserDataChangeInfo GetUserDataChangeInfo(Guid userId, List<BaseItem> changedItems)
|
private UserDataChangeInfo GetUserDataChangeInfo(Guid userId, List<BaseItem> changedItems)
|
||||||
|
@ -11,6 +11,7 @@ using System.Threading.Tasks;
|
|||||||
using MediaBrowser.Common.Json;
|
using MediaBrowser.Common.Json;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@ -227,7 +228,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
Connection = this
|
Connection = this
|
||||||
};
|
};
|
||||||
|
|
||||||
if (info.MessageType.Equals("KeepAlive", StringComparison.Ordinal))
|
if (info.MessageType == SessionMessageType.KeepAlive)
|
||||||
{
|
{
|
||||||
await SendKeepAliveResponse().ConfigureAwait(false);
|
await SendKeepAliveResponse().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -244,7 +245,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
new WebSocketMessage<string>
|
new WebSocketMessage<string>
|
||||||
{
|
{
|
||||||
MessageId = Guid.NewGuid(),
|
MessageId = Guid.NewGuid(),
|
||||||
MessageType = "KeepAlive"
|
MessageType = SessionMessageType.KeepAlive
|
||||||
}, CancellationToken.None);
|
}, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,11 +16,6 @@ namespace Emby.Server.Implementations
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsService { get; }
|
bool IsService { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of the --noautorunwebapp command line option.
|
|
||||||
/// </summary>
|
|
||||||
bool NoAutoRunWebApp { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value of the --package-name command line option.
|
/// Gets the value of the --package-name command line option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Emby.Naming.Audio;
|
using Emby.Naming.Audio;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
@ -113,22 +116,29 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
ILibraryManager libraryManager)
|
ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
|
// check for audio files before digging down into directories
|
||||||
|
var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && libraryManager.IsAudioFile(fileSystemInfo.FullName));
|
||||||
|
if (foundAudioFile)
|
||||||
|
{
|
||||||
|
// at least one audio file exists
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allowSubfolders)
|
||||||
|
{
|
||||||
|
// not music since no audio file exists and we're not looking into subfolders
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var discSubfolderCount = 0;
|
var discSubfolderCount = 0;
|
||||||
var notMultiDisc = false;
|
|
||||||
|
|
||||||
var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
|
var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
|
||||||
var parser = new AlbumParser(namingOptions);
|
var parser = new AlbumParser(namingOptions);
|
||||||
foreach (var fileSystemInfo in list)
|
|
||||||
{
|
|
||||||
if (fileSystemInfo.IsDirectory)
|
|
||||||
{
|
|
||||||
if (allowSubfolders)
|
|
||||||
{
|
|
||||||
if (notMultiDisc)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var directories = list.Where(fileSystemInfo => fileSystemInfo.IsDirectory);
|
||||||
|
|
||||||
|
var result = Parallel.ForEach(directories, (fileSystemInfo, state) =>
|
||||||
|
{
|
||||||
var path = fileSystemInfo.FullName;
|
var path = fileSystemInfo.FullName;
|
||||||
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
|
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
|
||||||
|
|
||||||
@ -137,28 +147,17 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||||||
if (parser.IsMultiPart(path))
|
if (parser.IsMultiPart(path))
|
||||||
{
|
{
|
||||||
logger.LogDebug("Found multi-disc folder: " + path);
|
logger.LogDebug("Found multi-disc folder: " + path);
|
||||||
discSubfolderCount++;
|
Interlocked.Increment(ref discSubfolderCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
|
// If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
|
||||||
notMultiDisc = true;
|
state.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var fullName = fileSystemInfo.FullName;
|
|
||||||
|
|
||||||
if (libraryManager.IsAudioFile(fullName))
|
if (!result.IsCompleted)
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notMultiDisc)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
@ -94,7 +95,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||||||
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
|
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
|
||||||
|
|
||||||
// If we contain an album assume we are an artist folder
|
// If we contain an album assume we are an artist folder
|
||||||
return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService)) ? new MusicArtist() : null;
|
var directories = args.FileSystemChildren.Where(i => i.IsDirectory);
|
||||||
|
|
||||||
|
var result = Parallel.ForEach(directories, (fileSystemInfo, state) =>
|
||||||
|
{
|
||||||
|
if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, directoryService))
|
||||||
|
{
|
||||||
|
// stop once we see a music album
|
||||||
|
state.Stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return !result.IsCompleted ? new MusicArtist() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -874,7 +874,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
public List<Lineup> lineups { get; set; }
|
public List<Lineup> lineups { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class Headends
|
public class Headends
|
||||||
{
|
{
|
||||||
public string headend { get; set; }
|
public string headend { get; set; }
|
||||||
@ -886,8 +885,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
public List<Lineup> lineups { get; set; }
|
public List<Lineup> lineups { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class Map
|
public class Map
|
||||||
{
|
{
|
||||||
public string stationID { get; set; }
|
public string stationID { get; set; }
|
||||||
@ -971,9 +968,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
public List<string> date { get; set; }
|
public List<string> date { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class Rating
|
public class Rating
|
||||||
{
|
{
|
||||||
public string body { get; set; }
|
public string body { get; set; }
|
||||||
@ -1017,8 +1011,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
public string isPremiereOrFinale { get; set; }
|
public string isPremiereOrFinale { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class MetadataSchedule
|
public class MetadataSchedule
|
||||||
{
|
{
|
||||||
public string modified { get; set; }
|
public string modified { get; set; }
|
||||||
|
@ -2135,6 +2135,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool _disposed = false;
|
private bool _disposed = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -563,6 +563,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||||||
|
|
||||||
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, ChannelInfo channelInfo, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, ChannelInfo channelInfo, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var tunerCount = info.TunerCount;
|
||||||
|
|
||||||
|
if (tunerCount > 0)
|
||||||
|
{
|
||||||
|
var tunerHostId = info.Id;
|
||||||
|
var liveStreams = currentLiveStreams.Where(i => string.Equals(i.TunerHostId, tunerHostId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (liveStreams.Count() >= tunerCount)
|
||||||
|
{
|
||||||
|
throw new LiveTvConflictException("HDHomeRun simultaneous stream limit has been reached.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var profile = streamId.Split('_')[0];
|
var profile = streamId.Split('_')[0];
|
||||||
|
|
||||||
Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channelInfo.Id, streamId, profile);
|
Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channelInfo.Id, streamId, profile);
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"Artists": "Kunstenare",
|
"Artists": "Kunstenare",
|
||||||
"Channels": "Kanale",
|
"Channels": "Kanale",
|
||||||
"Folders": "Fouers",
|
"Folders": "Lêergidse",
|
||||||
"Favorites": "Gunstelinge",
|
"Favorites": "Gunstellinge",
|
||||||
"HeaderFavoriteShows": "Gunsteling Vertonings",
|
"HeaderFavoriteShows": "Gunsteling Vertonings",
|
||||||
"ValueSpecialEpisodeName": "Spesiale - {0}",
|
"ValueSpecialEpisodeName": "Spesiale - {0}",
|
||||||
"HeaderAlbumArtists": "Album Kunstenaars",
|
"HeaderAlbumArtists": "Album Kunstenaars",
|
||||||
"Books": "Boeke",
|
"Books": "Boeke",
|
||||||
"HeaderNextUp": "Volgende",
|
"HeaderNextUp": "Volgende",
|
||||||
"Movies": "Rolprente",
|
"Movies": "Flieks",
|
||||||
"Shows": "Program",
|
"Shows": "Televisie Reekse",
|
||||||
"HeaderContinueWatching": "Hou Aan Kyk",
|
"HeaderContinueWatching": "Kyk Verder",
|
||||||
"HeaderFavoriteEpisodes": "Gunsteling Episodes",
|
"HeaderFavoriteEpisodes": "Gunsteling Episodes",
|
||||||
"Photos": "Fotos",
|
"Photos": "Fotos",
|
||||||
"Playlists": "Speellysse",
|
"Playlists": "Snitlyste",
|
||||||
"HeaderFavoriteArtists": "Gunsteling Kunstenaars",
|
"HeaderFavoriteArtists": "Gunsteling Kunstenaars",
|
||||||
"HeaderFavoriteAlbums": "Gunsteling Albums",
|
"HeaderFavoriteAlbums": "Gunsteling Albums",
|
||||||
"Sync": "Sinkroniseer",
|
"Sync": "Sinkroniseer",
|
||||||
@ -23,7 +23,7 @@
|
|||||||
"DeviceOfflineWithName": "{0} is ontkoppel",
|
"DeviceOfflineWithName": "{0} is ontkoppel",
|
||||||
"Collections": "Versamelings",
|
"Collections": "Versamelings",
|
||||||
"Inherit": "Ontvang",
|
"Inherit": "Ontvang",
|
||||||
"HeaderLiveTV": "Live TV",
|
"HeaderLiveTV": "Lewendige TV",
|
||||||
"Application": "Program",
|
"Application": "Program",
|
||||||
"AppDeviceValues": "App: {0}, Toestel: {1}",
|
"AppDeviceValues": "App: {0}, Toestel: {1}",
|
||||||
"VersionNumber": "Weergawe {0}",
|
"VersionNumber": "Weergawe {0}",
|
||||||
@ -85,7 +85,6 @@
|
|||||||
"ItemAddedWithName": "{0} is in die versameling",
|
"ItemAddedWithName": "{0} is in die versameling",
|
||||||
"HomeVideos": "Tuis opnames",
|
"HomeVideos": "Tuis opnames",
|
||||||
"HeaderRecordingGroups": "Groep Opnames",
|
"HeaderRecordingGroups": "Groep Opnames",
|
||||||
"HeaderCameraUploads": "Kamera Oplaai",
|
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"FailedLoginAttemptWithUserName": "Mislukte aansluiting van {0}",
|
"FailedLoginAttemptWithUserName": "Mislukte aansluiting van {0}",
|
||||||
"ChapterNameValue": "Hoofstuk",
|
"ChapterNameValue": "Hoofstuk",
|
||||||
@ -95,5 +94,23 @@
|
|||||||
"TasksChannelsCategory": "Internet kanale",
|
"TasksChannelsCategory": "Internet kanale",
|
||||||
"TasksApplicationCategory": "aansoek",
|
"TasksApplicationCategory": "aansoek",
|
||||||
"TasksLibraryCategory": "biblioteek",
|
"TasksLibraryCategory": "biblioteek",
|
||||||
"TasksMaintenanceCategory": "onderhoud"
|
"TasksMaintenanceCategory": "onderhoud",
|
||||||
|
"TaskCleanCacheDescription": "Vee kasregister lêers uit wat nie meer deur die stelsel benodig word nie.",
|
||||||
|
"TaskCleanCache": "Reinig Kasgeheue Lêergids",
|
||||||
|
"TaskDownloadMissingSubtitlesDescription": "Soek aanlyn vir vermiste onderskrifte gebasseer op metadata verstellings.",
|
||||||
|
"TaskDownloadMissingSubtitles": "Laai vermiste onderskrifte af",
|
||||||
|
"TaskRefreshChannelsDescription": "Vervris internet kanaal inligting.",
|
||||||
|
"TaskRefreshChannels": "Vervris Kanale",
|
||||||
|
"TaskCleanTranscodeDescription": "Vee transkodering lêers uit wat ouer is as een dag.",
|
||||||
|
"TaskCleanTranscode": "Reinig Transkoderings Leêrbinder",
|
||||||
|
"TaskUpdatePluginsDescription": "Laai opgedateerde inprop-sagteware af en installeer inprop-sagteware wat verstel is om outomaties op te dateer.",
|
||||||
|
"TaskUpdatePlugins": "Dateer Inprop-Sagteware Op",
|
||||||
|
"TaskRefreshPeopleDescription": "Vervris metadata oor akteurs en regisseurs in u media versameling.",
|
||||||
|
"TaskRefreshPeople": "Vervris Mense",
|
||||||
|
"TaskCleanLogsDescription": "Vee loglêers wat ouer as {0} dae is uit.",
|
||||||
|
"TaskCleanLogs": "Reinig Loglêer Lêervouer",
|
||||||
|
"TaskRefreshLibraryDescription": "Skandeer u media versameling vir nuwe lêers en verfris metadata.",
|
||||||
|
"TaskRefreshLibrary": "Skandeer Media Versameling",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Maak kleinkiekeis (fotos) vir films wat hoofstukke het.",
|
||||||
|
"TaskRefreshChapterImages": "Verkry Hoofstuk Beelde"
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "المجلدات",
|
"Folders": "المجلدات",
|
||||||
"Genres": "التضنيفات",
|
"Genres": "التضنيفات",
|
||||||
"HeaderAlbumArtists": "فناني الألبومات",
|
"HeaderAlbumArtists": "فناني الألبومات",
|
||||||
"HeaderCameraUploads": "تحميلات الكاميرا",
|
|
||||||
"HeaderContinueWatching": "استئناف",
|
"HeaderContinueWatching": "استئناف",
|
||||||
"HeaderFavoriteAlbums": "الألبومات المفضلة",
|
"HeaderFavoriteAlbums": "الألبومات المفضلة",
|
||||||
"HeaderFavoriteArtists": "الفنانون المفضلون",
|
"HeaderFavoriteArtists": "الفنانون المفضلون",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Папки",
|
"Folders": "Папки",
|
||||||
"Genres": "Жанрове",
|
"Genres": "Жанрове",
|
||||||
"HeaderAlbumArtists": "Изпълнители на албуми",
|
"HeaderAlbumArtists": "Изпълнители на албуми",
|
||||||
"HeaderCameraUploads": "Качени от камера",
|
|
||||||
"HeaderContinueWatching": "Продължаване на гледането",
|
"HeaderContinueWatching": "Продължаване на гледането",
|
||||||
"HeaderFavoriteAlbums": "Любими албуми",
|
"HeaderFavoriteAlbums": "Любими албуми",
|
||||||
"HeaderFavoriteArtists": "Любими изпълнители",
|
"HeaderFavoriteArtists": "Любими изпълнители",
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
"HeaderFavoriteArtists": "প্রিয় শিল্পীরা",
|
"HeaderFavoriteArtists": "প্রিয় শিল্পীরা",
|
||||||
"HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
|
"HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
|
||||||
"HeaderContinueWatching": "দেখতে থাকুন",
|
"HeaderContinueWatching": "দেখতে থাকুন",
|
||||||
"HeaderCameraUploads": "ক্যামেরার আপলোড সমূহ",
|
|
||||||
"HeaderAlbumArtists": "এলবাম শিল্পী",
|
"HeaderAlbumArtists": "এলবাম শিল্পী",
|
||||||
"Genres": "জেনার",
|
"Genres": "জেনার",
|
||||||
"Folders": "ফোল্ডারগুলো",
|
"Folders": "ফোল্ডারগুলো",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Carpetes",
|
"Folders": "Carpetes",
|
||||||
"Genres": "Gèneres",
|
"Genres": "Gèneres",
|
||||||
"HeaderAlbumArtists": "Artistes del Àlbum",
|
"HeaderAlbumArtists": "Artistes del Àlbum",
|
||||||
"HeaderCameraUploads": "Pujades de Càmera",
|
|
||||||
"HeaderContinueWatching": "Continua Veient",
|
"HeaderContinueWatching": "Continua Veient",
|
||||||
"HeaderFavoriteAlbums": "Àlbums Preferits",
|
"HeaderFavoriteAlbums": "Àlbums Preferits",
|
||||||
"HeaderFavoriteArtists": "Artistes Preferits",
|
"HeaderFavoriteArtists": "Artistes Preferits",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Složky",
|
"Folders": "Složky",
|
||||||
"Genres": "Žánry",
|
"Genres": "Žánry",
|
||||||
"HeaderAlbumArtists": "Umělci alba",
|
"HeaderAlbumArtists": "Umělci alba",
|
||||||
"HeaderCameraUploads": "Nahrané fotografie",
|
|
||||||
"HeaderContinueWatching": "Pokračovat ve sledování",
|
"HeaderContinueWatching": "Pokračovat ve sledování",
|
||||||
"HeaderFavoriteAlbums": "Oblíbená alba",
|
"HeaderFavoriteAlbums": "Oblíbená alba",
|
||||||
"HeaderFavoriteArtists": "Oblíbení interpreti",
|
"HeaderFavoriteArtists": "Oblíbení interpreti",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Mapper",
|
"Folders": "Mapper",
|
||||||
"Genres": "Genrer",
|
"Genres": "Genrer",
|
||||||
"HeaderAlbumArtists": "Albumkunstnere",
|
"HeaderAlbumArtists": "Albumkunstnere",
|
||||||
"HeaderCameraUploads": "Kamera Uploads",
|
|
||||||
"HeaderContinueWatching": "Fortsæt Afspilning",
|
"HeaderContinueWatching": "Fortsæt Afspilning",
|
||||||
"HeaderFavoriteAlbums": "Favoritalbummer",
|
"HeaderFavoriteAlbums": "Favoritalbummer",
|
||||||
"HeaderFavoriteArtists": "Favoritkunstnere",
|
"HeaderFavoriteArtists": "Favoritkunstnere",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Verzeichnisse",
|
"Folders": "Verzeichnisse",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Album-Interpreten",
|
"HeaderAlbumArtists": "Album-Interpreten",
|
||||||
"HeaderCameraUploads": "Kamera-Uploads",
|
|
||||||
"HeaderContinueWatching": "Fortsetzen",
|
"HeaderContinueWatching": "Fortsetzen",
|
||||||
"HeaderFavoriteAlbums": "Lieblingsalben",
|
"HeaderFavoriteAlbums": "Lieblingsalben",
|
||||||
"HeaderFavoriteArtists": "Lieblings-Interpreten",
|
"HeaderFavoriteArtists": "Lieblings-Interpreten",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Φάκελοι",
|
"Folders": "Φάκελοι",
|
||||||
"Genres": "Είδη",
|
"Genres": "Είδη",
|
||||||
"HeaderAlbumArtists": "Καλλιτέχνες του Άλμπουμ",
|
"HeaderAlbumArtists": "Καλλιτέχνες του Άλμπουμ",
|
||||||
"HeaderCameraUploads": "Μεταφορτώσεις Κάμερας",
|
|
||||||
"HeaderContinueWatching": "Συνεχίστε την παρακολούθηση",
|
"HeaderContinueWatching": "Συνεχίστε την παρακολούθηση",
|
||||||
"HeaderFavoriteAlbums": "Αγαπημένα Άλμπουμ",
|
"HeaderFavoriteAlbums": "Αγαπημένα Άλμπουμ",
|
||||||
"HeaderFavoriteArtists": "Αγαπημένοι Καλλιτέχνες",
|
"HeaderFavoriteArtists": "Αγαπημένοι Καλλιτέχνες",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Folders",
|
"Folders": "Folders",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Album Artists",
|
"HeaderAlbumArtists": "Album Artists",
|
||||||
"HeaderCameraUploads": "Camera Uploads",
|
|
||||||
"HeaderContinueWatching": "Continue Watching",
|
"HeaderContinueWatching": "Continue Watching",
|
||||||
"HeaderFavoriteAlbums": "Favourite Albums",
|
"HeaderFavoriteAlbums": "Favourite Albums",
|
||||||
"HeaderFavoriteArtists": "Favourite Artists",
|
"HeaderFavoriteArtists": "Favourite Artists",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Folders",
|
"Folders": "Folders",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Album Artists",
|
"HeaderAlbumArtists": "Album Artists",
|
||||||
"HeaderCameraUploads": "Camera Uploads",
|
|
||||||
"HeaderContinueWatching": "Continue Watching",
|
"HeaderContinueWatching": "Continue Watching",
|
||||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||||
"HeaderFavoriteArtists": "Favorite Artists",
|
"HeaderFavoriteArtists": "Favorite Artists",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Carpetas",
|
"Folders": "Carpetas",
|
||||||
"Genres": "Géneros",
|
"Genres": "Géneros",
|
||||||
"HeaderAlbumArtists": "Artistas de álbum",
|
"HeaderAlbumArtists": "Artistas de álbum",
|
||||||
"HeaderCameraUploads": "Subidas de cámara",
|
|
||||||
"HeaderContinueWatching": "Seguir viendo",
|
"HeaderContinueWatching": "Seguir viendo",
|
||||||
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
||||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Carpetas",
|
"Folders": "Carpetas",
|
||||||
"Genres": "Géneros",
|
"Genres": "Géneros",
|
||||||
"HeaderAlbumArtists": "Artistas del álbum",
|
"HeaderAlbumArtists": "Artistas del álbum",
|
||||||
"HeaderCameraUploads": "Subidas desde la cámara",
|
|
||||||
"HeaderContinueWatching": "Continuar viendo",
|
"HeaderContinueWatching": "Continuar viendo",
|
||||||
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
||||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Carpetas",
|
"Folders": "Carpetas",
|
||||||
"Genres": "Géneros",
|
"Genres": "Géneros",
|
||||||
"HeaderAlbumArtists": "Artistas del álbum",
|
"HeaderAlbumArtists": "Artistas del álbum",
|
||||||
"HeaderCameraUploads": "Subidas desde la cámara",
|
|
||||||
"HeaderContinueWatching": "Continuar viendo",
|
"HeaderContinueWatching": "Continuar viendo",
|
||||||
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
||||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||||
|
@ -105,7 +105,6 @@
|
|||||||
"Inherit": "Heredar",
|
"Inherit": "Heredar",
|
||||||
"HomeVideos": "Videos caseros",
|
"HomeVideos": "Videos caseros",
|
||||||
"HeaderRecordingGroups": "Grupos de grabación",
|
"HeaderRecordingGroups": "Grupos de grabación",
|
||||||
"HeaderCameraUploads": "Subidas desde la cámara",
|
|
||||||
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión desde {0}",
|
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión desde {0}",
|
||||||
"DeviceOnlineWithName": "{0} está conectado",
|
"DeviceOnlineWithName": "{0} está conectado",
|
||||||
"DeviceOfflineWithName": "{0} se ha desconectado",
|
"DeviceOfflineWithName": "{0} se ha desconectado",
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
"Application": "Aplicación",
|
"Application": "Aplicación",
|
||||||
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
|
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
|
||||||
"HeaderContinueWatching": "Continuar Viendo",
|
"HeaderContinueWatching": "Continuar Viendo",
|
||||||
"HeaderCameraUploads": "Subidas de Cámara",
|
|
||||||
"HeaderAlbumArtists": "Artistas del Álbum",
|
"HeaderAlbumArtists": "Artistas del Álbum",
|
||||||
"Genres": "Géneros",
|
"Genres": "Géneros",
|
||||||
"Folders": "Carpetas",
|
"Folders": "Carpetas",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "پوشهها",
|
"Folders": "پوشهها",
|
||||||
"Genres": "ژانرها",
|
"Genres": "ژانرها",
|
||||||
"HeaderAlbumArtists": "هنرمندان آلبوم",
|
"HeaderAlbumArtists": "هنرمندان آلبوم",
|
||||||
"HeaderCameraUploads": "آپلودهای دوربین",
|
|
||||||
"HeaderContinueWatching": "ادامه تماشا",
|
"HeaderContinueWatching": "ادامه تماشا",
|
||||||
"HeaderFavoriteAlbums": "آلبومهای مورد علاقه",
|
"HeaderFavoriteAlbums": "آلبومهای مورد علاقه",
|
||||||
"HeaderFavoriteArtists": "هنرمندان مورد علاقه",
|
"HeaderFavoriteArtists": "هنرمندان مورد علاقه",
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
"HeaderFavoriteSongs": "Lempikappaleet",
|
"HeaderFavoriteSongs": "Lempikappaleet",
|
||||||
"HeaderFavoriteShows": "Lempisarjat",
|
"HeaderFavoriteShows": "Lempisarjat",
|
||||||
"HeaderFavoriteEpisodes": "Lempijaksot",
|
"HeaderFavoriteEpisodes": "Lempijaksot",
|
||||||
"HeaderCameraUploads": "Kamerasta Lähetetyt",
|
|
||||||
"HeaderFavoriteArtists": "Lempiartistit",
|
"HeaderFavoriteArtists": "Lempiartistit",
|
||||||
"HeaderFavoriteAlbums": "Lempialbumit",
|
"HeaderFavoriteAlbums": "Lempialbumit",
|
||||||
"HeaderContinueWatching": "Jatka katsomista",
|
"HeaderContinueWatching": "Jatka katsomista",
|
||||||
|
@ -73,7 +73,6 @@
|
|||||||
"HeaderFavoriteArtists": "Paboritong Artista",
|
"HeaderFavoriteArtists": "Paboritong Artista",
|
||||||
"HeaderFavoriteAlbums": "Paboritong Albums",
|
"HeaderFavoriteAlbums": "Paboritong Albums",
|
||||||
"HeaderContinueWatching": "Ituloy Manood",
|
"HeaderContinueWatching": "Ituloy Manood",
|
||||||
"HeaderCameraUploads": "Camera Uploads",
|
|
||||||
"HeaderAlbumArtists": "Artista ng Album",
|
"HeaderAlbumArtists": "Artista ng Album",
|
||||||
"Genres": "Kategorya",
|
"Genres": "Kategorya",
|
||||||
"Folders": "Folders",
|
"Folders": "Folders",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Dossiers",
|
"Folders": "Dossiers",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Artistes de l'album",
|
"HeaderAlbumArtists": "Artistes de l'album",
|
||||||
"HeaderCameraUploads": "Photos transférées",
|
|
||||||
"HeaderContinueWatching": "Continuer à regarder",
|
"HeaderContinueWatching": "Continuer à regarder",
|
||||||
"HeaderFavoriteAlbums": "Albums favoris",
|
"HeaderFavoriteAlbums": "Albums favoris",
|
||||||
"HeaderFavoriteArtists": "Artistes favoris",
|
"HeaderFavoriteArtists": "Artistes favoris",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Dossiers",
|
"Folders": "Dossiers",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Artistes",
|
"HeaderAlbumArtists": "Artistes",
|
||||||
"HeaderCameraUploads": "Photos transférées",
|
|
||||||
"HeaderContinueWatching": "Continuer à regarder",
|
"HeaderContinueWatching": "Continuer à regarder",
|
||||||
"HeaderFavoriteAlbums": "Albums favoris",
|
"HeaderFavoriteAlbums": "Albums favoris",
|
||||||
"HeaderFavoriteArtists": "Artistes préférés",
|
"HeaderFavoriteArtists": "Artistes préférés",
|
||||||
@ -107,7 +106,7 @@
|
|||||||
"TaskCleanLogsDescription": "Supprime les journaux de plus de {0} jours.",
|
"TaskCleanLogsDescription": "Supprime les journaux de plus de {0} jours.",
|
||||||
"TaskCleanLogs": "Nettoyer le répertoire des journaux",
|
"TaskCleanLogs": "Nettoyer le répertoire des journaux",
|
||||||
"TaskRefreshLibraryDescription": "Scanne toute les bibliothèques pour trouver les nouveaux fichiers et rafraîchit les métadonnées.",
|
"TaskRefreshLibraryDescription": "Scanne toute les bibliothèques pour trouver les nouveaux fichiers et rafraîchit les métadonnées.",
|
||||||
"TaskRefreshLibrary": "Scanner toute les Bibliothèques",
|
"TaskRefreshLibrary": "Scanner toutes les Bibliothèques",
|
||||||
"TaskRefreshChapterImagesDescription": "Crée des images de miniature pour les vidéos ayant des chapitres.",
|
"TaskRefreshChapterImagesDescription": "Crée des images de miniature pour les vidéos ayant des chapitres.",
|
||||||
"TaskRefreshChapterImages": "Extraire les images de chapitre",
|
"TaskRefreshChapterImages": "Extraire les images de chapitre",
|
||||||
"TaskCleanCacheDescription": "Supprime les fichiers de cache dont le système n'a plus besoin.",
|
"TaskCleanCacheDescription": "Supprime les fichiers de cache dont le système n'a plus besoin.",
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
{
|
{
|
||||||
"Albums": "Álbumes"
|
"Albums": "Álbumes",
|
||||||
|
"Collections": "Colecións",
|
||||||
|
"ChapterNameValue": "Capítulos {0}",
|
||||||
|
"Channels": "Canles",
|
||||||
|
"CameraImageUploadedFrom": "Cargouse unha nova imaxe da cámara desde {0}",
|
||||||
|
"Books": "Libros",
|
||||||
|
"AuthenticationSucceededWithUserName": "{0} autenticouse correctamente",
|
||||||
|
"Artists": "Artistas",
|
||||||
|
"Application": "Aplicativo"
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Ordner",
|
"Folders": "Ordner",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Album-Künstler",
|
"HeaderAlbumArtists": "Album-Künstler",
|
||||||
"HeaderCameraUploads": "Kamera-Uploads",
|
|
||||||
"HeaderContinueWatching": "weiter schauen",
|
"HeaderContinueWatching": "weiter schauen",
|
||||||
"HeaderFavoriteAlbums": "Lieblingsalben",
|
"HeaderFavoriteAlbums": "Lieblingsalben",
|
||||||
"HeaderFavoriteArtists": "Lieblings-Künstler",
|
"HeaderFavoriteArtists": "Lieblings-Künstler",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "תיקיות",
|
"Folders": "תיקיות",
|
||||||
"Genres": "ז'אנרים",
|
"Genres": "ז'אנרים",
|
||||||
"HeaderAlbumArtists": "אמני האלבום",
|
"HeaderAlbumArtists": "אמני האלבום",
|
||||||
"HeaderCameraUploads": "העלאות ממצלמה",
|
|
||||||
"HeaderContinueWatching": "המשך לצפות",
|
"HeaderContinueWatching": "המשך לצפות",
|
||||||
"HeaderFavoriteAlbums": "אלבומים מועדפים",
|
"HeaderFavoriteAlbums": "אלבומים מועדפים",
|
||||||
"HeaderFavoriteArtists": "אמנים מועדפים",
|
"HeaderFavoriteArtists": "אמנים מועדפים",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Mape",
|
"Folders": "Mape",
|
||||||
"Genres": "Žanrovi",
|
"Genres": "Žanrovi",
|
||||||
"HeaderAlbumArtists": "Izvođači na albumu",
|
"HeaderAlbumArtists": "Izvođači na albumu",
|
||||||
"HeaderCameraUploads": "Uvoz sa kamere",
|
|
||||||
"HeaderContinueWatching": "Nastavi gledati",
|
"HeaderContinueWatching": "Nastavi gledati",
|
||||||
"HeaderFavoriteAlbums": "Omiljeni albumi",
|
"HeaderFavoriteAlbums": "Omiljeni albumi",
|
||||||
"HeaderFavoriteArtists": "Omiljeni izvođači",
|
"HeaderFavoriteArtists": "Omiljeni izvođači",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Könyvtárak",
|
"Folders": "Könyvtárak",
|
||||||
"Genres": "Műfajok",
|
"Genres": "Műfajok",
|
||||||
"HeaderAlbumArtists": "Album előadók",
|
"HeaderAlbumArtists": "Album előadók",
|
||||||
"HeaderCameraUploads": "Kamera feltöltések",
|
|
||||||
"HeaderContinueWatching": "Megtekintés folytatása",
|
"HeaderContinueWatching": "Megtekintés folytatása",
|
||||||
"HeaderFavoriteAlbums": "Kedvenc albumok",
|
"HeaderFavoriteAlbums": "Kedvenc albumok",
|
||||||
"HeaderFavoriteArtists": "Kedvenc előadók",
|
"HeaderFavoriteArtists": "Kedvenc előadók",
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
"HeaderFavoriteArtists": "Artis Favorit",
|
"HeaderFavoriteArtists": "Artis Favorit",
|
||||||
"HeaderFavoriteAlbums": "Album Favorit",
|
"HeaderFavoriteAlbums": "Album Favorit",
|
||||||
"HeaderContinueWatching": "Lanjut Menonton",
|
"HeaderContinueWatching": "Lanjut Menonton",
|
||||||
"HeaderCameraUploads": "Unggahan Kamera",
|
|
||||||
"HeaderAlbumArtists": "Album Artis",
|
"HeaderAlbumArtists": "Album Artis",
|
||||||
"Genres": "Aliran",
|
"Genres": "Aliran",
|
||||||
"Folders": "Folder",
|
"Folders": "Folder",
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
"HeaderFavoriteArtists": "Uppáhalds Listamenn",
|
"HeaderFavoriteArtists": "Uppáhalds Listamenn",
|
||||||
"HeaderFavoriteAlbums": "Uppáhalds Plötur",
|
"HeaderFavoriteAlbums": "Uppáhalds Plötur",
|
||||||
"HeaderContinueWatching": "Halda áfram að horfa",
|
"HeaderContinueWatching": "Halda áfram að horfa",
|
||||||
"HeaderCameraUploads": "Myndavéla upphal",
|
|
||||||
"HeaderAlbumArtists": "Höfundur plötu",
|
"HeaderAlbumArtists": "Höfundur plötu",
|
||||||
"Genres": "Tegundir",
|
"Genres": "Tegundir",
|
||||||
"Folders": "Möppur",
|
"Folders": "Möppur",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Cartelle",
|
"Folders": "Cartelle",
|
||||||
"Genres": "Generi",
|
"Genres": "Generi",
|
||||||
"HeaderAlbumArtists": "Artisti degli Album",
|
"HeaderAlbumArtists": "Artisti degli Album",
|
||||||
"HeaderCameraUploads": "Caricamenti Fotocamera",
|
|
||||||
"HeaderContinueWatching": "Continua a guardare",
|
"HeaderContinueWatching": "Continua a guardare",
|
||||||
"HeaderFavoriteAlbums": "Album Preferiti",
|
"HeaderFavoriteAlbums": "Album Preferiti",
|
||||||
"HeaderFavoriteArtists": "Artisti Preferiti",
|
"HeaderFavoriteArtists": "Artisti Preferiti",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "フォルダー",
|
"Folders": "フォルダー",
|
||||||
"Genres": "ジャンル",
|
"Genres": "ジャンル",
|
||||||
"HeaderAlbumArtists": "アルバムアーティスト",
|
"HeaderAlbumArtists": "アルバムアーティスト",
|
||||||
"HeaderCameraUploads": "カメラアップロード",
|
|
||||||
"HeaderContinueWatching": "視聴を続ける",
|
"HeaderContinueWatching": "視聴を続ける",
|
||||||
"HeaderFavoriteAlbums": "お気に入りのアルバム",
|
"HeaderFavoriteAlbums": "お気に入りのアルバム",
|
||||||
"HeaderFavoriteArtists": "お気に入りのアーティスト",
|
"HeaderFavoriteArtists": "お気に入りのアーティスト",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Qaltalar",
|
"Folders": "Qaltalar",
|
||||||
"Genres": "Janrlar",
|
"Genres": "Janrlar",
|
||||||
"HeaderAlbumArtists": "Álbom oryndaýshylary",
|
"HeaderAlbumArtists": "Álbom oryndaýshylary",
|
||||||
"HeaderCameraUploads": "Kameradan júktelgender",
|
|
||||||
"HeaderContinueWatching": "Qaraýdy jalǵastyrý",
|
"HeaderContinueWatching": "Qaraýdy jalǵastyrý",
|
||||||
"HeaderFavoriteAlbums": "Tańdaýly álbomdar",
|
"HeaderFavoriteAlbums": "Tańdaýly álbomdar",
|
||||||
"HeaderFavoriteArtists": "Tańdaýly oryndaýshylar",
|
"HeaderFavoriteArtists": "Tańdaýly oryndaýshylar",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "폴더",
|
"Folders": "폴더",
|
||||||
"Genres": "장르",
|
"Genres": "장르",
|
||||||
"HeaderAlbumArtists": "앨범 아티스트",
|
"HeaderAlbumArtists": "앨범 아티스트",
|
||||||
"HeaderCameraUploads": "카메라 업로드",
|
|
||||||
"HeaderContinueWatching": "계속 시청하기",
|
"HeaderContinueWatching": "계속 시청하기",
|
||||||
"HeaderFavoriteAlbums": "즐겨찾는 앨범",
|
"HeaderFavoriteAlbums": "즐겨찾는 앨범",
|
||||||
"HeaderFavoriteArtists": "즐겨찾는 아티스트",
|
"HeaderFavoriteArtists": "즐겨찾는 아티스트",
|
||||||
@ -84,8 +83,8 @@
|
|||||||
"UserDeletedWithName": "사용자 {0} 삭제됨",
|
"UserDeletedWithName": "사용자 {0} 삭제됨",
|
||||||
"UserDownloadingItemWithValues": "{0}이(가) {1}을 다운로드 중입니다",
|
"UserDownloadingItemWithValues": "{0}이(가) {1}을 다운로드 중입니다",
|
||||||
"UserLockedOutWithName": "유저 {0} 은(는) 잠금처리 되었습니다",
|
"UserLockedOutWithName": "유저 {0} 은(는) 잠금처리 되었습니다",
|
||||||
"UserOfflineFromDevice": "{1}로부터 {0}의 연결이 끊겼습니다",
|
"UserOfflineFromDevice": "{1}에서 {0}의 연결이 끊킴",
|
||||||
"UserOnlineFromDevice": "{0}은 {1}에서 온라인 상태입니다",
|
"UserOnlineFromDevice": "{0}이 {1}으로 접속",
|
||||||
"UserPasswordChangedWithName": "사용자 {0}의 비밀번호가 변경되었습니다",
|
"UserPasswordChangedWithName": "사용자 {0}의 비밀번호가 변경되었습니다",
|
||||||
"UserPolicyUpdatedWithName": "{0}의 사용자 정책이 업데이트되었습니다",
|
"UserPolicyUpdatedWithName": "{0}의 사용자 정책이 업데이트되었습니다",
|
||||||
"UserStartedPlayingItemWithValues": "{2}에서 {0}이 {1} 재생 중",
|
"UserStartedPlayingItemWithValues": "{2}에서 {0}이 {1} 재생 중",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Katalogai",
|
"Folders": "Katalogai",
|
||||||
"Genres": "Žanrai",
|
"Genres": "Žanrai",
|
||||||
"HeaderAlbumArtists": "Albumo atlikėjai",
|
"HeaderAlbumArtists": "Albumo atlikėjai",
|
||||||
"HeaderCameraUploads": "Kameros",
|
|
||||||
"HeaderContinueWatching": "Žiūrėti toliau",
|
"HeaderContinueWatching": "Žiūrėti toliau",
|
||||||
"HeaderFavoriteAlbums": "Mėgstami Albumai",
|
"HeaderFavoriteAlbums": "Mėgstami Albumai",
|
||||||
"HeaderFavoriteArtists": "Mėgstami Atlikėjai",
|
"HeaderFavoriteArtists": "Mėgstami Atlikėjai",
|
||||||
|
@ -72,7 +72,6 @@
|
|||||||
"ItemAddedWithName": "{0} tika pievienots bibliotēkai",
|
"ItemAddedWithName": "{0} tika pievienots bibliotēkai",
|
||||||
"HeaderLiveTV": "Tiešraides TV",
|
"HeaderLiveTV": "Tiešraides TV",
|
||||||
"HeaderContinueWatching": "Turpināt Skatīšanos",
|
"HeaderContinueWatching": "Turpināt Skatīšanos",
|
||||||
"HeaderCameraUploads": "Kameras augšupielādes",
|
|
||||||
"HeaderAlbumArtists": "Albumu Izpildītāji",
|
"HeaderAlbumArtists": "Albumu Izpildītāji",
|
||||||
"Genres": "Žanri",
|
"Genres": "Žanri",
|
||||||
"Folders": "Mapes",
|
"Folders": "Mapes",
|
||||||
|
@ -51,7 +51,6 @@
|
|||||||
"HeaderFavoriteArtists": "Омилени Изведувачи",
|
"HeaderFavoriteArtists": "Омилени Изведувачи",
|
||||||
"HeaderFavoriteAlbums": "Омилени Албуми",
|
"HeaderFavoriteAlbums": "Омилени Албуми",
|
||||||
"HeaderContinueWatching": "Продолжи со гледање",
|
"HeaderContinueWatching": "Продолжи со гледање",
|
||||||
"HeaderCameraUploads": "Поставувања од камера",
|
|
||||||
"HeaderAlbumArtists": "Изведувачи од Албуми",
|
"HeaderAlbumArtists": "Изведувачи од Албуми",
|
||||||
"Genres": "Жанрови",
|
"Genres": "Жанрови",
|
||||||
"Folders": "Папки",
|
"Folders": "Папки",
|
||||||
|
@ -54,7 +54,6 @@
|
|||||||
"ItemAddedWithName": "{0} हे संग्रहालयात जोडले गेले",
|
"ItemAddedWithName": "{0} हे संग्रहालयात जोडले गेले",
|
||||||
"HomeVideos": "घरचे व्हिडीयो",
|
"HomeVideos": "घरचे व्हिडीयो",
|
||||||
"HeaderRecordingGroups": "रेकॉर्डिंग गट",
|
"HeaderRecordingGroups": "रेकॉर्डिंग गट",
|
||||||
"HeaderCameraUploads": "कॅमेरा अपलोड",
|
|
||||||
"CameraImageUploadedFrom": "एक नवीन कॅमेरा चित्र {0} येथून अपलोड केले आहे",
|
"CameraImageUploadedFrom": "एक नवीन कॅमेरा चित्र {0} येथून अपलोड केले आहे",
|
||||||
"Application": "अॅप्लिकेशन",
|
"Application": "अॅप्लिकेशन",
|
||||||
"AppDeviceValues": "अॅप: {0}, यंत्र: {1}",
|
"AppDeviceValues": "अॅप: {0}, यंत्र: {1}",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Fail-fail",
|
"Folders": "Fail-fail",
|
||||||
"Genres": "Genre-genre",
|
"Genres": "Genre-genre",
|
||||||
"HeaderAlbumArtists": "Album Artis-artis",
|
"HeaderAlbumArtists": "Album Artis-artis",
|
||||||
"HeaderCameraUploads": "Muatnaik Kamera",
|
|
||||||
"HeaderContinueWatching": "Terus Menonton",
|
"HeaderContinueWatching": "Terus Menonton",
|
||||||
"HeaderFavoriteAlbums": "Album-album Kegemaran",
|
"HeaderFavoriteAlbums": "Album-album Kegemaran",
|
||||||
"HeaderFavoriteArtists": "Artis-artis Kegemaran",
|
"HeaderFavoriteArtists": "Artis-artis Kegemaran",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Mapper",
|
"Folders": "Mapper",
|
||||||
"Genres": "Sjangre",
|
"Genres": "Sjangre",
|
||||||
"HeaderAlbumArtists": "Albumartister",
|
"HeaderAlbumArtists": "Albumartister",
|
||||||
"HeaderCameraUploads": "Kameraopplastinger",
|
|
||||||
"HeaderContinueWatching": "Fortsett å se",
|
"HeaderContinueWatching": "Fortsett å se",
|
||||||
"HeaderFavoriteAlbums": "Favorittalbum",
|
"HeaderFavoriteAlbums": "Favorittalbum",
|
||||||
"HeaderFavoriteArtists": "Favorittartister",
|
"HeaderFavoriteArtists": "Favorittartister",
|
||||||
@ -50,7 +49,7 @@
|
|||||||
"NotificationOptionAudioPlayback": "Lydavspilling startet",
|
"NotificationOptionAudioPlayback": "Lydavspilling startet",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Lydavspilling stoppet",
|
"NotificationOptionAudioPlaybackStopped": "Lydavspilling stoppet",
|
||||||
"NotificationOptionCameraImageUploaded": "Kamerabilde lastet opp",
|
"NotificationOptionCameraImageUploaded": "Kamerabilde lastet opp",
|
||||||
"NotificationOptionInstallationFailed": "Installasjonsfeil",
|
"NotificationOptionInstallationFailed": "Installasjonen feilet",
|
||||||
"NotificationOptionNewLibraryContent": "Nytt innhold lagt til",
|
"NotificationOptionNewLibraryContent": "Nytt innhold lagt til",
|
||||||
"NotificationOptionPluginError": "Pluginfeil",
|
"NotificationOptionPluginError": "Pluginfeil",
|
||||||
"NotificationOptionPluginInstalled": "Plugin installert",
|
"NotificationOptionPluginInstalled": "Plugin installert",
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
"HeaderFavoriteArtists": "मनपर्ने कलाकारहरू",
|
"HeaderFavoriteArtists": "मनपर्ने कलाकारहरू",
|
||||||
"HeaderFavoriteAlbums": "मनपर्ने एल्बमहरू",
|
"HeaderFavoriteAlbums": "मनपर्ने एल्बमहरू",
|
||||||
"HeaderContinueWatching": "हेर्न जारी राख्नुहोस्",
|
"HeaderContinueWatching": "हेर्न जारी राख्नुहोस्",
|
||||||
"HeaderCameraUploads": "क्यामेरा अपलोडहरू",
|
|
||||||
"HeaderAlbumArtists": "एल्बमका कलाकारहरू",
|
"HeaderAlbumArtists": "एल्बमका कलाकारहरू",
|
||||||
"Genres": "विधाहरू",
|
"Genres": "विधाहरू",
|
||||||
"Folders": "फोल्डरहरू",
|
"Folders": "फोल्डरहरू",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Mappen",
|
"Folders": "Mappen",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Albumartiesten",
|
"HeaderAlbumArtists": "Albumartiesten",
|
||||||
"HeaderCameraUploads": "Camera-uploads",
|
|
||||||
"HeaderContinueWatching": "Kijken hervatten",
|
"HeaderContinueWatching": "Kijken hervatten",
|
||||||
"HeaderFavoriteAlbums": "Favoriete albums",
|
"HeaderFavoriteAlbums": "Favoriete albums",
|
||||||
"HeaderFavoriteArtists": "Favoriete artiesten",
|
"HeaderFavoriteArtists": "Favoriete artiesten",
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
"HeaderFavoriteArtists": "Favoritt Artistar",
|
"HeaderFavoriteArtists": "Favoritt Artistar",
|
||||||
"HeaderFavoriteAlbums": "Favoritt Album",
|
"HeaderFavoriteAlbums": "Favoritt Album",
|
||||||
"HeaderContinueWatching": "Fortsett å sjå",
|
"HeaderContinueWatching": "Fortsett å sjå",
|
||||||
"HeaderCameraUploads": "Kamera Opplastingar",
|
|
||||||
"HeaderAlbumArtists": "Album Artist",
|
"HeaderAlbumArtists": "Album Artist",
|
||||||
"Genres": "Sjangrar",
|
"Genres": "Sjangrar",
|
||||||
"Folders": "Mapper",
|
"Folders": "Mapper",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Foldery",
|
"Folders": "Foldery",
|
||||||
"Genres": "Gatunki",
|
"Genres": "Gatunki",
|
||||||
"HeaderAlbumArtists": "Wykonawcy albumów",
|
"HeaderAlbumArtists": "Wykonawcy albumów",
|
||||||
"HeaderCameraUploads": "Przekazane obrazy",
|
|
||||||
"HeaderContinueWatching": "Kontynuuj odtwarzanie",
|
"HeaderContinueWatching": "Kontynuuj odtwarzanie",
|
||||||
"HeaderFavoriteAlbums": "Ulubione albumy",
|
"HeaderFavoriteAlbums": "Ulubione albumy",
|
||||||
"HeaderFavoriteArtists": "Ulubieni wykonawcy",
|
"HeaderFavoriteArtists": "Ulubieni wykonawcy",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Pastas",
|
"Folders": "Pastas",
|
||||||
"Genres": "Gêneros",
|
"Genres": "Gêneros",
|
||||||
"HeaderAlbumArtists": "Artistas do Álbum",
|
"HeaderAlbumArtists": "Artistas do Álbum",
|
||||||
"HeaderCameraUploads": "Envios da Câmera",
|
|
||||||
"HeaderContinueWatching": "Continuar Assistindo",
|
"HeaderContinueWatching": "Continuar Assistindo",
|
||||||
"HeaderFavoriteAlbums": "Álbuns Favoritos",
|
"HeaderFavoriteAlbums": "Álbuns Favoritos",
|
||||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Pastas",
|
"Folders": "Pastas",
|
||||||
"Genres": "Géneros",
|
"Genres": "Géneros",
|
||||||
"HeaderAlbumArtists": "Artistas do Álbum",
|
"HeaderAlbumArtists": "Artistas do Álbum",
|
||||||
"HeaderCameraUploads": "Envios a partir da câmara",
|
|
||||||
"HeaderContinueWatching": "Continuar a Ver",
|
"HeaderContinueWatching": "Continuar a Ver",
|
||||||
"HeaderFavoriteAlbums": "Álbuns Favoritos",
|
"HeaderFavoriteAlbums": "Álbuns Favoritos",
|
||||||
"HeaderFavoriteArtists": "Artistas Favoritos",
|
"HeaderFavoriteArtists": "Artistas Favoritos",
|
||||||
@ -26,7 +25,7 @@
|
|||||||
"HeaderLiveTV": "TV em Direto",
|
"HeaderLiveTV": "TV em Direto",
|
||||||
"HeaderNextUp": "A Seguir",
|
"HeaderNextUp": "A Seguir",
|
||||||
"HeaderRecordingGroups": "Grupos de Gravação",
|
"HeaderRecordingGroups": "Grupos de Gravação",
|
||||||
"HomeVideos": "Videos caseiros",
|
"HomeVideos": "Vídeos Caseiros",
|
||||||
"Inherit": "Herdar",
|
"Inherit": "Herdar",
|
||||||
"ItemAddedWithName": "{0} foi adicionado à biblioteca",
|
"ItemAddedWithName": "{0} foi adicionado à biblioteca",
|
||||||
"ItemRemovedWithName": "{0} foi removido da biblioteca",
|
"ItemRemovedWithName": "{0} foi removido da biblioteca",
|
||||||
|
@ -83,7 +83,6 @@
|
|||||||
"Playlists": "Listas de Reprodução",
|
"Playlists": "Listas de Reprodução",
|
||||||
"Photos": "Fotografias",
|
"Photos": "Fotografias",
|
||||||
"Movies": "Filmes",
|
"Movies": "Filmes",
|
||||||
"HeaderCameraUploads": "Carregamentos a partir da câmara",
|
|
||||||
"FailedLoginAttemptWithUserName": "Tentativa de ligação falhada a partir de {0}",
|
"FailedLoginAttemptWithUserName": "Tentativa de ligação falhada a partir de {0}",
|
||||||
"DeviceOnlineWithName": "{0} está connectado",
|
"DeviceOnlineWithName": "{0} está connectado",
|
||||||
"DeviceOfflineWithName": "{0} desconectou-se",
|
"DeviceOfflineWithName": "{0} desconectou-se",
|
||||||
|
@ -74,7 +74,6 @@
|
|||||||
"HeaderFavoriteArtists": "Artiști Favoriți",
|
"HeaderFavoriteArtists": "Artiști Favoriți",
|
||||||
"HeaderFavoriteAlbums": "Albume Favorite",
|
"HeaderFavoriteAlbums": "Albume Favorite",
|
||||||
"HeaderContinueWatching": "Vizionează în continuare",
|
"HeaderContinueWatching": "Vizionează în continuare",
|
||||||
"HeaderCameraUploads": "Incărcări Cameră Foto",
|
|
||||||
"HeaderAlbumArtists": "Album Artiști",
|
"HeaderAlbumArtists": "Album Artiști",
|
||||||
"Genres": "Genuri",
|
"Genres": "Genuri",
|
||||||
"Folders": "Dosare",
|
"Folders": "Dosare",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Папки",
|
"Folders": "Папки",
|
||||||
"Genres": "Жанры",
|
"Genres": "Жанры",
|
||||||
"HeaderAlbumArtists": "Исполнители альбома",
|
"HeaderAlbumArtists": "Исполнители альбома",
|
||||||
"HeaderCameraUploads": "Камеры",
|
|
||||||
"HeaderContinueWatching": "Продолжение просмотра",
|
"HeaderContinueWatching": "Продолжение просмотра",
|
||||||
"HeaderFavoriteAlbums": "Избранные альбомы",
|
"HeaderFavoriteAlbums": "Избранные альбомы",
|
||||||
"HeaderFavoriteArtists": "Избранные исполнители",
|
"HeaderFavoriteArtists": "Избранные исполнители",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Priečinky",
|
"Folders": "Priečinky",
|
||||||
"Genres": "Žánre",
|
"Genres": "Žánre",
|
||||||
"HeaderAlbumArtists": "Umelci albumu",
|
"HeaderAlbumArtists": "Umelci albumu",
|
||||||
"HeaderCameraUploads": "Nahrané fotografie",
|
|
||||||
"HeaderContinueWatching": "Pokračovať v pozeraní",
|
"HeaderContinueWatching": "Pokračovať v pozeraní",
|
||||||
"HeaderFavoriteAlbums": "Obľúbené albumy",
|
"HeaderFavoriteAlbums": "Obľúbené albumy",
|
||||||
"HeaderFavoriteArtists": "Obľúbení umelci",
|
"HeaderFavoriteArtists": "Obľúbení umelci",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Mape",
|
"Folders": "Mape",
|
||||||
"Genres": "Zvrsti",
|
"Genres": "Zvrsti",
|
||||||
"HeaderAlbumArtists": "Izvajalci albuma",
|
"HeaderAlbumArtists": "Izvajalci albuma",
|
||||||
"HeaderCameraUploads": "Posnetki kamere",
|
|
||||||
"HeaderContinueWatching": "Nadaljuj gledanje",
|
"HeaderContinueWatching": "Nadaljuj gledanje",
|
||||||
"HeaderFavoriteAlbums": "Priljubljeni albumi",
|
"HeaderFavoriteAlbums": "Priljubljeni albumi",
|
||||||
"HeaderFavoriteArtists": "Priljubljeni izvajalci",
|
"HeaderFavoriteArtists": "Priljubljeni izvajalci",
|
||||||
|
116
Emby.Server.Implementations/Localization/Core/sq.json
Normal file
116
Emby.Server.Implementations/Localization/Core/sq.json
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"MessageApplicationUpdatedTo": "Serveri Jellyfin u përditesua në versionin {0}",
|
||||||
|
"Inherit": "Trashgimi",
|
||||||
|
"TaskDownloadMissingSubtitlesDescription": "Kërkon në internet për titra që mungojnë bazuar tek konfigurimi i metadata-ve.",
|
||||||
|
"TaskDownloadMissingSubtitles": "Shkarko titra që mungojnë",
|
||||||
|
"TaskRefreshChannelsDescription": "Rifreskon informacionin e kanaleve të internetit.",
|
||||||
|
"TaskRefreshChannels": "Rifresko Kanalet",
|
||||||
|
"TaskCleanTranscodeDescription": "Fshin skedarët e transkodimit që janë më të vjetër se një ditë.",
|
||||||
|
"TaskCleanTranscode": "Fshi dosjen e transkodimit",
|
||||||
|
"TaskUpdatePluginsDescription": "Shkarkon dhe instalon përditësimi për plugin që janë konfiguruar të përditësohen automatikisht.",
|
||||||
|
"TaskUpdatePlugins": "Përditëso Plugin",
|
||||||
|
"TaskRefreshPeopleDescription": "Përditëson metadata të aktorëve dhe regjizorëve në librarinë tuaj.",
|
||||||
|
"TaskRefreshPeople": "Rifresko aktorët",
|
||||||
|
"TaskCleanLogsDescription": "Fshin skëdarët log që janë më të vjetër se {0} ditë.",
|
||||||
|
"TaskCleanLogs": "Fshi dosjen Log",
|
||||||
|
"TaskRefreshLibraryDescription": "Skanon librarinë media për skedarë të rinj dhe rifreskon metadata.",
|
||||||
|
"TaskRefreshLibrary": "Skano librarinë media",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Krijon imazh për videot që kanë kapituj.",
|
||||||
|
"TaskRefreshChapterImages": "Ekstrakto Imazhet e Kapitullit",
|
||||||
|
"TaskCleanCacheDescription": "Fshi skedarët e cache-s që nuk i duhen më sistemit.",
|
||||||
|
"TaskCleanCache": "Pastro memorjen cache",
|
||||||
|
"TasksChannelsCategory": "Kanalet nga interneti",
|
||||||
|
"TasksApplicationCategory": "Aplikacioni",
|
||||||
|
"TasksLibraryCategory": "Libraria",
|
||||||
|
"TasksMaintenanceCategory": "Mirëmbajtje",
|
||||||
|
"VersionNumber": "Versioni {0}",
|
||||||
|
"ValueSpecialEpisodeName": "Speciale - {0}",
|
||||||
|
"ValueHasBeenAddedToLibrary": "{0} u shtua tek libraria juaj",
|
||||||
|
"UserStoppedPlayingItemWithValues": "{0} mbaroi së shikuari {1} tek {2}",
|
||||||
|
"UserStartedPlayingItemWithValues": "{0} po shikon {1} tek {2}",
|
||||||
|
"UserPolicyUpdatedWithName": "Politika e përdoruesit u përditësua për {0}",
|
||||||
|
"UserPasswordChangedWithName": "Fjalëkalimi u ndryshua për përdoruesin {0}",
|
||||||
|
"UserOnlineFromDevice": "{0} është në linjë nga {1}",
|
||||||
|
"UserOfflineFromDevice": "{0} u shkëput nga {1}",
|
||||||
|
"UserLockedOutWithName": "Përdoruesi {0} u përjashtua",
|
||||||
|
"UserDownloadingItemWithValues": "{0} po shkarkon {1}",
|
||||||
|
"UserDeletedWithName": "Përdoruesi {0} u fshi",
|
||||||
|
"UserCreatedWithName": "Përdoruesi {0} u krijua",
|
||||||
|
"User": "Përdoruesi",
|
||||||
|
"TvShows": "Seriale TV",
|
||||||
|
"System": "Sistemi",
|
||||||
|
"Sync": "Sinkronizo",
|
||||||
|
"SubtitleDownloadFailureFromForItem": "Titrat deshtuan të shkarkohen nga {0} për {1}",
|
||||||
|
"StartupEmbyServerIsLoading": "Serveri Jellyfin po ngarkohet. Ju lutemi provoni përseri pas pak.",
|
||||||
|
"Songs": "Këngë",
|
||||||
|
"Shows": "Seriale",
|
||||||
|
"ServerNameNeedsToBeRestarted": "{0} duhet të ristartoj",
|
||||||
|
"ScheduledTaskStartedWithName": "{0} filloi",
|
||||||
|
"ScheduledTaskFailedWithName": "{0} dështoi",
|
||||||
|
"ProviderValue": "Ofruesi: {0}",
|
||||||
|
"PluginUpdatedWithName": "{0} u përditësua",
|
||||||
|
"PluginUninstalledWithName": "{0} u çinstalua",
|
||||||
|
"PluginInstalledWithName": "{0} u instalua",
|
||||||
|
"Plugin": "Plugin",
|
||||||
|
"Playlists": "Listat për luajtje",
|
||||||
|
"Photos": "Fotografitë",
|
||||||
|
"NotificationOptionVideoPlaybackStopped": "Luajtja e videos ndaloi",
|
||||||
|
"NotificationOptionVideoPlayback": "Luajtja e videos filloi",
|
||||||
|
"NotificationOptionUserLockedOut": "Përdoruesi u përjashtua",
|
||||||
|
"NotificationOptionTaskFailed": "Ushtrimi i planifikuar dështoi",
|
||||||
|
"NotificationOptionServerRestartRequired": "Kërkohet ristartim i serverit",
|
||||||
|
"NotificationOptionPluginUpdateInstalled": "Përditësimi i plugin u instalua",
|
||||||
|
"NotificationOptionPluginUninstalled": "Plugin u çinstalua",
|
||||||
|
"NotificationOptionPluginInstalled": "Plugin u instalua",
|
||||||
|
"NotificationOptionPluginError": "Plugin dështoi",
|
||||||
|
"NotificationOptionNewLibraryContent": "Një përmbajtje e re u shtua",
|
||||||
|
"NotificationOptionInstallationFailed": "Instalimi dështoi",
|
||||||
|
"NotificationOptionCameraImageUploaded": "Fotoja nga kamera u ngarkua",
|
||||||
|
"NotificationOptionAudioPlaybackStopped": "Luajtja e audios ndaloi",
|
||||||
|
"NotificationOptionAudioPlayback": "Luajtja e audios filloi",
|
||||||
|
"NotificationOptionApplicationUpdateInstalled": "Përditësimi i aplikacionit u instalua",
|
||||||
|
"NotificationOptionApplicationUpdateAvailable": "Një perditësim i aplikacionit është gati",
|
||||||
|
"NewVersionIsAvailable": "Një version i ri i Jellyfin është gati për tu shkarkuar.",
|
||||||
|
"NameSeasonUnknown": "Sezon i panjohur",
|
||||||
|
"NameSeasonNumber": "Sezoni {0}",
|
||||||
|
"NameInstallFailed": "Instalimi i {0} dështoi",
|
||||||
|
"MusicVideos": "Video muzikore",
|
||||||
|
"Music": "Muzikë",
|
||||||
|
"Movies": "Filma",
|
||||||
|
"MixedContent": "Përmbajtje e përzier",
|
||||||
|
"MessageServerConfigurationUpdated": "Konfigurimet e serverit u përditësuan",
|
||||||
|
"MessageNamedServerConfigurationUpdatedWithValue": "Seksioni i konfigurimit të serverit {0} u përditësua",
|
||||||
|
"MessageApplicationUpdated": "Serveri Jellyfin u përditësua",
|
||||||
|
"Latest": "Të fundit",
|
||||||
|
"LabelRunningTimeValue": "Kohëzgjatja: {0}",
|
||||||
|
"LabelIpAddressValue": "Adresa IP: {0}",
|
||||||
|
"ItemRemovedWithName": "{0} u fshi nga libraria",
|
||||||
|
"ItemAddedWithName": "{0} u shtua tek libraria",
|
||||||
|
"HomeVideos": "Video personale",
|
||||||
|
"HeaderRecordingGroups": "Grupet e regjistrimit",
|
||||||
|
"HeaderNextUp": "Në vazhdim",
|
||||||
|
"HeaderLiveTV": "TV Live",
|
||||||
|
"HeaderFavoriteSongs": "Kënget e preferuara",
|
||||||
|
"HeaderFavoriteShows": "Serialet e preferuar",
|
||||||
|
"HeaderFavoriteEpisodes": "Episodet e preferuar",
|
||||||
|
"HeaderFavoriteArtists": "Artistët e preferuar",
|
||||||
|
"HeaderFavoriteAlbums": "Albumet e preferuar",
|
||||||
|
"HeaderContinueWatching": "Vazhdo të shikosh",
|
||||||
|
"HeaderAlbumArtists": "Artistët e albumeve",
|
||||||
|
"Genres": "Zhanre",
|
||||||
|
"Folders": "Dosje",
|
||||||
|
"Favorites": "Të preferuara",
|
||||||
|
"FailedLoginAttemptWithUserName": "Përpjekja për hyrje dështoi nga {0}",
|
||||||
|
"DeviceOnlineWithName": "{0} u lidh",
|
||||||
|
"DeviceOfflineWithName": "{0} u shkëput",
|
||||||
|
"Collections": "Koleksione",
|
||||||
|
"ChapterNameValue": "Kapituj",
|
||||||
|
"Channels": "Kanale",
|
||||||
|
"CameraImageUploadedFrom": "Një foto e re nga kamera u ngarkua nga {0}",
|
||||||
|
"Books": "Libra",
|
||||||
|
"AuthenticationSucceededWithUserName": "{0} u identifikua me sukses",
|
||||||
|
"Artists": "Artistë",
|
||||||
|
"Application": "Aplikacioni",
|
||||||
|
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
|
||||||
|
"Albums": "Albumet"
|
||||||
|
}
|
@ -74,7 +74,6 @@
|
|||||||
"HeaderFavoriteArtists": "Омиљени извођачи",
|
"HeaderFavoriteArtists": "Омиљени извођачи",
|
||||||
"HeaderFavoriteAlbums": "Омиљени албуми",
|
"HeaderFavoriteAlbums": "Омиљени албуми",
|
||||||
"HeaderContinueWatching": "Настави гледање",
|
"HeaderContinueWatching": "Настави гледање",
|
||||||
"HeaderCameraUploads": "Слања са камере",
|
|
||||||
"HeaderAlbumArtists": "Извођачи албума",
|
"HeaderAlbumArtists": "Извођачи албума",
|
||||||
"Genres": "Жанрови",
|
"Genres": "Жанрови",
|
||||||
"Folders": "Фасцикле",
|
"Folders": "Фасцикле",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Mappar",
|
"Folders": "Mappar",
|
||||||
"Genres": "Genrer",
|
"Genres": "Genrer",
|
||||||
"HeaderAlbumArtists": "Albumartister",
|
"HeaderAlbumArtists": "Albumartister",
|
||||||
"HeaderCameraUploads": "Kamerauppladdningar",
|
|
||||||
"HeaderContinueWatching": "Fortsätt kolla",
|
"HeaderContinueWatching": "Fortsätt kolla",
|
||||||
"HeaderFavoriteAlbums": "Favoritalbum",
|
"HeaderFavoriteAlbums": "Favoritalbum",
|
||||||
"HeaderFavoriteArtists": "Favoritartister",
|
"HeaderFavoriteArtists": "Favoritartister",
|
||||||
|
@ -20,13 +20,12 @@
|
|||||||
"MessageApplicationUpdated": "ஜெல்லிஃபின் சேவையகம் புதுப்பிக்கப்பட்டது",
|
"MessageApplicationUpdated": "ஜெல்லிஃபின் சேவையகம் புதுப்பிக்கப்பட்டது",
|
||||||
"Inherit": "மரபுரிமையாகப் பெறு",
|
"Inherit": "மரபுரிமையாகப் பெறு",
|
||||||
"HeaderRecordingGroups": "பதிவு குழுக்கள்",
|
"HeaderRecordingGroups": "பதிவு குழுக்கள்",
|
||||||
"HeaderCameraUploads": "புகைப்பட பதிவேற்றங்கள்",
|
|
||||||
"Folders": "கோப்புறைகள்",
|
"Folders": "கோப்புறைகள்",
|
||||||
"FailedLoginAttemptWithUserName": "{0} இலிருந்து உள்நுழைவு முயற்சி தோல்வியடைந்தது",
|
"FailedLoginAttemptWithUserName": "{0} இலிருந்து உள்நுழைவு முயற்சி தோல்வியடைந்தது",
|
||||||
"DeviceOnlineWithName": "{0} இணைக்கப்பட்டது",
|
"DeviceOnlineWithName": "{0} இணைக்கப்பட்டது",
|
||||||
"DeviceOfflineWithName": "{0} துண்டிக்கப்பட்டது",
|
"DeviceOfflineWithName": "{0} துண்டிக்கப்பட்டது",
|
||||||
"Collections": "தொகுப்புகள்",
|
"Collections": "தொகுப்புகள்",
|
||||||
"CameraImageUploadedFrom": "{0} இலிருந்து புதிய புகைப்படம் பதிவேற்றப்பட்டது",
|
"CameraImageUploadedFrom": "{0} இல் இருந்து புதிய புகைப்படம் பதிவேற்றப்பட்டது",
|
||||||
"AppDeviceValues": "செயலி: {0}, சாதனம்: {1}",
|
"AppDeviceValues": "செயலி: {0}, சாதனம்: {1}",
|
||||||
"TaskDownloadMissingSubtitles": "விடுபட்டுபோன வசன வரிகளைப் பதிவிறக்கு",
|
"TaskDownloadMissingSubtitles": "விடுபட்டுபோன வசன வரிகளைப் பதிவிறக்கு",
|
||||||
"TaskRefreshChannels": "சேனல்களை புதுப்பி",
|
"TaskRefreshChannels": "சேனல்களை புதுப்பி",
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
"NotificationOptionCameraImageUploaded": "อัปโหลดภาพถ่ายแล้ว",
|
"NotificationOptionCameraImageUploaded": "อัปโหลดภาพถ่ายแล้ว",
|
||||||
"NotificationOptionAudioPlaybackStopped": "หยุดเล่นเสียง",
|
"NotificationOptionAudioPlaybackStopped": "หยุดเล่นเสียง",
|
||||||
"NotificationOptionAudioPlayback": "เริ่มเล่นเสียง",
|
"NotificationOptionAudioPlayback": "เริ่มเล่นเสียง",
|
||||||
"NotificationOptionApplicationUpdateInstalled": "ติดตั้งการอัปเดตแอพพลิเคชันแล้ว",
|
"NotificationOptionApplicationUpdateInstalled": "ติดตั้งการอัปเดตแอปพลิเคชันแล้ว",
|
||||||
"NotificationOptionApplicationUpdateAvailable": "มีการอัปเดตแอพพลิเคชัน",
|
"NotificationOptionApplicationUpdateAvailable": "มีการอัปเดตแอปพลิเคชัน",
|
||||||
"NewVersionIsAvailable": "เวอร์ชันใหม่ของเซิร์ฟเวอร์ Jellyfin พร้อมให้ดาวน์โหลดแล้ว",
|
"NewVersionIsAvailable": "เวอร์ชันใหม่ของเซิร์ฟเวอร์ Jellyfin พร้อมให้ดาวน์โหลดแล้ว",
|
||||||
"NameSeasonUnknown": "ไม่ทราบซีซัน",
|
"NameSeasonUnknown": "ไม่ทราบซีซัน",
|
||||||
"NameSeasonNumber": "ซีซัน {0}",
|
"NameSeasonNumber": "ซีซัน {0}",
|
||||||
@ -50,7 +50,6 @@
|
|||||||
"HeaderFavoriteArtists": "ศิลปินที่ชื่นชอบ",
|
"HeaderFavoriteArtists": "ศิลปินที่ชื่นชอบ",
|
||||||
"HeaderFavoriteAlbums": "อัมบั้มที่ชื่นชอบ",
|
"HeaderFavoriteAlbums": "อัมบั้มที่ชื่นชอบ",
|
||||||
"HeaderContinueWatching": "ดูต่อ",
|
"HeaderContinueWatching": "ดูต่อ",
|
||||||
"HeaderCameraUploads": "อัปโหลดรูปถ่าย",
|
|
||||||
"HeaderAlbumArtists": "อัลบั้มศิลปิน",
|
"HeaderAlbumArtists": "อัลบั้มศิลปิน",
|
||||||
"Genres": "ประเภท",
|
"Genres": "ประเภท",
|
||||||
"Folders": "โฟลเดอร์",
|
"Folders": "โฟลเดอร์",
|
||||||
@ -65,8 +64,8 @@
|
|||||||
"Books": "หนังสือ",
|
"Books": "หนังสือ",
|
||||||
"AuthenticationSucceededWithUserName": "{0} ยืนยันตัวสำเร็จแล้ว",
|
"AuthenticationSucceededWithUserName": "{0} ยืนยันตัวสำเร็จแล้ว",
|
||||||
"Artists": "ศิลปิน",
|
"Artists": "ศิลปิน",
|
||||||
"Application": "แอพพลิเคชัน",
|
"Application": "แอปพลิเคชัน",
|
||||||
"AppDeviceValues": "แอพ: {0}, อุปกรณ์: {1}",
|
"AppDeviceValues": "แอป: {0}, อุปกรณ์: {1}",
|
||||||
"Albums": "อัลบั้ม",
|
"Albums": "อัลบั้ม",
|
||||||
"ScheduledTaskStartedWithName": "{0} เริ่มต้น",
|
"ScheduledTaskStartedWithName": "{0} เริ่มต้น",
|
||||||
"ScheduledTaskFailedWithName": "{0} ล้มเหลว",
|
"ScheduledTaskFailedWithName": "{0} ล้มเหลว",
|
||||||
@ -92,7 +91,7 @@
|
|||||||
"TaskCleanCacheDescription": "ลบไฟล์แคชที่ระบบไม่ต้องการ",
|
"TaskCleanCacheDescription": "ลบไฟล์แคชที่ระบบไม่ต้องการ",
|
||||||
"TaskCleanCache": "ล้างไดเรกทอรีแคช",
|
"TaskCleanCache": "ล้างไดเรกทอรีแคช",
|
||||||
"TasksChannelsCategory": "ช่องอินเทอร์เน็ต",
|
"TasksChannelsCategory": "ช่องอินเทอร์เน็ต",
|
||||||
"TasksApplicationCategory": "แอพพลิเคชัน",
|
"TasksApplicationCategory": "แอปพลิเคชัน",
|
||||||
"TasksLibraryCategory": "ไลบรารี",
|
"TasksLibraryCategory": "ไลบรารี",
|
||||||
"TasksMaintenanceCategory": "ปิดซ่อมบำรุง",
|
"TasksMaintenanceCategory": "ปิดซ่อมบำรุง",
|
||||||
"VersionNumber": "เวอร์ชัน {0}",
|
"VersionNumber": "เวอร์ชัน {0}",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "Klasörler",
|
"Folders": "Klasörler",
|
||||||
"Genres": "Türler",
|
"Genres": "Türler",
|
||||||
"HeaderAlbumArtists": "Albüm Sanatçıları",
|
"HeaderAlbumArtists": "Albüm Sanatçıları",
|
||||||
"HeaderCameraUploads": "Kamera Yüklemeleri",
|
|
||||||
"HeaderContinueWatching": "İzlemeye Devam Et",
|
"HeaderContinueWatching": "İzlemeye Devam Et",
|
||||||
"HeaderFavoriteAlbums": "Favori Albümler",
|
"HeaderFavoriteAlbums": "Favori Albümler",
|
||||||
"HeaderFavoriteArtists": "Favori Sanatçılar",
|
"HeaderFavoriteArtists": "Favori Sanatçılar",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"HeaderFavoriteArtists": "Улюблені виконавці",
|
"HeaderFavoriteArtists": "Улюблені виконавці",
|
||||||
"HeaderFavoriteAlbums": "Улюблені альбоми",
|
"HeaderFavoriteAlbums": "Улюблені альбоми",
|
||||||
"HeaderContinueWatching": "Продовжити перегляд",
|
"HeaderContinueWatching": "Продовжити перегляд",
|
||||||
"HeaderCameraUploads": "Завантажено з камери",
|
|
||||||
"HeaderAlbumArtists": "Виконавці альбому",
|
"HeaderAlbumArtists": "Виконавці альбому",
|
||||||
"Genres": "Жанри",
|
"Genres": "Жанри",
|
||||||
"Folders": "Каталоги",
|
"Folders": "Каталоги",
|
||||||
|
@ -105,7 +105,6 @@
|
|||||||
"Inherit": "وراثت میں",
|
"Inherit": "وراثت میں",
|
||||||
"HomeVideos": "ہوم ویڈیو",
|
"HomeVideos": "ہوم ویڈیو",
|
||||||
"HeaderRecordingGroups": "ریکارڈنگ گروپس",
|
"HeaderRecordingGroups": "ریکارڈنگ گروپس",
|
||||||
"HeaderCameraUploads": "کیمرہ اپلوڈز",
|
|
||||||
"FailedLoginAttemptWithUserName": "لاگن کئ کوشش ناکام {0}",
|
"FailedLoginAttemptWithUserName": "لاگن کئ کوشش ناکام {0}",
|
||||||
"DeviceOnlineWithName": "{0} متصل ھو چکا ھے",
|
"DeviceOnlineWithName": "{0} متصل ھو چکا ھے",
|
||||||
"DeviceOfflineWithName": "{0} منقطع ھو چکا ھے",
|
"DeviceOfflineWithName": "{0} منقطع ھو چکا ھے",
|
||||||
|
116
Emby.Server.Implementations/Localization/Core/vi.json
Normal file
116
Emby.Server.Implementations/Localization/Core/vi.json
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"Collections": "Bộ Sưu Tập",
|
||||||
|
"Favorites": "Yêu Thích",
|
||||||
|
"Folders": "Thư Mục",
|
||||||
|
"Genres": "Thể Loại",
|
||||||
|
"HeaderAlbumArtists": "Bộ Sưu Tập Nghệ sĩ",
|
||||||
|
"HeaderContinueWatching": "Xem Tiếp",
|
||||||
|
"HeaderLiveTV": "TV Trực Tiếp",
|
||||||
|
"Movies": "Phim",
|
||||||
|
"Photos": "Ảnh",
|
||||||
|
"Playlists": "Danh sách phát",
|
||||||
|
"Shows": "Chương Trình TV",
|
||||||
|
"Songs": "Các Bài Hát",
|
||||||
|
"Sync": "Đồng Bộ",
|
||||||
|
"ValueSpecialEpisodeName": "Đặc Biệt - {0}",
|
||||||
|
"Albums": "Albums",
|
||||||
|
"Artists": "Các Nghệ Sĩ",
|
||||||
|
"TaskDownloadMissingSubtitlesDescription": "Tìm kiếm phụ đề bị thiếu trên Internet dựa trên cấu hình dữ liệu mô tả.",
|
||||||
|
"TaskDownloadMissingSubtitles": "Tải xuống phụ đề bị thiếu",
|
||||||
|
"TaskRefreshChannelsDescription": "Làm mới thông tin kênh internet.",
|
||||||
|
"TaskRefreshChannels": "Làm Mới Kênh",
|
||||||
|
"TaskCleanTranscodeDescription": "Xóa các tệp chuyển mã cũ hơn một ngày.",
|
||||||
|
"TaskCleanTranscode": "Làm Sạch Thư Mục Chuyển Mã",
|
||||||
|
"TaskUpdatePluginsDescription": "Tải xuống và cài đặt các bản cập nhật cho các plugin được định cấu hình để cập nhật tự động.",
|
||||||
|
"TaskUpdatePlugins": "Cập Nhật Plugins",
|
||||||
|
"TaskRefreshPeopleDescription": "Cập nhật thông tin chi tiết cho diễn viên và đạo diễn trong thư viện phương tiện của bạn.",
|
||||||
|
"TaskRefreshPeople": "Làm mới Người dùng",
|
||||||
|
"TaskCleanLogsDescription": "Xóa tập tin nhật ký cũ hơn {0} ngày.",
|
||||||
|
"TaskCleanLogs": "Làm sạch nhật ký",
|
||||||
|
"TaskRefreshLibraryDescription": "Quét thư viện phương tiện của bạn để tìm các tệp mới và làm mới thông tin chi tiết.",
|
||||||
|
"TaskRefreshLibrary": "Quét Thư viện Phương tiện",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Tạo hình thu nhỏ cho video có các phân cảnh.",
|
||||||
|
"TaskRefreshChapterImages": "Trích Xuất Ảnh Phân Cảnh",
|
||||||
|
"TaskCleanCacheDescription": "Xóa các tệp cache không còn cần thiết của hệ thống.",
|
||||||
|
"TaskCleanCache": "Làm Sạch Thư Mục Cache",
|
||||||
|
"TasksChannelsCategory": "Kênh Internet",
|
||||||
|
"TasksApplicationCategory": "Ứng Dụng",
|
||||||
|
"TasksLibraryCategory": "Thư Viện",
|
||||||
|
"TasksMaintenanceCategory": "Bảo Trì",
|
||||||
|
"VersionNumber": "Phiên Bản {0}",
|
||||||
|
"ValueHasBeenAddedToLibrary": "{0} đã được thêm vào thư viện của bạn",
|
||||||
|
"UserStoppedPlayingItemWithValues": "{0} đã phát xong {1} trên {2}",
|
||||||
|
"UserStartedPlayingItemWithValues": "{0} đang phát {1} trên {2}",
|
||||||
|
"UserPolicyUpdatedWithName": "Chính sách người dùng đã được cập nhật cho {0}",
|
||||||
|
"UserPasswordChangedWithName": "Mật khẩu đã được thay đổi cho người dùng {0}",
|
||||||
|
"UserOnlineFromDevice": "{0} trực tuyến từ {1}",
|
||||||
|
"UserOfflineFromDevice": "{0} đã ngắt kết nối từ {1}",
|
||||||
|
"UserLockedOutWithName": "User {0} đã bị khóa",
|
||||||
|
"UserDownloadingItemWithValues": "{0} đang tải xuống {1}",
|
||||||
|
"UserDeletedWithName": "Người Dùng {0} đã được xóa",
|
||||||
|
"UserCreatedWithName": "Người Dùng {0} đã được tạo",
|
||||||
|
"User": "Người Dùng",
|
||||||
|
"TvShows": "Chương Trình TV",
|
||||||
|
"System": "Hệ Thống",
|
||||||
|
"SubtitleDownloadFailureFromForItem": "Không thể tải xuống phụ đề từ {0} cho {1}",
|
||||||
|
"StartupEmbyServerIsLoading": "Jellyfin Server đang tải. Vui lòng thử lại trong thời gian ngắn.",
|
||||||
|
"ServerNameNeedsToBeRestarted": "{0} cần được khởi động lại",
|
||||||
|
"ScheduledTaskStartedWithName": "{0} đã bắt đầu",
|
||||||
|
"ScheduledTaskFailedWithName": "{0} đã thất bại",
|
||||||
|
"ProviderValue": "Provider: {0}",
|
||||||
|
"PluginUpdatedWithName": "{0} đã cập nhật",
|
||||||
|
"PluginUninstalledWithName": "{0} đã được gỡ bỏ",
|
||||||
|
"PluginInstalledWithName": "{0} đã được cài đặt",
|
||||||
|
"Plugin": "Plugin",
|
||||||
|
"NotificationOptionVideoPlaybackStopped": "Phát lại video đã dừng",
|
||||||
|
"NotificationOptionVideoPlayback": "Đã bắt đầu phát lại video",
|
||||||
|
"NotificationOptionUserLockedOut": "Người dùng bị khóa",
|
||||||
|
"NotificationOptionTaskFailed": "Lỗi tác vụ đã lên lịch",
|
||||||
|
"NotificationOptionServerRestartRequired": "Yêu cầu khởi động lại Server",
|
||||||
|
"NotificationOptionPluginUpdateInstalled": "Cập nhật Plugin đã được cài đặt",
|
||||||
|
"NotificationOptionPluginUninstalled": "Đã gỡ bỏ Plugin",
|
||||||
|
"NotificationOptionPluginInstalled": "Đã cài đặt Plugin",
|
||||||
|
"NotificationOptionPluginError": "Thất bại Plugin",
|
||||||
|
"NotificationOptionNewLibraryContent": "Nội dung mới được thêm vào",
|
||||||
|
"NotificationOptionInstallationFailed": "Cài đặt thất bại",
|
||||||
|
"NotificationOptionCameraImageUploaded": "Đã tải lên hình ảnh máy ảnh",
|
||||||
|
"NotificationOptionAudioPlaybackStopped": "Phát lại âm thanh đã dừng",
|
||||||
|
"NotificationOptionAudioPlayback": "Phát lại âm thanh đã bắt đầu",
|
||||||
|
"NotificationOptionApplicationUpdateInstalled": "Bản cập nhật ứng dụng đã được cài đặt",
|
||||||
|
"NotificationOptionApplicationUpdateAvailable": "Bản cập nhật ứng dụng hiện sẵn có",
|
||||||
|
"NewVersionIsAvailable": "Một phiên bản mới của Jellyfin Server sẵn có để tải.",
|
||||||
|
"NameSeasonUnknown": "Không Rõ Mùa",
|
||||||
|
"NameSeasonNumber": "Mùa {0}",
|
||||||
|
"NameInstallFailed": "{0} cài đặt thất bại",
|
||||||
|
"MusicVideos": "Video Nhạc",
|
||||||
|
"Music": "Nhạc",
|
||||||
|
"MixedContent": "Nội dung hỗn hợp",
|
||||||
|
"MessageServerConfigurationUpdated": "Cấu hình máy chủ đã được cập nhật",
|
||||||
|
"MessageNamedServerConfigurationUpdatedWithValue": "Phần cấu hình máy chủ {0} đã được cập nhật",
|
||||||
|
"MessageApplicationUpdatedTo": "Jellyfin Server đã được cập nhật lên {0}",
|
||||||
|
"MessageApplicationUpdated": "Jellyfin Server đã được cập nhật",
|
||||||
|
"Latest": "Gần Nhất",
|
||||||
|
"LabelRunningTimeValue": "Thời Gian Chạy: {0}",
|
||||||
|
"LabelIpAddressValue": "Địa Chỉ IP: {0}",
|
||||||
|
"ItemRemovedWithName": "{0} đã xóa khỏi thư viện",
|
||||||
|
"ItemAddedWithName": "{0} được thêm vào thư viện",
|
||||||
|
"Inherit": "Thừa hưởng",
|
||||||
|
"HomeVideos": "Video nhà",
|
||||||
|
"HeaderRecordingGroups": "Nhóm Ghi Video",
|
||||||
|
"HeaderNextUp": "Tiếp Theo",
|
||||||
|
"HeaderFavoriteSongs": "Bài Hát Yêu Thích",
|
||||||
|
"HeaderFavoriteShows": "Chương Trình Yêu Thích",
|
||||||
|
"HeaderFavoriteEpisodes": "Tập Phim Yêu Thích",
|
||||||
|
"HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích",
|
||||||
|
"HeaderFavoriteAlbums": "Album Ưa Thích",
|
||||||
|
"FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập thất bại từ {0}",
|
||||||
|
"DeviceOnlineWithName": "{0} đã kết nối",
|
||||||
|
"DeviceOfflineWithName": "{0} đã ngắt kết nối",
|
||||||
|
"ChapterNameValue": "Phân Cảnh {0}",
|
||||||
|
"Channels": "Các Kênh",
|
||||||
|
"CameraImageUploadedFrom": "Một hình ảnh máy ảnh mới đã được tải lên từ {0}",
|
||||||
|
"Books": "Sách",
|
||||||
|
"AuthenticationSucceededWithUserName": "{0} xác thực thành công",
|
||||||
|
"Application": "Ứng Dụng",
|
||||||
|
"AppDeviceValues": "Ứng Dụng: {0}, Thiết Bị: {1}"
|
||||||
|
}
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "文件夹",
|
"Folders": "文件夹",
|
||||||
"Genres": "风格",
|
"Genres": "风格",
|
||||||
"HeaderAlbumArtists": "专辑作家",
|
"HeaderAlbumArtists": "专辑作家",
|
||||||
"HeaderCameraUploads": "相机上传",
|
|
||||||
"HeaderContinueWatching": "继续观影",
|
"HeaderContinueWatching": "继续观影",
|
||||||
"HeaderFavoriteAlbums": "收藏的专辑",
|
"HeaderFavoriteAlbums": "收藏的专辑",
|
||||||
"HeaderFavoriteArtists": "最爱的艺术家",
|
"HeaderFavoriteArtists": "最爱的艺术家",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "檔案夾",
|
"Folders": "檔案夾",
|
||||||
"Genres": "風格",
|
"Genres": "風格",
|
||||||
"HeaderAlbumArtists": "專輯藝人",
|
"HeaderAlbumArtists": "專輯藝人",
|
||||||
"HeaderCameraUploads": "相機上載",
|
|
||||||
"HeaderContinueWatching": "繼續觀看",
|
"HeaderContinueWatching": "繼續觀看",
|
||||||
"HeaderFavoriteAlbums": "最愛專輯",
|
"HeaderFavoriteAlbums": "最愛專輯",
|
||||||
"HeaderFavoriteArtists": "最愛的藝人",
|
"HeaderFavoriteArtists": "最愛的藝人",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"Folders": "資料夾",
|
"Folders": "資料夾",
|
||||||
"Genres": "風格",
|
"Genres": "風格",
|
||||||
"HeaderAlbumArtists": "專輯演出者",
|
"HeaderAlbumArtists": "專輯演出者",
|
||||||
"HeaderCameraUploads": "相機上傳",
|
|
||||||
"HeaderContinueWatching": "繼續觀賞",
|
"HeaderContinueWatching": "繼續觀賞",
|
||||||
"HeaderFavoriteAlbums": "最愛專輯",
|
"HeaderFavoriteAlbums": "最愛專輯",
|
||||||
"HeaderFavoriteArtists": "最愛演出者",
|
"HeaderFavoriteArtists": "最愛演出者",
|
||||||
@ -96,7 +95,7 @@
|
|||||||
"TaskDownloadMissingSubtitles": "下載遺失的字幕",
|
"TaskDownloadMissingSubtitles": "下載遺失的字幕",
|
||||||
"TaskRefreshChannels": "重新整理頻道",
|
"TaskRefreshChannels": "重新整理頻道",
|
||||||
"TaskUpdatePlugins": "更新外掛",
|
"TaskUpdatePlugins": "更新外掛",
|
||||||
"TaskRefreshPeople": "重新整理人員",
|
"TaskRefreshPeople": "刷新用戶",
|
||||||
"TaskCleanLogsDescription": "刪除超過 {0} 天的舊紀錄檔。",
|
"TaskCleanLogsDescription": "刪除超過 {0} 天的舊紀錄檔。",
|
||||||
"TaskCleanLogs": "清空紀錄資料夾",
|
"TaskCleanLogs": "清空紀錄資料夾",
|
||||||
"TaskRefreshLibraryDescription": "重新掃描媒體庫的新檔案並更新描述資料。",
|
"TaskRefreshLibraryDescription": "重新掃描媒體庫的新檔案並更新描述資料。",
|
||||||
|
@ -413,6 +413,7 @@ namespace Emby.Server.Implementations.Localization
|
|||||||
yield return new LocalizationOption("Swedish", "sv");
|
yield return new LocalizationOption("Swedish", "sv");
|
||||||
yield return new LocalizationOption("Swiss German", "gsw");
|
yield return new LocalizationOption("Swiss German", "gsw");
|
||||||
yield return new LocalizationOption("Turkish", "tr");
|
yield return new LocalizationOption("Turkish", "tr");
|
||||||
|
yield return new LocalizationOption("Tiếng Việt", "vi");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
Emby.Server.Implementations/Plugins/PluginManifest.cs
Normal file
60
Emby.Server.Implementations/Plugins/PluginManifest.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Emby.Server.Implementations.Plugins
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a Plugin manifest file.
|
||||||
|
/// </summary>
|
||||||
|
public class PluginManifest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the category of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string Category { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the changelog information.
|
||||||
|
/// </summary>
|
||||||
|
public string Changelog { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the description of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Global Unique Identifier for the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Name of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an overview of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string Overview { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the owner of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string Owner { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the compatibility version for the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string TargetAbi { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the timestamp of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Version number of the plugin.
|
||||||
|
/// </summary>
|
||||||
|
public string Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
|||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsEnabled => false;
|
public bool IsEnabled => true;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsLogged => true;
|
public bool IsLogged => true;
|
||||||
|
@ -666,7 +666,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var eventArgs = new PlaybackProgressEventArgs
|
var eventArgs = new PlaybackStartEventArgs
|
||||||
{
|
{
|
||||||
Item = libraryItem,
|
Item = libraryItem,
|
||||||
Users = users,
|
Users = users,
|
||||||
@ -1037,7 +1037,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
|
|
||||||
var generalCommand = new GeneralCommand
|
var generalCommand = new GeneralCommand
|
||||||
{
|
{
|
||||||
Name = GeneralCommandType.DisplayMessage.ToString()
|
Name = GeneralCommandType.DisplayMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
generalCommand.Arguments["Header"] = command.Header;
|
generalCommand.Arguments["Header"] = command.Header;
|
||||||
@ -1064,10 +1064,10 @@ namespace Emby.Server.Implementations.Session
|
|||||||
AssertCanControl(session, controllingSession);
|
AssertCanControl(session, controllingSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SendMessageToSession(session, "GeneralCommand", command, cancellationToken);
|
return SendMessageToSession(session, SessionMessageType.GeneralCommand, command, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SendMessageToSession<T>(SessionInfo session, string name, T data, CancellationToken cancellationToken)
|
private static async Task SendMessageToSession<T>(SessionInfo session, SessionMessageType name, T data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var controllers = session.SessionControllers;
|
var controllers = session.SessionControllers;
|
||||||
var messageId = Guid.NewGuid();
|
var messageId = Guid.NewGuid();
|
||||||
@ -1078,7 +1078,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task SendMessageToSessions<T>(IEnumerable<SessionInfo> sessions, string name, T data, CancellationToken cancellationToken)
|
private static Task SendMessageToSessions<T>(IEnumerable<SessionInfo> sessions, SessionMessageType name, T data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
IEnumerable<Task> GetTasks()
|
IEnumerable<Task> GetTasks()
|
||||||
{
|
{
|
||||||
@ -1178,7 +1178,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await SendMessageToSession(session, "Play", command, cancellationToken).ConfigureAwait(false);
|
await SendMessageToSession(session, SessionMessageType.Play, command, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -1186,7 +1186,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
var session = GetSessionToRemoteControl(sessionId);
|
var session = GetSessionToRemoteControl(sessionId);
|
||||||
await SendMessageToSession(session, "SyncPlayCommand", command, cancellationToken).ConfigureAwait(false);
|
await SendMessageToSession(session, SessionMessageType.SyncPlayCommand, command, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -1194,7 +1194,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
var session = GetSessionToRemoteControl(sessionId);
|
var session = GetSessionToRemoteControl(sessionId);
|
||||||
await SendMessageToSession(session, "SyncPlayGroupUpdate", command, cancellationToken).ConfigureAwait(false);
|
await SendMessageToSession(session, SessionMessageType.SyncPlayGroupUpdate, command, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<BaseItem> TranslateItemForPlayback(Guid id, User user)
|
private IEnumerable<BaseItem> TranslateItemForPlayback(Guid id, User user)
|
||||||
@ -1268,7 +1268,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
{
|
{
|
||||||
var generalCommand = new GeneralCommand
|
var generalCommand = new GeneralCommand
|
||||||
{
|
{
|
||||||
Name = GeneralCommandType.DisplayContent.ToString(),
|
Name = GeneralCommandType.DisplayContent,
|
||||||
Arguments =
|
Arguments =
|
||||||
{
|
{
|
||||||
["ItemId"] = command.ItemId,
|
["ItemId"] = command.ItemId,
|
||||||
@ -1297,7 +1297,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SendMessageToSession(session, "Playstate", command, cancellationToken);
|
return SendMessageToSession(session, SessionMessageType.PlayState, command, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertCanControl(SessionInfo session, SessionInfo controllingSession)
|
private static void AssertCanControl(SessionInfo session, SessionInfo controllingSession)
|
||||||
@ -1322,7 +1322,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
return SendMessageToSessions(Sessions, "RestartRequired", string.Empty, cancellationToken);
|
return SendMessageToSessions(Sessions, SessionMessageType.RestartRequired, string.Empty, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1334,7 +1334,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
return SendMessageToSessions(Sessions, "ServerShuttingDown", string.Empty, cancellationToken);
|
return SendMessageToSessions(Sessions, SessionMessageType.ServerShuttingDown, string.Empty, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1348,7 +1348,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
|
|
||||||
_logger.LogDebug("Beginning SendServerRestartNotification");
|
_logger.LogDebug("Beginning SendServerRestartNotification");
|
||||||
|
|
||||||
return SendMessageToSessions(Sessions, "ServerRestarting", string.Empty, cancellationToken);
|
return SendMessageToSessions(Sessions, SessionMessageType.ServerRestarting, string.Empty, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1484,6 +1484,14 @@ namespace Emby.Server.Implementations.Session
|
|||||||
throw new SecurityException("User is not allowed access from this device.");
|
throw new SecurityException("User is not allowed access from this device.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sessionsCount = Sessions.Count(i => i.UserId.Equals(user.Id));
|
||||||
|
int maxActiveSessions = user.MaxActiveSessions;
|
||||||
|
_logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions);
|
||||||
|
if (maxActiveSessions >= 1 && sessionsCount >= maxActiveSessions)
|
||||||
|
{
|
||||||
|
throw new SecurityException("User is at their maximum number of sessions.");
|
||||||
|
}
|
||||||
|
|
||||||
var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName);
|
var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName);
|
||||||
|
|
||||||
var session = LogSessionActivity(
|
var session = LogSessionActivity(
|
||||||
@ -1866,7 +1874,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken)
|
public Task SendMessageToAdminSessions<T>(SessionMessageType name, T data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
@ -1879,7 +1887,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, Func<T> dataFn, CancellationToken cancellationToken)
|
public Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, Func<T> dataFn, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
@ -1894,7 +1902,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, T data, CancellationToken cancellationToken)
|
public Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, T data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
@ -1903,7 +1911,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken)
|
public Task SendMessageToUserDeviceSessions<T>(string deviceId, SessionMessageType name, T data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using Jellyfin.Data.Events;
|
|||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@ -316,7 +317,7 @@ namespace Emby.Server.Implementations.Session
|
|||||||
return webSocket.SendAsync(
|
return webSocket.SendAsync(
|
||||||
new WebSocketMessage<int>
|
new WebSocketMessage<int>
|
||||||
{
|
{
|
||||||
MessageType = "ForceKeepAlive",
|
MessageType = SessionMessageType.ForceKeepAlive,
|
||||||
Data = WebSocketLostTimeout
|
Data = WebSocketLostTimeout
|
||||||
},
|
},
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user