Merge branch 'master' into NetworkPR2
This commit is contained in:
commit
0b5ddc90ff
|
@ -28,7 +28,13 @@ jobs:
|
||||||
inputs:
|
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"
|
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
|
## Authenticate with npm registry
|
||||||
|
- task: npmAuthenticate@0
|
||||||
|
inputs:
|
||||||
|
workingFile: ./.npmrc
|
||||||
|
customEndpoint: 'jellyfin-bot for NPM'
|
||||||
|
|
||||||
|
## Generate npm api client
|
||||||
# Unstable
|
# Unstable
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
displayName: 'Build unstable typescript axios client'
|
displayName: 'Build unstable typescript axios client'
|
||||||
|
@ -36,15 +42,6 @@ jobs:
|
||||||
inputs:
|
inputs:
|
||||||
script: "bash ./apiclient/templates/typescript/axios/generate.sh $(System.ArtifactsDirectory) $(Build.BuildNumber)"
|
script: "bash ./apiclient/templates/typescript/axios/generate.sh $(System.ArtifactsDirectory) $(Build.BuildNumber)"
|
||||||
|
|
||||||
- task: Npm@1
|
|
||||||
displayName: 'Publish unstable typescript axios client'
|
|
||||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
|
||||||
inputs:
|
|
||||||
command: publish
|
|
||||||
publishRegistry: useFeed
|
|
||||||
publishFeed: 'unstable@Local'
|
|
||||||
workingDir: ./apiclient/generated/typescript/axios
|
|
||||||
|
|
||||||
# Stable
|
# Stable
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
displayName: 'Build stable typescript axios client'
|
displayName: 'Build stable typescript axios client'
|
||||||
|
@ -52,6 +49,25 @@ jobs:
|
||||||
inputs:
|
inputs:
|
||||||
script: "bash ./apiclient/templates/typescript/axios/generate.sh $(System.ArtifactsDirectory)"
|
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
|
- task: Npm@1
|
||||||
displayName: 'Publish stable typescript axios client'
|
displayName: 'Publish stable typescript axios client'
|
||||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||||
|
|
3
.npmrc
Normal file
3
.npmrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
registry=https://registry.npmjs.org/
|
||||||
|
@jellyfin:registry=https://pkgs.dev.azure.com/jellyfin-project/jellyfin/_packaging/unstable/npm/registry/
|
||||||
|
always-auth=true
|
|
@ -1,5 +1,3 @@
|
||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
@ -10,8 +8,16 @@ using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ControlHandler" />.
|
||||||
|
/// </summary>
|
||||||
public class ControlHandler : BaseControlHandler
|
public class ControlHandler : BaseControlHandler
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ControlHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">The <see cref="IServerConfigurationManager"/> for use with the <see cref="ControlHandler"/> instance.</param>
|
||||||
|
/// <param name="logger">The <see cref="ILogger"/> for use with the <see cref="ControlHandler"/> instance.</param>
|
||||||
public ControlHandler(IServerConfigurationManager config, ILogger logger)
|
public ControlHandler(IServerConfigurationManager config, ILogger logger)
|
||||||
: base(config, logger)
|
: base(config, logger)
|
||||||
{
|
{
|
||||||
|
@ -35,9 +41,17 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records that the handle is authorized in the xml stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="xmlWriter">The <see cref="XmlWriter"/>.</param>
|
||||||
private static void HandleIsAuthorized(XmlWriter xmlWriter)
|
private static void HandleIsAuthorized(XmlWriter xmlWriter)
|
||||||
=> xmlWriter.WriteElementString("Result", "1");
|
=> xmlWriter.WriteElementString("Result", "1");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records that the handle is validated in the xml stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="xmlWriter">The <see cref="XmlWriter"/>.</param>
|
||||||
private static void HandleIsValidated(XmlWriter xmlWriter)
|
private static void HandleIsValidated(XmlWriter xmlWriter)
|
||||||
=> xmlWriter.WriteElementString("Result", "1");
|
=> xmlWriter.WriteElementString("Result", "1");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
|
@ -8,10 +6,19 @@ using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="MediaReceiverRegistrarService" />.
|
||||||
|
/// </summary>
|
||||||
public class MediaReceiverRegistrarService : BaseService, IMediaReceiverRegistrar
|
public class MediaReceiverRegistrarService : BaseService, IMediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MediaReceiverRegistrarService"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">The <see cref="ILogger{MediaReceiverRegistrarService}"/> for use with the <see cref="MediaReceiverRegistrarService"/> instance.</param>
|
||||||
|
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for use with the <see cref="MediaReceiverRegistrarService"/> instance.</param>
|
||||||
|
/// <param name="config">The <see cref="IServerConfigurationManager"/> for use with the <see cref="MediaReceiverRegistrarService"/> instance.</param>
|
||||||
public MediaReceiverRegistrarService(
|
public MediaReceiverRegistrarService(
|
||||||
ILogger<MediaReceiverRegistrarService> logger,
|
ILogger<MediaReceiverRegistrarService> logger,
|
||||||
IHttpClientFactory httpClientFactory,
|
IHttpClientFactory httpClientFactory,
|
||||||
|
@ -24,7 +31,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetServiceXml()
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new MediaReceiverRegistrarXmlBuilder().GetXml();
|
return MediaReceiverRegistrarXmlBuilder.GetXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -1,79 +1,89 @@
|
||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Emby.Dlna.Common;
|
using Emby.Dlna.Common;
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
public class MediaReceiverRegistrarXmlBuilder
|
/// <summary>
|
||||||
|
/// Defines the <see cref="MediaReceiverRegistrarXmlBuilder" />.
|
||||||
|
/// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drmnd/5d37515e-7a63-4709-8258-8fd4e0ed4482.
|
||||||
|
/// </summary>
|
||||||
|
public static class MediaReceiverRegistrarXmlBuilder
|
||||||
{
|
{
|
||||||
public string GetXml()
|
/// <summary>
|
||||||
|
/// Retrieves an XML description of the X_MS_MediaReceiverRegistrar.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An XML representation of this service.</returns>
|
||||||
|
public static string GetXml()
|
||||||
{
|
{
|
||||||
return new ServiceXmlBuilder().GetXml(
|
return new ServiceXmlBuilder().GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
|
||||||
new ServiceActionListBuilder().GetActions(),
|
|
||||||
GetStateVariables());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The a list of all the state variables for this invocation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="IEnumerable{StateVariable}"/>.</returns>
|
||||||
private static IEnumerable<StateVariable> GetStateVariables()
|
private static IEnumerable<StateVariable> GetStateVariables()
|
||||||
{
|
{
|
||||||
var list = new List<StateVariable>();
|
var list = new List<StateVariable>
|
||||||
|
|
||||||
list.Add(new StateVariable
|
|
||||||
{
|
{
|
||||||
Name = "AuthorizationGrantedUpdateID",
|
new StateVariable
|
||||||
DataType = "ui4",
|
{
|
||||||
SendsEvents = true
|
Name = "AuthorizationGrantedUpdateID",
|
||||||
});
|
DataType = "ui4",
|
||||||
|
SendsEvents = true
|
||||||
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "A_ARG_TYPE_DeviceID",
|
Name = "A_ARG_TYPE_DeviceID",
|
||||||
DataType = "string",
|
DataType = "string",
|
||||||
SendsEvents = false
|
SendsEvents = false
|
||||||
});
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "AuthorizationDeniedUpdateID",
|
Name = "AuthorizationDeniedUpdateID",
|
||||||
DataType = "ui4",
|
DataType = "ui4",
|
||||||
SendsEvents = true
|
SendsEvents = true
|
||||||
});
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "ValidationSucceededUpdateID",
|
Name = "ValidationSucceededUpdateID",
|
||||||
DataType = "ui4",
|
DataType = "ui4",
|
||||||
SendsEvents = true
|
SendsEvents = true
|
||||||
});
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "A_ARG_TYPE_RegistrationRespMsg",
|
Name = "A_ARG_TYPE_RegistrationRespMsg",
|
||||||
DataType = "bin.base64",
|
DataType = "bin.base64",
|
||||||
SendsEvents = false
|
SendsEvents = false
|
||||||
});
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "A_ARG_TYPE_RegistrationReqMsg",
|
Name = "A_ARG_TYPE_RegistrationReqMsg",
|
||||||
DataType = "bin.base64",
|
DataType = "bin.base64",
|
||||||
SendsEvents = false
|
SendsEvents = false
|
||||||
});
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "ValidationRevokedUpdateID",
|
Name = "ValidationRevokedUpdateID",
|
||||||
DataType = "ui4",
|
DataType = "ui4",
|
||||||
SendsEvents = true
|
SendsEvents = true
|
||||||
});
|
},
|
||||||
|
|
||||||
list.Add(new StateVariable
|
new StateVariable
|
||||||
{
|
{
|
||||||
Name = "A_ARG_TYPE_Result",
|
Name = "A_ARG_TYPE_Result",
|
||||||
DataType = "int",
|
DataType = "int",
|
||||||
SendsEvents = false
|
SendsEvents = false
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Emby.Dlna.Common;
|
using Emby.Dlna.Common;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
public class ServiceActionListBuilder
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ServiceActionListBuilder" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class ServiceActionListBuilder
|
||||||
{
|
{
|
||||||
public IEnumerable<ServiceAction> GetActions()
|
/// <summary>
|
||||||
|
/// Returns a list of services that this instance provides.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An <see cref="IEnumerable{ServiceAction}"/>.</returns>
|
||||||
|
public static IEnumerable<ServiceAction> GetActions()
|
||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
|
@ -21,6 +27,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the action details for "IsValidated".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
private static ServiceAction GetIsValidated()
|
private static ServiceAction GetIsValidated()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
|
@ -43,6 +53,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the action details for "IsAuthorized".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
private static ServiceAction GetIsAuthorized()
|
private static ServiceAction GetIsAuthorized()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
|
@ -65,6 +79,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the action details for "RegisterDevice".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
private static ServiceAction GetRegisterDevice()
|
private static ServiceAction GetRegisterDevice()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
|
@ -87,6 +105,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the action details for "GetValidationSucceededUpdateID".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
private static ServiceAction GetGetValidationSucceededUpdateID()
|
private static ServiceAction GetGetValidationSucceededUpdateID()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
|
@ -103,7 +125,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetGetAuthorizationDeniedUpdateID()
|
/// <summary>
|
||||||
|
/// Returns the action details for "GetGetAuthorizationDeniedUpdateID".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
|
private static ServiceAction GetGetAuthorizationDeniedUpdateID()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
|
@ -119,7 +145,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetGetValidationRevokedUpdateID()
|
/// <summary>
|
||||||
|
/// Returns the action details for "GetValidationRevokedUpdateID".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
|
private static ServiceAction GetGetValidationRevokedUpdateID()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
|
@ -135,7 +165,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetGetAuthorizationGrantedUpdateID()
|
/// <summary>
|
||||||
|
/// Returns the action details for "GetAuthorizationGrantedUpdateID".
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ServiceAction"/>.</returns>
|
||||||
|
private static ServiceAction GetGetAuthorizationGrantedUpdateID()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
|
|
|
@ -235,13 +235,13 @@ namespace Emby.Dlna.Server
|
||||||
.Append(SecurityElement.Escape(service.ServiceId ?? string.Empty))
|
.Append(SecurityElement.Escape(service.ServiceId ?? string.Empty))
|
||||||
.Append("</serviceId>");
|
.Append("</serviceId>");
|
||||||
builder.Append("<SCPDURL>")
|
builder.Append("<SCPDURL>")
|
||||||
.Append(BuildUrl(service.ScpdUrl, true))
|
.Append(BuildUrl(service.ScpdUrl))
|
||||||
.Append("</SCPDURL>");
|
.Append("</SCPDURL>");
|
||||||
builder.Append("<controlURL>")
|
builder.Append("<controlURL>")
|
||||||
.Append(BuildUrl(service.ControlUrl, true))
|
.Append(BuildUrl(service.ControlUrl))
|
||||||
.Append("</controlURL>");
|
.Append("</controlURL>");
|
||||||
builder.Append("<eventSubURL>")
|
builder.Append("<eventSubURL>")
|
||||||
.Append(BuildUrl(service.EventSubUrl, true))
|
.Append(BuildUrl(service.EventSubUrl))
|
||||||
.Append("</eventSubURL>");
|
.Append("</eventSubURL>");
|
||||||
|
|
||||||
builder.Append("</service>");
|
builder.Append("</service>");
|
||||||
|
@ -250,13 +250,7 @@ namespace Emby.Dlna.Server
|
||||||
builder.Append("</serviceList>");
|
builder.Append("</serviceList>");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private string BuildUrl(string url)
|
||||||
/// Builds a valid url for inclusion in the xml.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url">Url to include.</param>
|
|
||||||
/// <param name="absoluteUrl">Optional. When set to true, the absolute url is always used.</param>
|
|
||||||
/// <returns>The url to use for the element.</returns>
|
|
||||||
private string BuildUrl(string url, bool absoluteUrl = false)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
|
@ -267,7 +261,7 @@ namespace Emby.Dlna.Server
|
||||||
|
|
||||||
url = "/dlna/" + _serverUdn + "/" + url;
|
url = "/dlna/" + _serverUdn + "/" + url;
|
||||||
|
|
||||||
if (EnableAbsoluteUrls || absoluteUrl)
|
if (EnableAbsoluteUrls)
|
||||||
{
|
{
|
||||||
url = _serverAddress.TrimEnd('/') + url;
|
url = _serverAddress.TrimEnd('/') + url;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,8 @@ namespace Emby.Dlna.Service
|
||||||
Async = true
|
Async = true
|
||||||
};
|
};
|
||||||
|
|
||||||
using (var reader = XmlReader.Create(streamReader, readerSettings))
|
using var reader = XmlReader.Create(streamReader, readerSettings);
|
||||||
{
|
requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
|
||||||
requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
|
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
|
||||||
|
@ -124,10 +122,8 @@ namespace Emby.Dlna.Service
|
||||||
{
|
{
|
||||||
if (!reader.IsEmptyElement)
|
if (!reader.IsEmptyElement)
|
||||||
{
|
{
|
||||||
using (var subReader = reader.ReadSubtree())
|
using var subReader = reader.ReadSubtree();
|
||||||
{
|
return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
|
||||||
return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -150,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);
|
||||||
|
@ -165,16 +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)
|
||||||
{
|
{
|
||||||
using (var subReader = reader.ReadSubtree())
|
var result = new ControlRequestInfo(localName, namespaceURI);
|
||||||
{
|
using var subReader = reader.ReadSubtree();
|
||||||
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
|
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -187,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)
|
||||||
|
@ -234,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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Emby.Drawing
|
||||||
private readonly IImageEncoder _imageEncoder;
|
private readonly IImageEncoder _imageEncoder;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
private bool _disposed = false;
|
private bool _disposed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ImageProcessor"/> class.
|
/// Initializes a new instance of the <see cref="ImageProcessor"/> class.
|
||||||
|
@ -466,11 +466,11 @@ namespace Emby.Drawing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void CreateImageCollage(ImageCollageOptions options)
|
public void CreateImageCollage(ImageCollageOptions options, string? libraryName)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Creating image collage and saving to {Path}", options.OutputPath);
|
_logger.LogInformation("Creating image collage and saving to {Path}", options.OutputPath);
|
||||||
|
|
||||||
_imageEncoder.CreateImageCollage(options);
|
_imageEncoder.CreateImageCollage(options, libraryName);
|
||||||
|
|
||||||
_logger.LogInformation("Completed creation of image collage and saved to {Path}", options.OutputPath);
|
_logger.LogInformation("Completed creation of image collage and saved to {Path}", options.OutputPath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace Emby.Drawing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void CreateImageCollage(ImageCollageOptions options)
|
public void CreateImageCollage(ImageCollageOptions options, string? libraryName)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#nullable enable
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
@ -16,21 +17,11 @@ namespace Emby.Naming.AudioBook
|
||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AudioBookFileInfo ParseFile(string path)
|
public AudioBookFileInfo? Resolve(string path, bool isDirectory = false)
|
||||||
{
|
{
|
||||||
return Resolve(path, false);
|
if (path.Length == 0)
|
||||||
}
|
|
||||||
|
|
||||||
public AudioBookFileInfo ParseDirectory(string path)
|
|
||||||
{
|
|
||||||
return Resolve(path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AudioBookFileInfo Resolve(string path, bool isDirectory = false)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(path));
|
throw new ArgumentException("String can't be empty.", nameof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -133,7 +133,6 @@ namespace Emby.Server.Implementations
|
||||||
private IMediaEncoder _mediaEncoder;
|
private IMediaEncoder _mediaEncoder;
|
||||||
private ISessionManager _sessionManager;
|
private ISessionManager _sessionManager;
|
||||||
private IHttpClientFactory _httpClientFactory;
|
private IHttpClientFactory _httpClientFactory;
|
||||||
private IWebSocketManager _webSocketManager;
|
|
||||||
|
|
||||||
private string[] _urlPrefixes;
|
private string[] _urlPrefixes;
|
||||||
|
|
||||||
|
@ -678,7 +677,6 @@ namespace Emby.Server.Implementations
|
||||||
_mediaEncoder = Resolve<IMediaEncoder>();
|
_mediaEncoder = Resolve<IMediaEncoder>();
|
||||||
_sessionManager = Resolve<ISessionManager>();
|
_sessionManager = Resolve<ISessionManager>();
|
||||||
_httpClientFactory = Resolve<IHttpClientFactory>();
|
_httpClientFactory = Resolve<IHttpClientFactory>();
|
||||||
_webSocketManager = Resolve<IWebSocketManager>();
|
|
||||||
|
|
||||||
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
||||||
|
|
||||||
|
@ -799,7 +797,6 @@ namespace Emby.Server.Implementations
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
_urlPrefixes = GetUrlPrefixes().ToArray();
|
_urlPrefixes = GetUrlPrefixes().ToArray();
|
||||||
_webSocketManager.Init(GetExports<IWebSocketListener>());
|
|
||||||
|
|
||||||
Resolve<ILibraryManager>().AddParts(
|
Resolve<ILibraryManager>().AddParts(
|
||||||
GetExports<IResolverIgnoreRule>(),
|
GetExports<IResolverIgnoreRule>(),
|
||||||
|
@ -832,38 +829,6 @@ namespace Emby.Server.Implementations
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (plugin is IPluginAssembly assemblyPlugin)
|
|
||||||
{
|
|
||||||
var assembly = plugin.GetType().Assembly;
|
|
||||||
var assemblyName = assembly.GetName();
|
|
||||||
var assemblyFilePath = assembly.Location;
|
|
||||||
|
|
||||||
var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath));
|
|
||||||
|
|
||||||
assemblyPlugin.SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true);
|
|
||||||
if (idAttributes.Length > 0)
|
|
||||||
{
|
|
||||||
var attribute = (GuidAttribute)idAttributes[0];
|
|
||||||
var assemblyId = new Guid(attribute.Value);
|
|
||||||
|
|
||||||
assemblyPlugin.SetId(assemblyId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, "Error getting plugin Id from {PluginName}.", plugin.GetType().FullName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plugin is IHasPluginConfiguration hasPluginConfiguration)
|
|
||||||
{
|
|
||||||
hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.RegisterServices(ServiceCollection);
|
plugin.RegisterServices(ServiceCollection);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -157,7 +157,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
protected bool TableExists(ManagedConnection connection, string name)
|
protected bool TableExists(ManagedConnection connection, string name)
|
||||||
{
|
{
|
||||||
return connection.RunInTransaction(db =>
|
return connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var statement = PrepareStatement(db, "select DISTINCT tbl_name from sqlite_master"))
|
using (var statement = PrepareStatement(db, "select DISTINCT tbl_name from sqlite_master"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -219,7 +219,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
connection.RunQueries(queries);
|
connection.RunQueries(queries);
|
||||||
|
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var existingColumnNames = GetColumnNames(db, "AncestorIds");
|
var existingColumnNames = GetColumnNames(db, "AncestorIds");
|
||||||
AddColumn(db, "AncestorIds", "AncestorIdText", "Text", existingColumnNames);
|
AddColumn(db, "AncestorIds", "AncestorIdText", "Text", existingColumnNames);
|
||||||
|
@ -495,7 +496,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var saveImagesStatement = base.PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id"))
|
using (var saveImagesStatement = base.PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id"))
|
||||||
{
|
{
|
||||||
|
@ -546,7 +548,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
SaveItemsInTranscation(db, tuples);
|
SaveItemsInTranscation(db, tuples);
|
||||||
}, TransactionMode);
|
}, TransactionMode);
|
||||||
|
@ -2032,7 +2035,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
// First delete chapters
|
// First delete chapters
|
||||||
db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob);
|
db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob);
|
||||||
|
@ -2921,7 +2925,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
var result = new QueryResult<BaseItem>();
|
var result = new QueryResult<BaseItem>();
|
||||||
using (var connection = GetConnection(true))
|
using (var connection = GetConnection(true))
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var statements = PrepareAll(db, statementTexts);
|
var statements = PrepareAll(db, statementTexts);
|
||||||
|
|
||||||
|
@ -3324,7 +3329,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
var result = new QueryResult<Guid>();
|
var result = new QueryResult<Guid>();
|
||||||
using (var connection = GetConnection(true))
|
using (var connection = GetConnection(true))
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var statements = PrepareAll(db, statementTexts);
|
var statements = PrepareAll(db, statementTexts);
|
||||||
|
|
||||||
|
@ -4899,7 +4905,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
connection.ExecuteAll(sql);
|
connection.ExecuteAll(sql);
|
||||||
}, TransactionMode);
|
}, TransactionMode);
|
||||||
|
@ -4950,7 +4957,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var idBlob = id.ToByteArray();
|
var idBlob = id.ToByteArray();
|
||||||
|
|
||||||
|
@ -5357,7 +5365,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
|
|
||||||
itemCountColumns = new Dictionary<string, string>()
|
itemCountColumns = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "itemTypes", "(" + itemCountColumnQuery + ") as itemTypes"}
|
{ "itemTypes", "(" + itemCountColumnQuery + ") as itemTypes" }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5744,7 +5752,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var itemIdBlob = itemId.ToByteArray();
|
var itemIdBlob = itemId.ToByteArray();
|
||||||
|
|
||||||
|
@ -5898,7 +5907,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var itemIdBlob = id.ToByteArray();
|
var itemIdBlob = id.ToByteArray();
|
||||||
|
|
||||||
|
@ -6232,7 +6242,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var itemIdBlob = id.ToByteArray();
|
var itemIdBlob = id.ToByteArray();
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
var users = userDatasTableExists ? null : userManager.Users;
|
var users = userDatasTableExists ? null : userManager.Users;
|
||||||
|
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
db.ExecuteAll(string.Join(";", new[] {
|
db.ExecuteAll(string.Join(";", new[] {
|
||||||
|
|
||||||
|
@ -178,7 +179,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
SaveUserData(db, internalUserId, key, userData);
|
SaveUserData(db, internalUserId, key, userData);
|
||||||
}, TransactionMode);
|
}, TransactionMode);
|
||||||
|
@ -246,7 +248,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
foreach (var userItemData in userDataList)
|
foreach (var userItemData in userDataList)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,10 +31,10 @@
|
||||||
<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.8" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Mono.Nat" Version="3.0.0" />
|
<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" />
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Data.Events;
|
using Jellyfin.Data.Events;
|
||||||
|
@ -14,16 +13,18 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
public class WebSocketManager : IWebSocketManager
|
public class WebSocketManager : IWebSocketManager
|
||||||
{
|
{
|
||||||
|
private readonly Lazy<IEnumerable<IWebSocketListener>> _webSocketListeners;
|
||||||
private readonly ILogger<WebSocketManager> _logger;
|
private readonly ILogger<WebSocketManager> _logger;
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
|
|
||||||
private bool _disposed = false;
|
private bool _disposed = false;
|
||||||
|
|
||||||
public WebSocketManager(
|
public WebSocketManager(
|
||||||
|
Lazy<IEnumerable<IWebSocketListener>> webSocketListeners,
|
||||||
ILogger<WebSocketManager> logger,
|
ILogger<WebSocketManager> logger,
|
||||||
ILoggerFactory loggerFactory)
|
ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
|
_webSocketListeners = webSocketListeners;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
}
|
}
|
||||||
|
@ -68,15 +69,6 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the rest handlers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="listeners">The web socket listeners.</param>
|
|
||||||
public void Init(IEnumerable<IWebSocketListener> listeners)
|
|
||||||
{
|
|
||||||
_webSocketListeners = listeners.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes the web socket message received.
|
/// Processes the web socket message received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -90,7 +82,8 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
|
|
||||||
IEnumerable<Task> GetTasks()
|
IEnumerable<Task> GetTasks()
|
||||||
{
|
{
|
||||||
foreach (var x in _webSocketListeners)
|
var listeners = _webSocketListeners.Value;
|
||||||
|
foreach (var x in listeners)
|
||||||
{
|
{
|
||||||
yield return x.ProcessMessageAsync(result);
|
yield return x.ProcessMessageAsync(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,9 +133,20 @@ namespace Emby.Server.Implementations.Images
|
||||||
|
|
||||||
protected virtual IEnumerable<string> GetStripCollageImagePaths(BaseItem primaryItem, IEnumerable<BaseItem> items)
|
protected virtual IEnumerable<string> GetStripCollageImagePaths(BaseItem primaryItem, IEnumerable<BaseItem> items)
|
||||||
{
|
{
|
||||||
|
var useBackdrop = primaryItem is CollectionFolder;
|
||||||
return items
|
return items
|
||||||
.Select(i =>
|
.Select(i =>
|
||||||
{
|
{
|
||||||
|
// Use Backdrop instead of Primary image for Library images.
|
||||||
|
if (useBackdrop)
|
||||||
|
{
|
||||||
|
var backdrop = i.GetImageInfo(ImageType.Backdrop, 0);
|
||||||
|
if (backdrop != null && backdrop.IsLocalFile)
|
||||||
|
{
|
||||||
|
return backdrop.Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var image = i.GetImageInfo(ImageType.Primary, 0);
|
var image = i.GetImageInfo(ImageType.Primary, 0);
|
||||||
if (image != null && image.IsLocalFile)
|
if (image != null && image.IsLocalFile)
|
||||||
{
|
{
|
||||||
|
@ -190,7 +201,7 @@ namespace Emby.Server.Implementations.Images
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageProcessor.CreateImageCollage(options);
|
ImageProcessor.CreateImageCollage(options, primaryItem.Name);
|
||||||
return outputPath;
|
return outputPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
private readonly ILocalizationManager _localizationManager;
|
private readonly ILocalizationManager _localizationManager;
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
|
||||||
private readonly Dictionary<string, ILiveStream> _openStreams = new Dictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
|
private readonly ConcurrentDictionary<string, ILiveStream> _openStreams = new ConcurrentDictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
|
||||||
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
private IMediaSourceProvider[] _providers;
|
private IMediaSourceProvider[] _providers;
|
||||||
|
@ -582,29 +583,20 @@ namespace Emby.Server.Implementations.Library
|
||||||
mediaSource.InferTotalBitrate();
|
mediaSource.InferTotalBitrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken)
|
public Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
var info = _openStreams.Values.FirstOrDefault(i =>
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var info = _openStreams.Values.FirstOrDefault(i =>
|
var liveStream = i as ILiveStream;
|
||||||
|
if (liveStream != null)
|
||||||
{
|
{
|
||||||
var liveStream = i as ILiveStream;
|
return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase);
|
||||||
if (liveStream != null)
|
}
|
||||||
{
|
|
||||||
return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return info as IDirectStreamProvider;
|
return Task.FromResult(info as IDirectStreamProvider);
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_liveStreamSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
|
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
|
||||||
|
@ -793,29 +785,20 @@ namespace Emby.Server.Implementations.Library
|
||||||
return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info as IDirectStreamProvider);
|
return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info as IDirectStreamProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ILiveStream> GetLiveStreamInfo(string id, CancellationToken cancellationToken)
|
private Task<ILiveStream> GetLiveStreamInfo(string id, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(id))
|
if (string.IsNullOrEmpty(id))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(id));
|
throw new ArgumentNullException(nameof(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
if (_openStreams.TryGetValue(id, out ILiveStream info))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (_openStreams.TryGetValue(id, out ILiveStream info))
|
return Task.FromResult(info);
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ResourceNotFoundException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
else
|
||||||
{
|
{
|
||||||
_liveStreamSemaphore.Release();
|
return Task.FromException<ILiveStream>(new ResourceNotFoundException());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,7 +827,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
if (liveStream.ConsumerCount <= 0)
|
if (liveStream.ConsumerCount <= 0)
|
||||||
{
|
{
|
||||||
_openStreams.Remove(id);
|
_openStreams.TryRemove(id, out _);
|
||||||
|
|
||||||
_logger.LogInformation("Closing live stream {0}", id);
|
_logger.LogInformation("Closing live stream {0}", id);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
/// <value>The priority.</value>
|
/// <value>The priority.</value>
|
||||||
public override ResolverPriority Priority => ResolverPriority.Fourth;
|
public override ResolverPriority Priority => ResolverPriority.Fourth;
|
||||||
|
|
||||||
public MultiItemResolverResult ResolveMultiple(Folder parent,
|
public MultiItemResolverResult ResolveMultiple(
|
||||||
|
Folder parent,
|
||||||
List<FileSystemMetadata> files,
|
List<FileSystemMetadata> files,
|
||||||
string collectionType,
|
string collectionType,
|
||||||
IDirectoryService directoryService)
|
IDirectoryService directoryService)
|
||||||
|
@ -50,7 +51,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
|
private MultiItemResolverResult ResolveMultipleInternal(
|
||||||
|
Folder parent,
|
||||||
List<FileSystemMetadata> files,
|
List<FileSystemMetadata> files,
|
||||||
string collectionType,
|
string collectionType,
|
||||||
IDirectoryService directoryService)
|
IDirectoryService directoryService)
|
||||||
|
|
|
@ -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,52 +116,48 @@ 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)
|
|
||||||
|
var directories = list.Where(fileSystemInfo => fileSystemInfo.IsDirectory);
|
||||||
|
|
||||||
|
var result = Parallel.ForEach(directories, (fileSystemInfo, state) =>
|
||||||
{
|
{
|
||||||
if (fileSystemInfo.IsDirectory)
|
var path = fileSystemInfo.FullName;
|
||||||
|
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
|
||||||
|
|
||||||
|
if (hasMusic)
|
||||||
{
|
{
|
||||||
if (allowSubfolders)
|
if (parser.IsMultiPart(path))
|
||||||
{
|
{
|
||||||
if (notMultiDisc)
|
logger.LogDebug("Found multi-disc folder: " + path);
|
||||||
{
|
Interlocked.Increment(ref discSubfolderCount);
|
||||||
continue;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
var path = fileSystemInfo.FullName;
|
// If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
|
||||||
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
|
state.Stop();
|
||||||
|
|
||||||
if (hasMusic)
|
|
||||||
{
|
|
||||||
if (parser.IsMultiPart(path))
|
|
||||||
{
|
|
||||||
logger.LogDebug("Found multi-disc folder: " + path);
|
|
||||||
discSubfolderCount++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
|
|
||||||
notMultiDisc = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||||
var fileExtension = Path.GetExtension(f.FullName) ??
|
var fileExtension = Path.GetExtension(f.FullName) ??
|
||||||
string.Empty;
|
string.Empty;
|
||||||
|
|
||||||
return _validExtensions.Contains(fileExtension,
|
return _validExtensions.Contains(
|
||||||
|
fileExtension,
|
||||||
StringComparer
|
StringComparer
|
||||||
.OrdinalIgnoreCase);
|
.OrdinalIgnoreCase);
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
// Every so often
|
// Every so often
|
||||||
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
|
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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": "אמנים מועדפים",
|
||||||
|
|
3
Emby.Server.Implementations/Localization/Core/hi.json
Normal file
3
Emby.Server.Implementations/Localization/Core/hi.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"Albums": "आल्बुम्"
|
||||||
|
}
|
|
@ -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": "즐겨찾는 아티스트",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -96,7 +96,6 @@
|
||||||
"HeaderFavoriteArtists": "Artistët e preferuar",
|
"HeaderFavoriteArtists": "Artistët e preferuar",
|
||||||
"HeaderFavoriteAlbums": "Albumet e preferuar",
|
"HeaderFavoriteAlbums": "Albumet e preferuar",
|
||||||
"HeaderContinueWatching": "Vazhdo të shikosh",
|
"HeaderContinueWatching": "Vazhdo të shikosh",
|
||||||
"HeaderCameraUploads": "Ngarkimet nga Kamera",
|
|
||||||
"HeaderAlbumArtists": "Artistët e albumeve",
|
"HeaderAlbumArtists": "Artistët e albumeve",
|
||||||
"Genres": "Zhanre",
|
"Genres": "Zhanre",
|
||||||
"Folders": "Dosje",
|
"Folders": "Dosje",
|
||||||
|
@ -113,5 +112,5 @@
|
||||||
"Artists": "Artistë",
|
"Artists": "Artistë",
|
||||||
"Application": "Aplikacioni",
|
"Application": "Aplikacioni",
|
||||||
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
|
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
|
||||||
"Albums": "Albumet"
|
"Albums": "Albume"
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,6 @@
|
||||||
"HeaderFavoriteArtists": "Омиљени извођачи",
|
"HeaderFavoriteArtists": "Омиљени извођачи",
|
||||||
"HeaderFavoriteAlbums": "Омиљени албуми",
|
"HeaderFavoriteAlbums": "Омиљени албуми",
|
||||||
"HeaderContinueWatching": "Настави гледање",
|
"HeaderContinueWatching": "Настави гледање",
|
||||||
"HeaderCameraUploads": "Слања са камере",
|
|
||||||
"HeaderAlbumArtists": "Извођачи албума",
|
"HeaderAlbumArtists": "Извођачи албума",
|
||||||
"Genres": "Жанрови",
|
"Genres": "Жанрови",
|
||||||
"Folders": "Фасцикле",
|
"Folders": "Фасцикле",
|
||||||
|
|
|
@ -9,14 +9,13 @@
|
||||||
"Channels": "Kanaler",
|
"Channels": "Kanaler",
|
||||||
"ChapterNameValue": "Kapitel {0}",
|
"ChapterNameValue": "Kapitel {0}",
|
||||||
"Collections": "Samlingar",
|
"Collections": "Samlingar",
|
||||||
"DeviceOfflineWithName": "{0} har kopplat från",
|
"DeviceOfflineWithName": "{0} har kopplat ner",
|
||||||
"DeviceOnlineWithName": "{0} är ansluten",
|
"DeviceOnlineWithName": "{0} är ansluten",
|
||||||
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
|
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
|
||||||
"Favorites": "Favoriter",
|
"Favorites": "Favoriter",
|
||||||
"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,7 +20,6 @@
|
||||||
"MessageApplicationUpdated": "ஜெல்லிஃபின் சேவையகம் புதுப்பிக்கப்பட்டது",
|
"MessageApplicationUpdated": "ஜெல்லிஃபின் சேவையகம் புதுப்பிக்கப்பட்டது",
|
||||||
"Inherit": "மரபுரிமையாகப் பெறு",
|
"Inherit": "மரபுரிமையாகப் பெறு",
|
||||||
"HeaderRecordingGroups": "பதிவு குழுக்கள்",
|
"HeaderRecordingGroups": "பதிவு குழுக்கள்",
|
||||||
"HeaderCameraUploads": "புகைப்பட பதிவேற்றங்கள்",
|
|
||||||
"Folders": "கோப்புறைகள்",
|
"Folders": "கோப்புறைகள்",
|
||||||
"FailedLoginAttemptWithUserName": "{0} இலிருந்து உள்நுழைவு முயற்சி தோல்வியடைந்தது",
|
"FailedLoginAttemptWithUserName": "{0} இலிருந்து உள்நுழைவு முயற்சி தோல்வியடைந்தது",
|
||||||
"DeviceOnlineWithName": "{0} இணைக்கப்பட்டது",
|
"DeviceOnlineWithName": "{0} இணைக்கப்பட்டது",
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
"HeaderFavoriteArtists": "ศิลปินที่ชื่นชอบ",
|
"HeaderFavoriteArtists": "ศิลปินที่ชื่นชอบ",
|
||||||
"HeaderFavoriteAlbums": "อัมบั้มที่ชื่นชอบ",
|
"HeaderFavoriteAlbums": "อัมบั้มที่ชื่นชอบ",
|
||||||
"HeaderContinueWatching": "ดูต่อ",
|
"HeaderContinueWatching": "ดูต่อ",
|
||||||
"HeaderCameraUploads": "อัปโหลดรูปถ่าย",
|
|
||||||
"HeaderAlbumArtists": "อัลบั้มศิลปิน",
|
"HeaderAlbumArtists": "อัลบั้มศิลปิน",
|
||||||
"Genres": "ประเภท",
|
"Genres": "ประเภท",
|
||||||
"Folders": "โฟลเดอร์",
|
"Folders": "โฟลเดอร์",
|
||||||
|
|
|
@ -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} منقطع ھو چکا ھے",
|
||||||
|
|
|
@ -103,7 +103,6 @@
|
||||||
"HeaderFavoriteEpisodes": "Tập Phim Yêu Thích",
|
"HeaderFavoriteEpisodes": "Tập Phim Yêu Thích",
|
||||||
"HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích",
|
"HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích",
|
||||||
"HeaderFavoriteAlbums": "Album Ưa Thích",
|
"HeaderFavoriteAlbums": "Album Ưa Thích",
|
||||||
"HeaderCameraUploads": "Máy Ảnh Tải Lên",
|
|
||||||
"FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập thất bại từ {0}",
|
"FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập thất bại từ {0}",
|
||||||
"DeviceOnlineWithName": "{0} đã kết nối",
|
"DeviceOnlineWithName": "{0} đã kết nối",
|
||||||
"DeviceOfflineWithName": "{0} đã ngắt kết nối",
|
"DeviceOfflineWithName": "{0} đã ngắt kết nối",
|
||||||
|
|
|
@ -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": "最愛演出者",
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
// Every so often
|
// Every so often
|
||||||
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
|
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
|
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@ namespace Emby.Server.Implementations.Security
|
||||||
{
|
{
|
||||||
if (tableNewlyCreated && TableExists(connection, "AccessTokens"))
|
if (tableNewlyCreated && TableExists(connection, "AccessTokens"))
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
var existingColumnNames = GetColumnNames(db, "AccessTokens");
|
var existingColumnNames = GetColumnNames(db, "AccessTokens");
|
||||||
|
|
||||||
|
@ -88,7 +89,8 @@ namespace Emby.Server.Implementations.Security
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var statement = db.PrepareStatement("insert into Tokens (AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity) values (@AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @UserName, @IsActive, @DateCreated, @DateLastActivity)"))
|
using (var statement = db.PrepareStatement("insert into Tokens (AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity) values (@AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @UserName, @IsActive, @DateCreated, @DateLastActivity)"))
|
||||||
{
|
{
|
||||||
|
@ -119,7 +121,8 @@ namespace Emby.Server.Implementations.Security
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var statement = db.PrepareStatement("Update Tokens set AccessToken=@AccessToken, DeviceId=@DeviceId, AppName=@AppName, AppVersion=@AppVersion, DeviceName=@DeviceName, UserId=@UserId, UserName=@UserName, DateCreated=@DateCreated, DateLastActivity=@DateLastActivity where Id=@Id"))
|
using (var statement = db.PrepareStatement("Update Tokens set AccessToken=@AccessToken, DeviceId=@DeviceId, AppName=@AppName, AppVersion=@AppVersion, DeviceName=@DeviceName, UserId=@UserId, UserName=@UserName, DateCreated=@DateCreated, DateLastActivity=@DateLastActivity where Id=@Id"))
|
||||||
{
|
{
|
||||||
|
@ -151,7 +154,8 @@ namespace Emby.Server.Implementations.Security
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var statement = db.PrepareStatement("Delete from Tokens where Id=@Id"))
|
using (var statement = db.PrepareStatement("Delete from Tokens where Id=@Id"))
|
||||||
{
|
{
|
||||||
|
@ -346,7 +350,8 @@ namespace Emby.Server.Implementations.Security
|
||||||
{
|
{
|
||||||
using (var connection = GetConnection(true))
|
using (var connection = GetConnection(true))
|
||||||
{
|
{
|
||||||
return connection.RunInTransaction(db =>
|
return connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var statement = base.PrepareStatement(db, "select CustomName from Devices where Id=@DeviceId"))
|
using (var statement = base.PrepareStatement(db, "select CustomName from Devices where Id=@DeviceId"))
|
||||||
{
|
{
|
||||||
|
@ -377,7 +382,8 @@ namespace Emby.Server.Implementations.Security
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(
|
||||||
|
db =>
|
||||||
{
|
{
|
||||||
using (var statement = db.PrepareStatement("replace into devices (Id, CustomName, Capabilities) VALUES (@Id, @CustomName, (Select Capabilities from Devices where Id=@Id))"))
|
using (var statement = db.PrepareStatement("replace into devices (Id, CustomName, Capabilities) VALUES (@Id, @CustomName, (Select Capabilities from Devices where Id=@Id))"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Queries;
|
||||||
using MediaBrowser.Model.Activity;
|
using MediaBrowser.Model.Activity;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
@ -39,19 +39,19 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="QueryResult{ActivityLogEntry}"/> containing the log entries.</returns>
|
/// <returns>A <see cref="QueryResult{ActivityLogEntry}"/> containing the log entries.</returns>
|
||||||
[HttpGet("Entries")]
|
[HttpGet("Entries")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<QueryResult<ActivityLogEntry>> GetLogEntries(
|
public async Task<ActionResult<QueryResult<ActivityLogEntry>>> GetLogEntries(
|
||||||
[FromQuery] int? startIndex,
|
[FromQuery] int? startIndex,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
[FromQuery] DateTime? minDate,
|
[FromQuery] DateTime? minDate,
|
||||||
[FromQuery] bool? hasUserId)
|
[FromQuery] bool? hasUserId)
|
||||||
{
|
{
|
||||||
var filterFunc = new Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>>(
|
return await _activityManager.GetPagedResultAsync(new ActivityLogQuery
|
||||||
entries => entries.Where(entry => entry.DateCreated >= minDate
|
{
|
||||||
&& (!hasUserId.HasValue || (hasUserId.Value
|
StartIndex = startIndex,
|
||||||
? entry.UserId != Guid.Empty
|
Limit = limit,
|
||||||
: entry.UserId == Guid.Empty))));
|
MinDate = minDate,
|
||||||
|
HasUserId = hasUserId
|
||||||
return _activityManager.GetPagedResult(filterFunc, startIndex, limit);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
||||||
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
||||||
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
||||||
|
@ -89,7 +89,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? genres,
|
[FromQuery] string? genres,
|
||||||
|
@ -188,7 +188,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}).Where(i => i != null).Select(i => i!.Id).ToArray();
|
}).Where(i => i != null).Select(i => i!.Id).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
@ -263,7 +263,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
||||||
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
||||||
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
||||||
|
@ -298,7 +298,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? genres,
|
[FromQuery] string? genres,
|
||||||
|
@ -397,7 +397,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}).Where(i => i != null).Select(i => i!.Id).ToArray();
|
}).Where(i => i != null).Select(i => i!.Id).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
||||||
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||||
/// <param name="sortOrder">Optional. Sort Order - Ascending,Descending.</param>
|
/// <param name="sortOrder">Optional. Sort Order - Ascending,Descending.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.</param>
|
/// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.</param>
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <response code="200">Channel items returned.</response>
|
/// <response code="200">Channel items returned.</response>
|
||||||
|
@ -121,7 +121,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] int? startIndex,
|
[FromQuery] int? startIndex,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
[FromQuery] string? sortOrder,
|
[FromQuery] string? sortOrder,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] string? sortBy,
|
[FromQuery] string? sortBy,
|
||||||
[FromQuery] string? fields)
|
[FromQuery] string? fields)
|
||||||
{
|
{
|
||||||
|
@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
.AddItemFields(fields)
|
.AddItemFields(fields)
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +183,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="userId">Optional. User Id.</param>
|
/// <param name="userId">Optional. User Id.</param>
|
||||||
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
||||||
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <param name="channelIds">Optional. Specify one or more channel id's, comma delimited.</param>
|
/// <param name="channelIds">Optional. Specify one or more channel id's, comma delimited.</param>
|
||||||
/// <response code="200">Latest channel items returned.</response>
|
/// <response code="200">Latest channel items returned.</response>
|
||||||
|
@ -196,7 +196,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] Guid? userId,
|
[FromQuery] Guid? userId,
|
||||||
[FromQuery] int? startIndex,
|
[FromQuery] int? startIndex,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? channelIds)
|
[FromQuery] string? channelIds)
|
||||||
{
|
{
|
||||||
|
@ -217,7 +217,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
.AddItemFields(fields)
|
.AddItemFields(fields)
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="includeItemTypes">Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
||||||
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
||||||
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
||||||
|
@ -90,7 +90,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? genres,
|
[FromQuery] string? genres,
|
||||||
|
@ -188,7 +188,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -333,7 +333,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
||||||
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
||||||
/// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
/// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
||||||
/// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
|
/// <param name="format">Optional. The <see cref="ImageFormat"/> of the returned image.</param>
|
||||||
/// <param name="addPlayedIndicator">Optional. Add a played indicator.</param>
|
/// <param name="addPlayedIndicator">Optional. Add a played indicator.</param>
|
||||||
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
||||||
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
||||||
|
@ -364,7 +364,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] int? quality,
|
[FromQuery] int? quality,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] bool? cropWhitespace,
|
[FromQuery] bool? cropWhitespace,
|
||||||
[FromQuery] string? format,
|
[FromQuery] ImageFormat? format,
|
||||||
[FromQuery] bool? addPlayedIndicator,
|
[FromQuery] bool? addPlayedIndicator,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
[FromQuery] int? unplayedCount,
|
[FromQuery] int? unplayedCount,
|
||||||
|
@ -443,7 +443,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] int? quality,
|
[FromQuery] int? quality,
|
||||||
[FromRoute, Required] string tag,
|
[FromRoute, Required] string tag,
|
||||||
[FromQuery] bool? cropWhitespace,
|
[FromQuery] bool? cropWhitespace,
|
||||||
[FromRoute, Required] string format,
|
[FromRoute, Required] ImageFormat format,
|
||||||
[FromQuery] bool? addPlayedIndicator,
|
[FromQuery] bool? addPlayedIndicator,
|
||||||
[FromRoute, Required] double percentPlayed,
|
[FromRoute, Required] double percentPlayed,
|
||||||
[FromRoute, Required] int unplayedCount,
|
[FromRoute, Required] int unplayedCount,
|
||||||
|
@ -516,7 +516,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromRoute, Required] ImageType imageType,
|
[FromRoute, Required] ImageType imageType,
|
||||||
[FromQuery] string tag,
|
[FromQuery] string tag,
|
||||||
[FromQuery] string format,
|
[FromQuery] ImageFormat? format,
|
||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
|
@ -595,7 +595,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromRoute, Required] ImageType imageType,
|
[FromRoute, Required] ImageType imageType,
|
||||||
[FromQuery] string tag,
|
[FromQuery] string tag,
|
||||||
[FromQuery] string format,
|
[FromQuery] ImageFormat? format,
|
||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
|
@ -674,7 +674,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromRoute, Required] ImageType imageType,
|
[FromRoute, Required] ImageType imageType,
|
||||||
[FromQuery] string tag,
|
[FromQuery] string tag,
|
||||||
[FromQuery] string format,
|
[FromQuery] ImageFormat? format,
|
||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
|
@ -753,7 +753,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromRoute, Required] ImageType imageType,
|
[FromRoute, Required] ImageType imageType,
|
||||||
[FromQuery] string tag,
|
[FromQuery] string tag,
|
||||||
[FromQuery] string format,
|
[FromQuery] ImageFormat? format,
|
||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
|
@ -832,7 +832,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromRoute, Required] ImageType imageType,
|
[FromRoute, Required] ImageType imageType,
|
||||||
[FromRoute, Required] string tag,
|
[FromRoute, Required] string tag,
|
||||||
[FromRoute, Required] string format,
|
[FromRoute, Required] ImageFormat format,
|
||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
|
@ -911,7 +911,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromRoute, Required] Guid userId,
|
[FromRoute, Required] Guid userId,
|
||||||
[FromRoute, Required] ImageType imageType,
|
[FromRoute, Required] ImageType imageType,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? format,
|
[FromQuery] ImageFormat? format,
|
||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] double? percentPlayed,
|
[FromQuery] double? percentPlayed,
|
||||||
|
@ -1038,7 +1038,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
ImageType imageType,
|
ImageType imageType,
|
||||||
int? imageIndex,
|
int? imageIndex,
|
||||||
string? tag,
|
string? tag,
|
||||||
string? format,
|
ImageFormat? format,
|
||||||
int? maxWidth,
|
int? maxWidth,
|
||||||
int? maxHeight,
|
int? maxHeight,
|
||||||
double? percentPlayed,
|
double? percentPlayed,
|
||||||
|
@ -1128,12 +1128,11 @@ namespace Jellyfin.Api.Controllers
|
||||||
isHeadRequest).ConfigureAwait(false);
|
isHeadRequest).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageFormat[] GetOutputFormats(string? format)
|
private ImageFormat[] GetOutputFormats(ImageFormat? format)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(format)
|
if (format.HasValue)
|
||||||
&& Enum.TryParse(format, true, out ImageFormat parsedFormat))
|
|
||||||
{
|
{
|
||||||
return new[] { parsedFormat };
|
return new[] { format.Value };
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetClientSupportedFormats();
|
return GetClientSupportedFormats();
|
||||||
|
@ -1157,7 +1156,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
|
|
||||||
var acceptParam = Request.Query[HeaderNames.Accept];
|
var acceptParam = Request.Query[HeaderNames.Accept];
|
||||||
|
|
||||||
var supportsWebP = SupportsFormat(supportedFormats, acceptParam, "webp", false);
|
var supportsWebP = SupportsFormat(supportedFormats, acceptParam, ImageFormat.Webp, false);
|
||||||
|
|
||||||
if (!supportsWebP)
|
if (!supportsWebP)
|
||||||
{
|
{
|
||||||
|
@ -1179,7 +1178,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
formats.Add(ImageFormat.Jpg);
|
formats.Add(ImageFormat.Jpg);
|
||||||
formats.Add(ImageFormat.Png);
|
formats.Add(ImageFormat.Png);
|
||||||
|
|
||||||
if (SupportsFormat(supportedFormats, acceptParam, "gif", true))
|
if (SupportsFormat(supportedFormats, acceptParam, ImageFormat.Gif, true))
|
||||||
{
|
{
|
||||||
formats.Add(ImageFormat.Gif);
|
formats.Add(ImageFormat.Gif);
|
||||||
}
|
}
|
||||||
|
@ -1187,9 +1186,10 @@ namespace Jellyfin.Api.Controllers
|
||||||
return formats.ToArray();
|
return formats.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SupportsFormat(IReadOnlyCollection<string> requestAcceptTypes, string acceptParam, string format, bool acceptAll)
|
private bool SupportsFormat(IReadOnlyCollection<string> requestAcceptTypes, string acceptParam, ImageFormat format, bool acceptAll)
|
||||||
{
|
{
|
||||||
var mimeType = "image/" + format;
|
var normalized = format.ToString().ToLowerInvariant();
|
||||||
|
var mimeType = "image/" + normalized;
|
||||||
|
|
||||||
if (requestAcceptTypes.Contains(mimeType))
|
if (requestAcceptTypes.Contains(mimeType))
|
||||||
{
|
{
|
||||||
|
@ -1201,7 +1201,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Equals(acceptParam, format, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(acceptParam, normalized, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ActionResult> GetImageResult(
|
private async Task<ActionResult> GetImageResult(
|
||||||
|
|
|
@ -159,7 +159,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] bool? isHd,
|
[FromQuery] bool? isHd,
|
||||||
[FromQuery] bool? is4K,
|
[FromQuery] bool? is4K,
|
||||||
[FromQuery] string? locationTypes,
|
[FromQuery] string? locationTypes,
|
||||||
[FromQuery] string? excludeLocationTypes,
|
[FromQuery] LocationType[] excludeLocationTypes,
|
||||||
[FromQuery] bool? isMissing,
|
[FromQuery] bool? isMissing,
|
||||||
[FromQuery] bool? isUnaired,
|
[FromQuery] bool? isUnaired,
|
||||||
[FromQuery] double? minCommunityRating,
|
[FromQuery] double? minCommunityRating,
|
||||||
|
@ -182,7 +182,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? imageTypes,
|
[FromQuery] string? imageTypes,
|
||||||
|
@ -365,7 +365,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
query.CollapseBoxSetItems = false;
|
query.CollapseBoxSetItems = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters!))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
@ -406,12 +406,9 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExcludeLocationTypes
|
// ExcludeLocationTypes
|
||||||
if (!string.IsNullOrEmpty(excludeLocationTypes))
|
if (excludeLocationTypes.Any(t => t == LocationType.Virtual))
|
||||||
{
|
{
|
||||||
if (excludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray().Contains(LocationType.Virtual))
|
query.IsVirtualItem = false;
|
||||||
{
|
|
||||||
query.IsVirtualItem = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(locationTypes))
|
if (!string.IsNullOrEmpty(locationTypes))
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="includeItemTypes">Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
||||||
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
||||||
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
||||||
|
@ -89,7 +89,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? genres,
|
[FromQuery] string? genres,
|
||||||
|
@ -187,7 +187,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -89,7 +89,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? genres,
|
[FromQuery] string? genres,
|
||||||
|
@ -187,7 +187,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
|
||||||
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
||||||
/// <param name="filters">Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.</param>
|
/// <param name="filters">Optional. Specify additional filters to apply.</param>
|
||||||
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
/// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param>
|
||||||
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
/// <param name="mediaTypes">Optional filter by MediaType. Allows multiple, comma delimited.</param>
|
||||||
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
/// <param name="genres">Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.</param>
|
||||||
|
@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? includeItemTypes,
|
[FromQuery] string? includeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? genres,
|
[FromQuery] string? genres,
|
||||||
|
@ -188,7 +188,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var filter in RequestHelpers.GetFilters(filters))
|
foreach (var filter in filters)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
@ -124,7 +125,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] bool? isHd,
|
[FromQuery] bool? isHd,
|
||||||
[FromQuery] bool? is4K,
|
[FromQuery] bool? is4K,
|
||||||
[FromQuery] string? locationTypes,
|
[FromQuery] string? locationTypes,
|
||||||
[FromQuery] string? excludeLocationTypes,
|
[FromQuery] LocationType[] excludeLocationTypes,
|
||||||
[FromQuery] bool? isMissing,
|
[FromQuery] bool? isMissing,
|
||||||
[FromQuery] bool? isUnaired,
|
[FromQuery] bool? isUnaired,
|
||||||
[FromQuery] double? minCommunityRating,
|
[FromQuery] double? minCommunityRating,
|
||||||
|
@ -146,7 +147,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] string? parentId,
|
[FromQuery] string? parentId,
|
||||||
[FromQuery] string? fields,
|
[FromQuery] string? fields,
|
||||||
[FromQuery] string? excludeItemTypes,
|
[FromQuery] string? excludeItemTypes,
|
||||||
[FromQuery] string? filters,
|
[FromQuery] ItemFilter[] filters,
|
||||||
[FromQuery] bool? isFavorite,
|
[FromQuery] bool? isFavorite,
|
||||||
[FromQuery] string? mediaTypes,
|
[FromQuery] string? mediaTypes,
|
||||||
[FromQuery] string? imageTypes,
|
[FromQuery] string? imageTypes,
|
||||||
|
|
|
@ -56,18 +56,6 @@ namespace Jellyfin.Api.Helpers
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get parsed filters.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filters">The filters.</param>
|
|
||||||
/// <returns>Item filters.</returns>
|
|
||||||
public static IEnumerable<ItemFilter> GetFilters(string? filters)
|
|
||||||
{
|
|
||||||
return string.IsNullOrEmpty(filters)
|
|
||||||
? Array.Empty<ItemFilter>()
|
|
||||||
: filters.Split(',').Select(v => Enum.Parse<ItemFilter>(v, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits a string at a separating character into an array of substrings.
|
/// Splits a string at a separating character into an array of substrings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user