mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Merge remote-tracking branch 'origin/master' into media-attachments-clean
This commit is contained in:
commit
1600d5b53f
@ -245,7 +245,7 @@ jobs:
|
|||||||
inputs:
|
inputs:
|
||||||
targetType: 'filePath' # Optional. Options: filePath, inline
|
targetType: 'filePath' # Optional. Options: filePath, inline
|
||||||
filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
|
filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
|
||||||
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
|
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
|
||||||
#script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
|
#script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
|
||||||
errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
|
errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
|
||||||
#failOnStderr: false # Optional
|
#failOnStderr: false # Optional
|
||||||
|
@ -1,8 +1,59 @@
|
|||||||
srpm:
|
VERSION := $(shell sed -ne '/^Version:/s/.* *//p' \
|
||||||
dnf -y install git
|
deployment/fedora-package-x64/pkg-src/jellyfin.spec)
|
||||||
git submodule update --init --recursive
|
|
||||||
|
deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz:
|
||||||
|
curl -f -L -o deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz \
|
||||||
|
https://github.com/jellyfin/jellyfin-web/archive/v$(VERSION).tar.gz \
|
||||||
|
|| curl -f -L -o deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz \
|
||||||
|
https://github.com/jellyfin/jellyfin-web/archive/master.tar.gz \
|
||||||
|
|
||||||
|
srpm: deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz
|
||||||
cd deployment/fedora-package-x64; \
|
cd deployment/fedora-package-x64; \
|
||||||
./create_tarball.sh; \
|
SOURCE_DIR=../.. \
|
||||||
|
WORKDIR="$${PWD}"; \
|
||||||
|
package_temporary_dir="$${WORKDIR}/pkg-dist-tmp"; \
|
||||||
|
pkg_src_dir="$${WORKDIR}/pkg-src"; \
|
||||||
|
GNU_TAR=1; \
|
||||||
|
tar \
|
||||||
|
--transform "s,^\.,jellyfin-$(VERSION)," \
|
||||||
|
--exclude='.git*' \
|
||||||
|
--exclude='**/.git' \
|
||||||
|
--exclude='**/.hg' \
|
||||||
|
--exclude='**/.vs' \
|
||||||
|
--exclude='**/.vscode' \
|
||||||
|
--exclude='deployment' \
|
||||||
|
--exclude='**/bin' \
|
||||||
|
--exclude='**/obj' \
|
||||||
|
--exclude='**/.nuget' \
|
||||||
|
--exclude='*.deb' \
|
||||||
|
--exclude='*.rpm' \
|
||||||
|
-czf "pkg-src/jellyfin-$(VERSION).tar.gz" \
|
||||||
|
-C $${SOURCE_DIR} ./ || GNU_TAR=0; \
|
||||||
|
if [ $${GNU_TAR} -eq 0 ]; then \
|
||||||
|
package_temporary_dir="$$(mktemp -d)"; \
|
||||||
|
mkdir -p "$${package_temporary_dir}/jellyfin"; \
|
||||||
|
tar \
|
||||||
|
--exclude='.git*' \
|
||||||
|
--exclude='**/.git' \
|
||||||
|
--exclude='**/.hg' \
|
||||||
|
--exclude='**/.vs' \
|
||||||
|
--exclude='**/.vscode' \
|
||||||
|
--exclude='deployment' \
|
||||||
|
--exclude='**/bin' \
|
||||||
|
--exclude='**/obj' \
|
||||||
|
--exclude='**/.nuget' \
|
||||||
|
--exclude='*.deb' \
|
||||||
|
--exclude='*.rpm' \
|
||||||
|
-czf "$${package_temporary_dir}/jellyfin/jellyfin-$(VERSION).tar.gz" \
|
||||||
|
-C $${SOURCE_DIR} ./; \
|
||||||
|
mkdir -p "$${package_temporary_dir}/jellyfin-$(VERSION)"; \
|
||||||
|
tar -xzf "$${package_temporary_dir}/jellyfin/jellyfin-$(VERSION).tar.gz" \
|
||||||
|
-C "$${package_temporary_dir}/jellyfin-$(VERSION); \
|
||||||
|
rm -f "$${package_temporary_dir}/jellyfin/jellyfin-$(VERSION).tar.gz"; \
|
||||||
|
tar -czf "$${SOURCE_DIR}/SOURCES/pkg-src/jellyfin-$(VERSION).tar.gz" \
|
||||||
|
-C "$${package_temporary_dir}" "jellyfin-$(VERSION); \
|
||||||
|
rm -rf $${package_temporary_dir}; \
|
||||||
|
fi; \
|
||||||
rpmbuild -bs pkg-src/jellyfin.spec \
|
rpmbuild -bs pkg-src/jellyfin.spec \
|
||||||
--define "_sourcedir $$PWD/pkg-src/" \
|
--define "_sourcedir $$PWD/pkg-src/" \
|
||||||
--define "_srcrpmdir $(outdir)"
|
--define "_srcrpmdir $(outdir)"
|
||||||
|
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@ -11,6 +11,7 @@ exemptLabels:
|
|||||||
- future
|
- future
|
||||||
- feature
|
- feature
|
||||||
- enhancement
|
- enhancement
|
||||||
|
- confirmed
|
||||||
# Label to use when marking an issue as stale
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: stale
|
staleLabel: stale
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -268,3 +268,6 @@ doc/
|
|||||||
# Deployment artifacts
|
# Deployment artifacts
|
||||||
dist
|
dist
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
# BenchmarkDotNet artifacts
|
||||||
|
BenchmarkDotNet.Artifacts
|
||||||
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -10,7 +10,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp2.1/jellyfin.dll",
|
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.0/jellyfin.dll",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
||||||
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
|
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
|
||||||
|
22
Dockerfile
22
Dockerfile
@ -1,8 +1,8 @@
|
|||||||
ARG DOTNET_VERSION=2.2
|
ARG DOTNET_VERSION=3.0
|
||||||
ARG FFMPEG_VERSION=latest
|
ARG FFMPEG_VERSION=latest
|
||||||
|
|
||||||
FROM node:alpine as web-builder
|
FROM node:alpine as web-builder
|
||||||
ARG JELLYFIN_WEB_VERSION=v10.5.0
|
ARG JELLYFIN_WEB_VERSION=master
|
||||||
RUN apk add curl \
|
RUN apk add curl \
|
||||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||||
&& cd jellyfin-web-* \
|
&& cd jellyfin-web-* \
|
||||||
@ -10,33 +10,39 @@ RUN apk add curl \
|
|||||||
&& yarn build \
|
&& yarn build \
|
||||||
&& mv dist /dist
|
&& mv dist /dist
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION}-buster as builder
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||||
|
|
||||||
FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
|
FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
|
||||||
|
FROM debian:buster-slim
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}
|
COPY --from=ffmpeg /opt/ffmpeg /opt/ffmpeg
|
||||||
COPY --from=ffmpeg / /
|
|
||||||
COPY --from=builder /jellyfin /jellyfin
|
COPY --from=builder /jellyfin /jellyfin
|
||||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||||
# Install dependencies:
|
# Install dependencies:
|
||||||
# libfontconfig1: needed for Skia
|
# libfontconfig1: needed for Skia
|
||||||
|
# libgomp1: needed for ffmpeg
|
||||||
|
# libva-drm2: needed for ffmpeg
|
||||||
# mesa-va-drivers: needed for VAAPI
|
# mesa-va-drivers: needed for VAAPI
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||||
libfontconfig1 mesa-va-drivers \
|
libfontconfig1 libgomp1 libva-drm2 mesa-va-drivers openssl \
|
||||||
&& apt-get clean autoclean \
|
&& apt-get clean autoclean \
|
||||||
&& apt-get autoremove \
|
&& apt-get autoremove \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& mkdir -p /cache /config /media \
|
&& mkdir -p /cache /config /media \
|
||||||
&& chmod 777 /cache /config /media
|
&& chmod 777 /cache /config /media \
|
||||||
|
&& ln -s /opt/ffmpeg/bin/ffmpeg /usr/local/bin \
|
||||||
|
&& ln -s /opt/ffmpeg/bin/ffprobe /usr/local/bin
|
||||||
|
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||||
|
|
||||||
EXPOSE 8096
|
EXPOSE 8096
|
||||||
VOLUME /cache /config /media
|
VOLUME /cache /config /media
|
||||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
ENTRYPOINT ./jellyfin/jellyfin \
|
||||||
--datadir /config \
|
--datadir /config \
|
||||||
--cachedir /cache \
|
--cachedir /cache \
|
||||||
--ffmpeg /usr/local/bin/ffmpeg
|
--ffmpeg /usr/local/bin/ffmpeg
|
||||||
|
@ -4,7 +4,7 @@ ARG DOTNET_VERSION=3.0
|
|||||||
|
|
||||||
|
|
||||||
FROM node:alpine as web-builder
|
FROM node:alpine as web-builder
|
||||||
ARG JELLYFIN_WEB_VERSION=v10.5.0
|
ARG JELLYFIN_WEB_VERSION=master
|
||||||
RUN apk add curl \
|
RUN apk add curl \
|
||||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||||
&& cd jellyfin-web-* \
|
&& cd jellyfin-web-* \
|
||||||
@ -17,8 +17,6 @@ FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
|||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
# TODO Remove or update the sed line when we update dotnet version.
|
|
||||||
RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
|
|
||||||
# Discard objs - may cause failures if exists
|
# Discard objs - may cause failures if exists
|
||||||
RUN find . -type d -name obj | xargs -r rm -r
|
RUN find . -type d -name obj | xargs -r rm -r
|
||||||
# Build
|
# Build
|
||||||
@ -26,7 +24,7 @@ RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin"
|
|||||||
|
|
||||||
|
|
||||||
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
||||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm32v7
|
FROM debian:stretch-slim-arm32v7
|
||||||
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||||
@ -36,9 +34,11 @@ RUN apt-get update \
|
|||||||
COPY --from=builder /jellyfin /jellyfin
|
COPY --from=builder /jellyfin /jellyfin
|
||||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||||
|
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||||
|
|
||||||
EXPOSE 8096
|
EXPOSE 8096
|
||||||
VOLUME /cache /config /media
|
VOLUME /cache /config /media
|
||||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
ENTRYPOINT ./jellyfin/jellyfin \
|
||||||
--datadir /config \
|
--datadir /config \
|
||||||
--cachedir /cache \
|
--cachedir /cache \
|
||||||
--ffmpeg /usr/bin/ffmpeg
|
--ffmpeg /usr/bin/ffmpeg
|
||||||
|
@ -4,7 +4,7 @@ ARG DOTNET_VERSION=3.0
|
|||||||
|
|
||||||
|
|
||||||
FROM node:alpine as web-builder
|
FROM node:alpine as web-builder
|
||||||
ARG JELLYFIN_WEB_VERSION=v10.5.0
|
ARG JELLYFIN_WEB_VERSION=master
|
||||||
RUN apk add curl \
|
RUN apk add curl \
|
||||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||||
&& cd jellyfin-web-* \
|
&& cd jellyfin-web-* \
|
||||||
@ -17,8 +17,6 @@ FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
|||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
# TODO Remove or update the sed line when we update dotnet version.
|
|
||||||
RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
|
|
||||||
# Discard objs - may cause failures if exists
|
# Discard objs - may cause failures if exists
|
||||||
RUN find . -type d -name obj | xargs -r rm -r
|
RUN find . -type d -name obj | xargs -r rm -r
|
||||||
# Build
|
# Build
|
||||||
@ -26,7 +24,7 @@ RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin"
|
|||||||
|
|
||||||
|
|
||||||
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
||||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm64v8
|
FROM debian:stretch-slim-arm64v8
|
||||||
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||||
@ -36,9 +34,11 @@ RUN apt-get update \
|
|||||||
COPY --from=builder /jellyfin /jellyfin
|
COPY --from=builder /jellyfin /jellyfin
|
||||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||||
|
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||||
|
|
||||||
EXPOSE 8096
|
EXPOSE 8096
|
||||||
VOLUME /cache /config /media
|
VOLUME /cache /config /media
|
||||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
ENTRYPOINT ./jellyfin/jellyfin \
|
||||||
--datadir /config \
|
--datadir /config \
|
||||||
--cachedir /cache \
|
--cachedir /cache \
|
||||||
--ffmpeg /usr/bin/ffmpeg
|
--ffmpeg /usr/bin/ffmpeg
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
@ -17,9 +17,4 @@
|
|||||||
<Compile Include="..\SharedVersion.cs" />
|
<Compile Include="..\SharedVersion.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- We need at least C# 7.1 for the "default literal" feature-->
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -24,8 +24,9 @@
|
|||||||
<!-- Code analysers-->
|
<!-- Code analysers-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" />
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
||||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
||||||
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.AppBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _configuration sync lock.
|
/// The _configuration sync lock.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _configurationSyncLock = new object();
|
private readonly object _configurationSyncLock = new object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _configuration.
|
/// The _configuration.
|
||||||
@ -98,17 +98,32 @@ namespace Emby.Server.Implementations.AppBase
|
|||||||
public IApplicationPaths CommonApplicationPaths { get; private set; }
|
public IApplicationPaths CommonApplicationPaths { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the system configuration
|
/// Gets the system configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The configuration.</value>
|
/// <value>The configuration.</value>
|
||||||
public BaseApplicationConfiguration CommonConfiguration
|
public BaseApplicationConfiguration CommonConfiguration
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// Lazy load
|
if (_configurationLoaded)
|
||||||
LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer));
|
{
|
||||||
return _configuration;
|
return _configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock (_configurationSyncLock)
|
||||||
|
{
|
||||||
|
if (_configurationLoaded)
|
||||||
|
{
|
||||||
|
return _configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
_configuration = (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer);
|
||||||
|
|
||||||
|
_configurationLoaded = true;
|
||||||
|
|
||||||
|
return _configuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
protected set
|
protected set
|
||||||
{
|
{
|
||||||
_configuration = value;
|
_configuration = value;
|
||||||
|
@ -364,7 +364,7 @@ namespace Emby.Server.Implementations
|
|||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
|
|
||||||
XmlSerializer = new MyXmlSerializer(fileSystem, loggerFactory);
|
XmlSerializer = new MyXmlSerializer();
|
||||||
|
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
|
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
|
||||||
@ -912,7 +912,7 @@ namespace Emby.Server.Implementations
|
|||||||
|
|
||||||
_displayPreferencesRepository.Initialize();
|
_displayPreferencesRepository.Initialize();
|
||||||
|
|
||||||
var userDataRepo = new SqliteUserDataRepository(LoggerFactory, ApplicationPaths);
|
var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger<SqliteUserDataRepository>(), ApplicationPaths);
|
||||||
|
|
||||||
SetStaticProperties();
|
SetStaticProperties();
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ namespace Emby.Server.Implementations.Channels
|
|||||||
_libraryManager.CreateItem(item, null);
|
_libraryManager.CreateItem(item, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
await item.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
await item.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
ForceSave = !isNew && forceUpdate
|
ForceSave = !isNew && forceUpdate
|
||||||
}, cancellationToken);
|
}, cancellationToken);
|
||||||
@ -1156,7 +1156,7 @@ namespace Emby.Server.Implementations.Channels
|
|||||||
|
|
||||||
if (isNew || forceUpdate || item.DateLastRefreshed == default(DateTime))
|
if (isNew || forceUpdate || item.DateLastRefreshed == default(DateTime))
|
||||||
{
|
{
|
||||||
_providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), RefreshPriority.Normal);
|
_providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.Collections
|
|||||||
|
|
||||||
if (options.ItemIdList.Length > 0)
|
if (options.ItemIdList.Length > 0)
|
||||||
{
|
{
|
||||||
AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
// The initial adding of items is going to create a local metadata file
|
// The initial adding of items is going to create a local metadata file
|
||||||
// This will cause internet metadata to be skipped as a result
|
// This will cause internet metadata to be skipped as a result
|
||||||
@ -158,7 +158,7 @@ namespace Emby.Server.Implementations.Collections
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), RefreshPriority.High);
|
_providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionCreated?.Invoke(this, new CollectionCreatedEventArgs
|
CollectionCreated?.Invoke(this, new CollectionCreatedEventArgs
|
||||||
@ -178,12 +178,12 @@ namespace Emby.Server.Implementations.Collections
|
|||||||
|
|
||||||
public void AddToCollection(Guid collectionId, IEnumerable<string> ids)
|
public void AddToCollection(Guid collectionId, IEnumerable<string> ids)
|
||||||
{
|
{
|
||||||
AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)));
|
AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(new DirectoryService(_fileSystem)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
|
public void AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
|
||||||
{
|
{
|
||||||
AddToCollection(collectionId, ids.Select(i => i.ToString("N", CultureInfo.InvariantCulture)), true, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)));
|
AddToCollection(collectionId, ids.Select(i => i.ToString("N", CultureInfo.InvariantCulture)), true, new MetadataRefreshOptions(new DirectoryService(_fileSystem)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
|
private void AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
|
||||||
@ -287,7 +287,7 @@ namespace Emby.Server.Implementations.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
|
collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
|
||||||
_providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
_providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
}, RefreshPriority.High);
|
}, RefreshPriority.High);
|
||||||
|
@ -110,8 +110,8 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
|
using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@id", displayPreferences.Id.ToGuidBlob());
|
statement.TryBind("@id", new Guid(displayPreferences.Id).ToByteArray());
|
||||||
statement.TryBind("@userId", userId.ToGuidBlob());
|
statement.TryBind("@userId", userId.ToByteArray());
|
||||||
statement.TryBind("@client", client);
|
statement.TryBind("@client", client);
|
||||||
statement.TryBind("@data", serialized);
|
statement.TryBind("@data", serialized);
|
||||||
|
|
||||||
@ -170,8 +170,8 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
|
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@id", guidId.ToGuidBlob());
|
statement.TryBind("@id", guidId.ToByteArray());
|
||||||
statement.TryBind("@userId", userId.ToGuidBlob());
|
statement.TryBind("@userId", userId.ToByteArray());
|
||||||
statement.TryBind("@client", client);
|
statement.TryBind("@client", client);
|
||||||
|
|
||||||
foreach (var row in statement.ExecuteQuery())
|
foreach (var row in statement.ExecuteQuery())
|
||||||
@ -200,7 +200,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
using (var connection = GetConnection(true))
|
using (var connection = GetConnection(true))
|
||||||
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
|
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@userId", userId.ToGuidBlob());
|
statement.TryBind("@userId", userId.ToByteArray());
|
||||||
|
|
||||||
foreach (var row in statement.ExecuteQuery())
|
foreach (var row in statement.ExecuteQuery())
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,47 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
public static class SqliteExtensions
|
public static class SqliteExtensions
|
||||||
{
|
{
|
||||||
|
private const string DatetimeFormatUtc = "yyyy-MM-dd HH:mm:ss.FFFFFFFK";
|
||||||
|
private const string DatetimeFormatLocal = "yyyy-MM-dd HH:mm:ss.FFFFFFF";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An array of ISO-8601 DateTime formats that we support parsing.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string[] _datetimeFormats = new string[]
|
||||||
|
{
|
||||||
|
"THHmmssK",
|
||||||
|
"THHmmK",
|
||||||
|
"HH:mm:ss.FFFFFFFK",
|
||||||
|
"HH:mm:ssK",
|
||||||
|
"HH:mmK",
|
||||||
|
DatetimeFormatUtc,
|
||||||
|
"yyyy-MM-dd HH:mm:ssK",
|
||||||
|
"yyyy-MM-dd HH:mmK",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
|
||||||
|
"yyyy-MM-ddTHH:mmK",
|
||||||
|
"yyyy-MM-ddTHH:mm:ssK",
|
||||||
|
"yyyyMMddHHmmssK",
|
||||||
|
"yyyyMMddHHmmK",
|
||||||
|
"yyyyMMddTHHmmssFFFFFFFK",
|
||||||
|
"THHmmss",
|
||||||
|
"THHmm",
|
||||||
|
"HH:mm:ss.FFFFFFF",
|
||||||
|
"HH:mm:ss",
|
||||||
|
"HH:mm",
|
||||||
|
DatetimeFormatLocal,
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
"yyyy-MM-dd HH:mm",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss.FFFFFFF",
|
||||||
|
"yyyy-MM-ddTHH:mm",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss",
|
||||||
|
"yyyyMMddHHmmss",
|
||||||
|
"yyyyMMddHHmm",
|
||||||
|
"yyyyMMddTHHmmssFFFFFFF",
|
||||||
|
"yyyy-MM-dd",
|
||||||
|
"yyyyMMdd",
|
||||||
|
"yy-MM-dd"
|
||||||
|
};
|
||||||
|
|
||||||
public static void RunQueries(this SQLiteDatabaseConnection connection, string[] queries)
|
public static void RunQueries(this SQLiteDatabaseConnection connection, string[] queries)
|
||||||
{
|
{
|
||||||
if (queries == null)
|
if (queries == null)
|
||||||
@ -22,16 +63,6 @@ namespace Emby.Server.Implementations.Data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] ToGuidBlob(this string str)
|
|
||||||
{
|
|
||||||
return ToGuidBlob(new Guid(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] ToGuidBlob(this Guid guid)
|
|
||||||
{
|
|
||||||
return guid.ToByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Guid ReadGuidFromBlob(this IResultSetValue result)
|
public static Guid ReadGuidFromBlob(this IResultSetValue result)
|
||||||
{
|
{
|
||||||
return new Guid(result.ToBlob());
|
return new Guid(result.ToBlob());
|
||||||
@ -50,58 +81,16 @@ namespace Emby.Server.Implementations.Data
|
|||||||
CultureInfo.InvariantCulture);
|
CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDateTimeKindFormat(
|
private static string GetDateTimeKindFormat(DateTimeKind kind)
|
||||||
DateTimeKind kind)
|
=> (kind == DateTimeKind.Utc) ? DatetimeFormatUtc : DatetimeFormatLocal;
|
||||||
{
|
|
||||||
return (kind == DateTimeKind.Utc) ? _datetimeFormatUtc : _datetimeFormatLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An array of ISO-8601 DateTime formats that we support parsing.
|
|
||||||
/// </summary>
|
|
||||||
private static string[] _datetimeFormats = new string[] {
|
|
||||||
"THHmmssK",
|
|
||||||
"THHmmK",
|
|
||||||
"HH:mm:ss.FFFFFFFK",
|
|
||||||
"HH:mm:ssK",
|
|
||||||
"HH:mmK",
|
|
||||||
"yyyy-MM-dd HH:mm:ss.FFFFFFFK", /* NOTE: UTC default (5). */
|
|
||||||
"yyyy-MM-dd HH:mm:ssK",
|
|
||||||
"yyyy-MM-dd HH:mmK",
|
|
||||||
"yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
|
|
||||||
"yyyy-MM-ddTHH:mmK",
|
|
||||||
"yyyy-MM-ddTHH:mm:ssK",
|
|
||||||
"yyyyMMddHHmmssK",
|
|
||||||
"yyyyMMddHHmmK",
|
|
||||||
"yyyyMMddTHHmmssFFFFFFFK",
|
|
||||||
"THHmmss",
|
|
||||||
"THHmm",
|
|
||||||
"HH:mm:ss.FFFFFFF",
|
|
||||||
"HH:mm:ss",
|
|
||||||
"HH:mm",
|
|
||||||
"yyyy-MM-dd HH:mm:ss.FFFFFFF", /* NOTE: Non-UTC default (19). */
|
|
||||||
"yyyy-MM-dd HH:mm:ss",
|
|
||||||
"yyyy-MM-dd HH:mm",
|
|
||||||
"yyyy-MM-ddTHH:mm:ss.FFFFFFF",
|
|
||||||
"yyyy-MM-ddTHH:mm",
|
|
||||||
"yyyy-MM-ddTHH:mm:ss",
|
|
||||||
"yyyyMMddHHmmss",
|
|
||||||
"yyyyMMddHHmm",
|
|
||||||
"yyyyMMddTHHmmssFFFFFFF",
|
|
||||||
"yyyy-MM-dd",
|
|
||||||
"yyyyMMdd",
|
|
||||||
"yy-MM-dd"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static string _datetimeFormatUtc = _datetimeFormats[5];
|
|
||||||
private static string _datetimeFormatLocal = _datetimeFormats[19];
|
|
||||||
|
|
||||||
public static DateTime ReadDateTime(this IResultSetValue result)
|
public static DateTime ReadDateTime(this IResultSetValue result)
|
||||||
{
|
{
|
||||||
var dateText = result.ToString();
|
var dateText = result.ToString();
|
||||||
|
|
||||||
return DateTime.ParseExact(
|
return DateTime.ParseExact(
|
||||||
dateText, _datetimeFormats,
|
dateText,
|
||||||
|
_datetimeFormats,
|
||||||
DateTimeFormatInfo.InvariantInfo,
|
DateTimeFormatInfo.InvariantInfo,
|
||||||
DateTimeStyles.None).ToUniversalTime();
|
DateTimeStyles.None).ToUniversalTime();
|
||||||
}
|
}
|
||||||
@ -139,7 +128,10 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
public static void Attach(SQLiteDatabaseConnection db, string path, string alias)
|
public static void Attach(SQLiteDatabaseConnection db, string path, string alias)
|
||||||
{
|
{
|
||||||
var commandText = string.Format("attach @path as {0};", alias);
|
var commandText = string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"attach @path as {0};",
|
||||||
|
alias);
|
||||||
|
|
||||||
using (var statement = db.PrepareStatement(commandText))
|
using (var statement = db.PrepareStatement(commandText))
|
||||||
{
|
{
|
||||||
@ -186,10 +178,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
private static void CheckName(string name)
|
private static void CheckName(string name)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//if (!name.IndexOf("@", StringComparison.OrdinalIgnoreCase) != 0)
|
throw new ArgumentException("Invalid param name: " + name, nameof(name));
|
||||||
{
|
|
||||||
throw new Exception("Invalid param name: " + name);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +253,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam))
|
if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam))
|
||||||
{
|
{
|
||||||
bindParam.Bind(value.ToGuidBlob());
|
bindParam.Bind(value.ToByteArray());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -392,8 +381,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<IReadOnlyList<IResultSetValue>> ExecuteQuery(
|
public static IEnumerable<IReadOnlyList<IResultSetValue>> ExecuteQuery(this IStatement This)
|
||||||
this IStatement This)
|
|
||||||
{
|
{
|
||||||
while (This.MoveNext())
|
while (This.MoveNext())
|
||||||
{
|
{
|
||||||
|
@ -563,7 +563,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
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"))
|
||||||
{
|
{
|
||||||
saveImagesStatement.TryBind("@Id", item.Id.ToGuidBlob());
|
saveImagesStatement.TryBind("@Id", item.Id.ToByteArray());
|
||||||
saveImagesStatement.TryBind("@Images", SerializeImages(item));
|
saveImagesStatement.TryBind("@Images", SerializeImages(item));
|
||||||
|
|
||||||
saveImagesStatement.MoveNext();
|
saveImagesStatement.MoveNext();
|
||||||
@ -2003,7 +2003,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
throw new ArgumentNullException(nameof(chapters));
|
throw new ArgumentNullException(nameof(chapters));
|
||||||
}
|
}
|
||||||
|
|
||||||
var idBlob = id.ToGuidBlob();
|
var idBlob = id.ToByteArray();
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
using (var connection = GetConnection())
|
||||||
{
|
{
|
||||||
@ -3782,7 +3782,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, personId.ToGuidBlob());
|
statement.TryBind(paramName, personId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -3993,7 +3993,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
|
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, artistId.ToGuidBlob());
|
statement.TryBind(paramName, artistId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4012,7 +4012,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
|
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, artistId.ToGuidBlob());
|
statement.TryBind(paramName, artistId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4031,7 +4031,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type=1))");
|
clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type=1))");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, artistId.ToGuidBlob());
|
statement.TryBind(paramName, artistId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4050,7 +4050,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
|
clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, albumId.ToGuidBlob());
|
statement.TryBind(paramName, albumId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4069,7 +4069,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
clauses.Add("(guid not in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
|
clauses.Add("(guid not in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, artistId.ToGuidBlob());
|
statement.TryBind(paramName, artistId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4088,7 +4088,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
|
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, genreId.ToGuidBlob());
|
statement.TryBind(paramName, genreId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4159,7 +4159,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind(paramName, studioId.ToGuidBlob());
|
statement.TryBind(paramName, studioId.ToByteArray());
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4935,7 +4935,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(db =>
|
||||||
{
|
{
|
||||||
var idBlob = id.ToGuidBlob();
|
var idBlob = id.ToByteArray();
|
||||||
|
|
||||||
// Delete people
|
// Delete people
|
||||||
ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", idBlob);
|
ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", idBlob);
|
||||||
@ -5054,7 +5054,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
whereClauses.Add("ItemId=@ItemId");
|
whereClauses.Add("ItemId=@ItemId");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
|
statement.TryBind("@ItemId", query.ItemId.ToByteArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!query.AppearsInItemId.Equals(Guid.Empty))
|
if (!query.AppearsInItemId.Equals(Guid.Empty))
|
||||||
@ -5062,7 +5062,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
|
whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
|
||||||
if (statement != null)
|
if (statement != null)
|
||||||
{
|
{
|
||||||
statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidBlob());
|
statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
|
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
|
||||||
@ -5131,7 +5131,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
var itemIdBlob = itemId.ToGuidBlob();
|
var itemIdBlob = itemId.ToByteArray();
|
||||||
|
|
||||||
// First delete
|
// First delete
|
||||||
deleteAncestorsStatement.Reset();
|
deleteAncestorsStatement.Reset();
|
||||||
@ -5165,7 +5165,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
var ancestorId = ancestorIds[i];
|
var ancestorId = ancestorIds[i];
|
||||||
|
|
||||||
statement.TryBind("@AncestorId" + index, ancestorId.ToGuidBlob());
|
statement.TryBind("@AncestorId" + index, ancestorId.ToByteArray());
|
||||||
statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture));
|
statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5630,7 +5630,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
var guidBlob = itemId.ToGuidBlob();
|
var guidBlob = itemId.ToByteArray();
|
||||||
|
|
||||||
// First delete
|
// First delete
|
||||||
db.Execute("delete from ItemValues where ItemId=@Id", guidBlob);
|
db.Execute("delete from ItemValues where ItemId=@Id", guidBlob);
|
||||||
@ -5654,10 +5654,13 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
{
|
{
|
||||||
if (isSubsequentRow)
|
if (isSubsequentRow)
|
||||||
{
|
{
|
||||||
insertText.Append(",");
|
insertText.Append(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
insertText.AppendFormat("(@ItemId, @Type{0}, @Value{0}, @CleanValue{0})", i.ToString(CultureInfo.InvariantCulture));
|
insertText.AppendFormat(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"(@ItemId, @Type{0}, @Value{0}, @CleanValue{0})",
|
||||||
|
i);
|
||||||
isSubsequentRow = true;
|
isSubsequentRow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5710,7 +5713,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(db =>
|
||||||
{
|
{
|
||||||
var itemIdBlob = itemId.ToGuidBlob();
|
var itemIdBlob = itemId.ToByteArray();
|
||||||
|
|
||||||
// First delete chapters
|
// First delete chapters
|
||||||
db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
|
db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
|
||||||
@ -5829,7 +5832,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
using (var statement = PrepareStatement(connection, cmdText))
|
using (var statement = PrepareStatement(connection, cmdText))
|
||||||
{
|
{
|
||||||
statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
|
statement.TryBind("@ItemId", query.ItemId.ToByteArray());
|
||||||
|
|
||||||
if (query.Type.HasValue)
|
if (query.Type.HasValue)
|
||||||
{
|
{
|
||||||
@ -5871,7 +5874,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
{
|
{
|
||||||
connection.RunInTransaction(db =>
|
connection.RunInTransaction(db =>
|
||||||
{
|
{
|
||||||
var itemIdBlob = id.ToGuidBlob();
|
var itemIdBlob = id.ToByteArray();
|
||||||
|
|
||||||
// First delete chapters
|
// First delete chapters
|
||||||
db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
|
db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
@ -15,23 +14,19 @@ namespace Emby.Server.Implementations.Data
|
|||||||
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
|
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
|
||||||
{
|
{
|
||||||
public SqliteUserDataRepository(
|
public SqliteUserDataRepository(
|
||||||
ILoggerFactory loggerFactory,
|
ILogger<SqliteUserDataRepository> logger,
|
||||||
IApplicationPaths appPaths)
|
IApplicationPaths appPaths)
|
||||||
: base(loggerFactory.CreateLogger(nameof(SqliteUserDataRepository)))
|
: base(logger)
|
||||||
{
|
{
|
||||||
DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
|
DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets the name of the repository
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The name.</value>
|
|
||||||
public string Name => "SQLite";
|
public string Name => "SQLite";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the connection to the database
|
/// Opens the connection to the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task.</returns>
|
|
||||||
public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection)
|
public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection)
|
||||||
{
|
{
|
||||||
WriteLock.Dispose();
|
WriteLock.Dispose();
|
||||||
@ -97,7 +92,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
statement.TryBind("@UserId", user.Id.ToGuidBlob());
|
statement.TryBind("@UserId", user.Id.ToByteArray());
|
||||||
statement.TryBind("@InternalUserId", user.InternalId);
|
statement.TryBind("@InternalUserId", user.InternalId);
|
||||||
|
|
||||||
statement.MoveNext();
|
statement.MoveNext();
|
||||||
|
@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
|
using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@guid", user.Id.ToGuidBlob());
|
statement.TryBind("@guid", user.Id.ToByteArray());
|
||||||
statement.TryBind("@data", serialized);
|
statement.TryBind("@data", serialized);
|
||||||
|
|
||||||
statement.MoveNext();
|
statement.MoveNext();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" />
|
<ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" />
|
||||||
@ -29,9 +29,9 @@
|
|||||||
<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.Logging" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.0" />
|
||||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.6.0" />
|
<PackageReference Include="ServiceStack.Text.Core" Version="5.6.0" />
|
||||||
<PackageReference Include="sharpcompress" Version="0.24.0" />
|
<PackageReference Include="sharpcompress" Version="0.24.0" />
|
||||||
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.0.1" />
|
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.0.1" />
|
||||||
@ -47,16 +47,12 @@
|
|||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- We need at least C# 7.3 to compare tuples-->
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<!-- Code analysers-->
|
<!-- Code analysers-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" />
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
||||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
||||||
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
@ -27,6 +27,11 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
private NatManager _natManager;
|
private NatManager _natManager;
|
||||||
|
|
||||||
|
private readonly object _createdRulesLock = new object();
|
||||||
|
private List<string> _createdRules = new List<string>();
|
||||||
|
private readonly object _usnsHandledLock = new object();
|
||||||
|
private List<string> _usnsHandled = new List<string>();
|
||||||
|
|
||||||
public ExternalPortForwarding(ILoggerFactory loggerFactory, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient)
|
public ExternalPortForwarding(ILoggerFactory loggerFactory, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory.CreateLogger("PortMapper");
|
_logger = loggerFactory.CreateLogger("PortMapper");
|
||||||
@ -127,12 +132,13 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (_usnsHandled)
|
lock (_usnsHandledLock)
|
||||||
{
|
{
|
||||||
if (_usnsHandled.Contains(identifier))
|
if (_usnsHandled.Contains(identifier))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_usnsHandled.Add(identifier);
|
_usnsHandled.Add(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,11 +192,12 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
private void ClearCreatedRules(object state)
|
private void ClearCreatedRules(object state)
|
||||||
{
|
{
|
||||||
lock (_createdRules)
|
lock (_createdRulesLock)
|
||||||
{
|
{
|
||||||
_createdRules.Clear();
|
_createdRules.Clear();
|
||||||
}
|
}
|
||||||
lock (_usnsHandled)
|
|
||||||
|
lock (_usnsHandledLock)
|
||||||
{
|
{
|
||||||
_usnsHandled.Clear();
|
_usnsHandled.Clear();
|
||||||
}
|
}
|
||||||
@ -216,8 +223,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> _createdRules = new List<string>();
|
|
||||||
private List<string> _usnsHandled = new List<string>();
|
|
||||||
private async void CreateRules(INatDevice device)
|
private async void CreateRules(INatDevice device)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@ -231,7 +236,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
|
|
||||||
var addressString = address.ToString();
|
var addressString = address.ToString();
|
||||||
|
|
||||||
lock (_createdRules)
|
lock (_createdRulesLock)
|
||||||
{
|
{
|
||||||
if (!_createdRules.Contains(addressString))
|
if (!_createdRules.Contains(addressString))
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), cancellationToken).ConfigureAwait(false);
|
await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,6 +539,11 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
if (httpRes.StatusCode >= 500)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Sending HTTP Response 500 in response to {Url}", urlToLog);
|
||||||
|
}
|
||||||
|
|
||||||
stopWatch.Stop();
|
stopWatch.Stop();
|
||||||
var elapsed = stopWatch.Elapsed;
|
var elapsed = stopWatch.Elapsed;
|
||||||
if (elapsed.TotalMilliseconds > 500)
|
if (elapsed.TotalMilliseconds > 500)
|
||||||
|
@ -2,11 +2,11 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Common.Cryptography;
|
using MediaBrowser.Common.Cryptography;
|
||||||
using MediaBrowser.Controller.Authentication;
|
using MediaBrowser.Controller.Authentication;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Model.Cryptography;
|
using MediaBrowser.Model.Cryptography;
|
||||||
using static MediaBrowser.Common.HexHelper;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Library
|
namespace Emby.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(user.EasyPassword)
|
return string.IsNullOrEmpty(user.EasyPassword)
|
||||||
? null
|
? null
|
||||||
: ToHexString(PasswordHash.Parse(user.EasyPassword).Hash);
|
: Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Authentication;
|
using MediaBrowser.Controller.Authentication;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Net;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Library
|
namespace Emby.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
|
@ -519,7 +519,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null)
|
public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null)
|
||||||
=> ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent);
|
=> ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent);
|
||||||
|
|
||||||
private BaseItem ResolvePath(
|
private BaseItem ResolvePath(
|
||||||
FileSystemMetadata fileInfo,
|
FileSystemMetadata fileInfo,
|
||||||
@ -1045,7 +1045,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
await RootFolder.ValidateChildren(
|
await RootFolder.ValidateChildren(
|
||||||
new SimpleProgress<double>(),
|
new SimpleProgress<double>(),
|
||||||
cancellationToken,
|
cancellationToken,
|
||||||
new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)),
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem)),
|
||||||
recursive: false).ConfigureAwait(false);
|
recursive: false).ConfigureAwait(false);
|
||||||
|
|
||||||
await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||||
@ -1053,7 +1053,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
await GetUserRootFolder().ValidateChildren(
|
await GetUserRootFolder().ValidateChildren(
|
||||||
new SimpleProgress<double>(),
|
new SimpleProgress<double>(),
|
||||||
cancellationToken,
|
cancellationToken,
|
||||||
new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)),
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem)),
|
||||||
recursive: false).ConfigureAwait(false);
|
recursive: false).ConfigureAwait(false);
|
||||||
|
|
||||||
// Quickly scan CollectionFolders for changes
|
// Quickly scan CollectionFolders for changes
|
||||||
@ -1074,7 +1074,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
innerProgress.RegisterAction(pct => progress.Report(pct * .96));
|
innerProgress.RegisterAction(pct => progress.Report(pct * .96));
|
||||||
|
|
||||||
// Now validate the entire media library
|
// Now validate the entire media library
|
||||||
await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), recursive: true).ConfigureAwait(false);
|
await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), recursive: true).ConfigureAwait(false);
|
||||||
|
|
||||||
progress.Report(96);
|
progress.Report(96);
|
||||||
|
|
||||||
@ -2135,7 +2135,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
if (refresh)
|
if (refresh)
|
||||||
{
|
{
|
||||||
item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
|
item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
|
||||||
_providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), RefreshPriority.Normal);
|
_providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@ -2193,7 +2193,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
_providerManagerFactory().QueueRefresh(
|
_providerManagerFactory().QueueRefresh(
|
||||||
item.Id,
|
item.Id,
|
||||||
new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
// Need to force save to increment DateLastSaved
|
// Need to force save to increment DateLastSaved
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
@ -2261,7 +2261,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
_providerManagerFactory().QueueRefresh(
|
_providerManagerFactory().QueueRefresh(
|
||||||
item.Id,
|
item.Id,
|
||||||
new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
// Need to force save to increment DateLastSaved
|
// Need to force save to increment DateLastSaved
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
@ -2338,7 +2338,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
_providerManagerFactory().QueueRefresh(
|
_providerManagerFactory().QueueRefresh(
|
||||||
item.Id,
|
item.Id,
|
||||||
new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
// Need to force save to increment DateLastSaved
|
// Need to force save to increment DateLastSaved
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
|
@ -160,12 +160,13 @@ namespace Emby.Server.Implementations.Library
|
|||||||
|
|
||||||
if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio || i.Type == MediaStreamType.Video))
|
if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio || i.Type == MediaStreamType.Video))
|
||||||
{
|
{
|
||||||
await item.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
await item.RefreshMetadata(
|
||||||
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
EnableRemoteContentProbe = true,
|
EnableRemoteContentProbe = true,
|
||||||
MetadataRefreshMode = MediaBrowser.Controller.Providers.MetadataRefreshMode.FullRefresh
|
MetadataRefreshMode = MetadataRefreshMode.FullRefresh
|
||||||
|
},
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user);
|
mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using System.Text;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Common.Cryptography;
|
using MediaBrowser.Common.Cryptography;
|
||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
@ -31,7 +32,6 @@ using MediaBrowser.Model.IO;
|
|||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static MediaBrowser.Common.HexHelper;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Library
|
namespace Emby.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
@ -490,7 +490,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(user.EasyPassword)
|
return string.IsNullOrEmpty(user.EasyPassword)
|
||||||
? null
|
? null
|
||||||
: ToHexString(PasswordHash.Parse(user.EasyPassword).Hash);
|
: Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetInvalidLoginAttemptCount(User user)
|
private void ResetInvalidLoginAttemptCount(User user)
|
||||||
@ -639,7 +639,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
foreach (var user in Users)
|
foreach (var user in Users)
|
||||||
{
|
{
|
||||||
await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), cancellationToken).ConfigureAwait(false);
|
await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,16 +11,17 @@ using Microsoft.Extensions.Logging;
|
|||||||
namespace Emby.Server.Implementations.Library.Validators
|
namespace Emby.Server.Implementations.Library.Validators
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class PeopleValidator
|
/// Class PeopleValidator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PeopleValidator
|
public class PeopleValidator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _library manager
|
/// The _library manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _logger
|
/// The _logger.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ namespace Emby.Server.Implementations.Library.Validators
|
|||||||
{
|
{
|
||||||
var item = _libraryManager.GetPerson(person);
|
var item = _libraryManager.GetPerson(person);
|
||||||
|
|
||||||
var options = new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
ImageRefreshMode = MetadataRefreshMode.ValidationOnly,
|
ImageRefreshMode = MetadataRefreshMode.ValidationOnly,
|
||||||
MetadataRefreshMode = MetadataRefreshMode.ValidationOnly
|
MetadataRefreshMode = MetadataRefreshMode.ValidationOnly
|
||||||
@ -96,12 +97,19 @@ namespace Emby.Server.Implementations.Library.Validators
|
|||||||
|
|
||||||
foreach (var item in deadEntities)
|
foreach (var item in deadEntities)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name);
|
_logger.LogInformation(
|
||||||
|
"Deleting dead {2} {0} {1}.",
|
||||||
|
item.Id.ToString("N", CultureInfo.InvariantCulture),
|
||||||
|
item.Name,
|
||||||
|
item.GetType().Name);
|
||||||
|
|
||||||
_libraryManager.DeleteItem(item, new DeleteOptions
|
_libraryManager.DeleteItem(
|
||||||
|
item,
|
||||||
|
new DeleteOptions
|
||||||
{
|
{
|
||||||
DeleteFileLocation = false
|
DeleteFileLocation = false
|
||||||
}, false);
|
},
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
|
@ -1489,7 +1489,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Refreshing recording parent {path}", item.Path);
|
_logger.LogInformation("Refreshing recording parent {path}", item.Path);
|
||||||
|
|
||||||
_providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
_providerManager.QueueRefresh(
|
||||||
|
item.Id,
|
||||||
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
RefreshPaths = new string[]
|
RefreshPaths = new string[]
|
||||||
{
|
{
|
||||||
@ -1497,8 +1499,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
Path.GetDirectoryName(path),
|
Path.GetDirectoryName(path),
|
||||||
Path.GetDirectoryName(Path.GetDirectoryName(path))
|
Path.GetDirectoryName(Path.GetDirectoryName(path))
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}, RefreshPriority.High);
|
RefreshPriority.High);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,12 +1226,13 @@ namespace Emby.Server.Implementations.LiveTv
|
|||||||
currentChannel.AddTag("Kids");
|
currentChannel.AddTag("Kids");
|
||||||
}
|
}
|
||||||
|
|
||||||
//currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
|
currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
|
||||||
await currentChannel.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
await currentChannel.RefreshMetadata(
|
||||||
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
|
},
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@ -1245,7 +1246,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||||||
numComplete++;
|
numComplete++;
|
||||||
double percent = numComplete / (double)allChannelsList.Count;
|
double percent = numComplete / (double)allChannelsList.Count;
|
||||||
|
|
||||||
progress.Report(85 * percent + 15);
|
progress.Report((85 * percent) + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
@ -1278,12 +1279,14 @@ namespace Emby.Server.Implementations.LiveTv
|
|||||||
|
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
_libraryManager.DeleteItem(item, new DeleteOptions
|
_libraryManager.DeleteItem(
|
||||||
|
item,
|
||||||
|
new DeleteOptions
|
||||||
{
|
{
|
||||||
DeleteFileLocation = false,
|
DeleteFileLocation = false,
|
||||||
DeleteFromExternalProvider = false
|
DeleteFromExternalProvider = false
|
||||||
|
},
|
||||||
}, false);
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2301,8 +2304,10 @@ namespace Emby.Server.Implementations.LiveTv
|
|||||||
if (provider == null)
|
if (provider == null)
|
||||||
{
|
{
|
||||||
throw new ResourceNotFoundException(
|
throw new ResourceNotFoundException(
|
||||||
string.Format("Couldn't find provider of type: '{0}'", info.Type)
|
string.Format(
|
||||||
);
|
CultureInfo.InvariantCulture,
|
||||||
|
"Couldn't find provider of type: '{0}'",
|
||||||
|
info.Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
await provider.Validate(info, validateLogin, validateListings).ConfigureAwait(false);
|
await provider.Validate(info, validateLogin, validateListings).ConfigureAwait(false);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"Artists": "Artistes",
|
"Artists": "Artistes",
|
||||||
"AuthenticationSucceededWithUserName": "{0} s'est authentifié avec succès",
|
"AuthenticationSucceededWithUserName": "{0} s'est authentifié avec succès",
|
||||||
"Books": "Livres",
|
"Books": "Livres",
|
||||||
"CameraImageUploadedFrom": "Une image de caméra a été chargée depuis {0}",
|
"CameraImageUploadedFrom": "Une nouvelle image de caméra a été chargée depuis {0}",
|
||||||
"Channels": "Chaînes",
|
"Channels": "Chaînes",
|
||||||
"ChapterNameValue": "Chapitre {0}",
|
"ChapterNameValue": "Chapitre {0}",
|
||||||
"Collections": "Collections",
|
"Collections": "Collections",
|
||||||
@ -17,7 +17,7 @@
|
|||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Artistes de l'album",
|
"HeaderAlbumArtists": "Artistes de l'album",
|
||||||
"HeaderCameraUploads": "Photos transférées",
|
"HeaderCameraUploads": "Photos transférées",
|
||||||
"HeaderContinueWatching": "Reprendre",
|
"HeaderContinueWatching": "Continuer à regarder",
|
||||||
"HeaderFavoriteAlbums": "Albums favoris",
|
"HeaderFavoriteAlbums": "Albums favoris",
|
||||||
"HeaderFavoriteArtists": "Artistes favoris",
|
"HeaderFavoriteArtists": "Artistes favoris",
|
||||||
"HeaderFavoriteEpisodes": "Épisodes favoris",
|
"HeaderFavoriteEpisodes": "Épisodes favoris",
|
||||||
@ -34,14 +34,14 @@
|
|||||||
"LabelRunningTimeValue": "Durée : {0}",
|
"LabelRunningTimeValue": "Durée : {0}",
|
||||||
"Latest": "Derniers",
|
"Latest": "Derniers",
|
||||||
"MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
|
"MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
|
||||||
"MessageApplicationUpdatedTo": "Jellyfin Serveur a été mis à jour en version {0}",
|
"MessageApplicationUpdatedTo": "Le serveur Jellyfin a été mis à jour vers {0}",
|
||||||
"MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
|
"MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
|
||||||
"MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour",
|
"MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour",
|
||||||
"MixedContent": "Contenu mixte",
|
"MixedContent": "Contenu mixte",
|
||||||
"Movies": "Films",
|
"Movies": "Films",
|
||||||
"Music": "Musique",
|
"Music": "Musique",
|
||||||
"MusicVideos": "Vidéos musicales",
|
"MusicVideos": "Vidéos musicales",
|
||||||
"NameInstallFailed": "{0} échec d'installation",
|
"NameInstallFailed": "{0} échec de l'installation",
|
||||||
"NameSeasonNumber": "Saison {0}",
|
"NameSeasonNumber": "Saison {0}",
|
||||||
"NameSeasonUnknown": "Saison Inconnue",
|
"NameSeasonUnknown": "Saison Inconnue",
|
||||||
"NewVersionIsAvailable": "Une nouvelle version de Jellyfin Serveur est disponible au téléchargement.",
|
"NewVersionIsAvailable": "Une nouvelle version de Jellyfin Serveur est disponible au téléchargement.",
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"NotificationOptionAudioPlayback": "Lecture audio démarrée",
|
"NotificationOptionAudioPlayback": "Lecture audio démarrée",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée",
|
"NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée",
|
||||||
"NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée",
|
"NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée",
|
||||||
"NotificationOptionInstallationFailed": "Échec d'installation",
|
"NotificationOptionInstallationFailed": "Échec de l'installation",
|
||||||
"NotificationOptionNewLibraryContent": "Nouveau contenu ajouté",
|
"NotificationOptionNewLibraryContent": "Nouveau contenu ajouté",
|
||||||
"NotificationOptionPluginError": "Erreur d'extension",
|
"NotificationOptionPluginError": "Erreur d'extension",
|
||||||
"NotificationOptionPluginInstalled": "Extension installée",
|
"NotificationOptionPluginInstalled": "Extension installée",
|
||||||
@ -91,7 +91,7 @@
|
|||||||
"UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}",
|
"UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}",
|
||||||
"UserStartedPlayingItemWithValues": "{0} est en train de lire {1} sur {2}",
|
"UserStartedPlayingItemWithValues": "{0} est en train de lire {1} sur {2}",
|
||||||
"UserStoppedPlayingItemWithValues": "{0} vient d'arrêter la lecture de {1} sur {2}",
|
"UserStoppedPlayingItemWithValues": "{0} vient d'arrêter la lecture de {1} sur {2}",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre librairie",
|
"ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre médiathèque",
|
||||||
"ValueSpecialEpisodeName": "Spécial - {0}",
|
"ValueSpecialEpisodeName": "Spécial - {0}",
|
||||||
"VersionNumber": "Version {0}"
|
"VersionNumber": "Version {0}"
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"Artists": "Előadók",
|
"Artists": "Előadók",
|
||||||
"AuthenticationSucceededWithUserName": "{0} sikeresen azonosítva",
|
"AuthenticationSucceededWithUserName": "{0} sikeresen azonosítva",
|
||||||
"Books": "Könyvek",
|
"Books": "Könyvek",
|
||||||
"CameraImageUploadedFrom": "Új kamerakép került feltöltésre {0}",
|
"CameraImageUploadedFrom": "Új kamerakép került feltöltésre innen: {0}",
|
||||||
"Channels": "Csatornák",
|
"Channels": "Csatornák",
|
||||||
"ChapterNameValue": "Jelenet {0}",
|
"ChapterNameValue": "Jelenet {0}",
|
||||||
"Collections": "Gyűjtemények",
|
"Collections": "Gyűjtemények",
|
||||||
@ -15,14 +15,14 @@
|
|||||||
"Favorites": "Kedvencek",
|
"Favorites": "Kedvencek",
|
||||||
"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",
|
"HeaderCameraUploads": "Kamera feltöltések",
|
||||||
"HeaderContinueWatching": "Folyamatban lévő filmek",
|
"HeaderContinueWatching": "Folyamatban lévő filmek",
|
||||||
"HeaderFavoriteAlbums": "Kedvenc Albumok",
|
"HeaderFavoriteAlbums": "Kedvenc albumok",
|
||||||
"HeaderFavoriteArtists": "Kedvenc Előadók",
|
"HeaderFavoriteArtists": "Kedvenc előadók",
|
||||||
"HeaderFavoriteEpisodes": "Kedvenc Epizódok",
|
"HeaderFavoriteEpisodes": "Kedvenc epizódok",
|
||||||
"HeaderFavoriteShows": "Kedvenc Sorozatok",
|
"HeaderFavoriteShows": "Kedvenc sorozatok",
|
||||||
"HeaderFavoriteSongs": "Kedvenc Dalok",
|
"HeaderFavoriteSongs": "Kedvenc dalok",
|
||||||
"HeaderLiveTV": "Élő TV",
|
"HeaderLiveTV": "Élő TV",
|
||||||
"HeaderNextUp": "Következik",
|
"HeaderNextUp": "Következik",
|
||||||
"HeaderRecordingGroups": "Felvételi csoportok",
|
"HeaderRecordingGroups": "Felvételi csoportok",
|
||||||
@ -34,21 +34,21 @@
|
|||||||
"LabelRunningTimeValue": "Futási idő: {0}",
|
"LabelRunningTimeValue": "Futási idő: {0}",
|
||||||
"Latest": "Legújabb",
|
"Latest": "Legújabb",
|
||||||
"MessageApplicationUpdated": "Jellyfin Szerver frissítve",
|
"MessageApplicationUpdated": "Jellyfin Szerver frissítve",
|
||||||
"MessageApplicationUpdatedTo": "Jellyfin Szerver frissítve lett a következőre {0}",
|
"MessageApplicationUpdatedTo": "Jellyfin Szerver frissítve lett a következőre: {0}",
|
||||||
"MessageNamedServerConfigurationUpdatedWithValue": "Szerver konfigurációs rész {0} frissítve",
|
"MessageNamedServerConfigurationUpdatedWithValue": "Szerver konfigurációs rész frissítve: {0}",
|
||||||
"MessageServerConfigurationUpdated": "Szerver konfiguráció frissítve",
|
"MessageServerConfigurationUpdated": "Szerver konfiguráció frissítve",
|
||||||
"MixedContent": "Vegyes tartalom",
|
"MixedContent": "Vegyes tartalom",
|
||||||
"Movies": "Filmek",
|
"Movies": "Filmek",
|
||||||
"Music": "Zene",
|
"Music": "Zene",
|
||||||
"MusicVideos": "Zenei Videók",
|
"MusicVideos": "Zenei videók",
|
||||||
"NameInstallFailed": "{0} sikertelen telepítés",
|
"NameInstallFailed": "{0} sikertelen telepítés",
|
||||||
"NameSeasonNumber": "Évad {0}",
|
"NameSeasonNumber": "Évad {0}",
|
||||||
"NameSeasonUnknown": "Ismeretlen évad",
|
"NameSeasonUnknown": "Ismeretlen évad",
|
||||||
"NewVersionIsAvailable": "Letölthető a Jellyfin Szerver új verziója.",
|
"NewVersionIsAvailable": "Letölthető a Jellyfin Szerver új verziója.",
|
||||||
"NotificationOptionApplicationUpdateAvailable": "Új programfrissítés érhető el",
|
"NotificationOptionApplicationUpdateAvailable": "Frissítés érhető el az alkalmazáshoz",
|
||||||
"NotificationOptionApplicationUpdateInstalled": "Programfrissítés telepítve",
|
"NotificationOptionApplicationUpdateInstalled": "Alkalmazásfrissítés telepítve",
|
||||||
"NotificationOptionAudioPlayback": "Audió lejátszás elkezdve",
|
"NotificationOptionAudioPlayback": "Audió lejátszás elkezdve",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Audió lejátszás befejezve",
|
"NotificationOptionAudioPlaybackStopped": "Audió lejátszás leállítva",
|
||||||
"NotificationOptionCameraImageUploaded": "Kamera kép feltöltve",
|
"NotificationOptionCameraImageUploaded": "Kamera kép feltöltve",
|
||||||
"NotificationOptionInstallationFailed": "Telepítési hiba",
|
"NotificationOptionInstallationFailed": "Telepítési hiba",
|
||||||
"NotificationOptionNewLibraryContent": "Új tartalom hozzáadva",
|
"NotificationOptionNewLibraryContent": "Új tartalom hozzáadva",
|
||||||
@ -60,15 +60,15 @@
|
|||||||
"NotificationOptionTaskFailed": "Ütemezett feladat hiba",
|
"NotificationOptionTaskFailed": "Ütemezett feladat hiba",
|
||||||
"NotificationOptionUserLockedOut": "Felhasználó tiltva",
|
"NotificationOptionUserLockedOut": "Felhasználó tiltva",
|
||||||
"NotificationOptionVideoPlayback": "Videó lejátszás elkezdve",
|
"NotificationOptionVideoPlayback": "Videó lejátszás elkezdve",
|
||||||
"NotificationOptionVideoPlaybackStopped": "Videó lejátszás befejezve",
|
"NotificationOptionVideoPlaybackStopped": "Videó lejátszás leállítva",
|
||||||
"Photos": "Fényképek",
|
"Photos": "Fényképek",
|
||||||
"Playlists": "Lejátszási listák",
|
"Playlists": "Lejátszási listák",
|
||||||
"Plugin": "Bővítmény",
|
"Plugin": "Bővítmény",
|
||||||
"PluginInstalledWithName": "{0} telepítve",
|
"PluginInstalledWithName": "{0} telepítve",
|
||||||
"PluginUninstalledWithName": "{0} eltávolítva",
|
"PluginUninstalledWithName": "{0} eltávolítva",
|
||||||
"PluginUpdatedWithName": "{0} frissítve",
|
"PluginUpdatedWithName": "{0} frissítve",
|
||||||
"ProviderValue": "Provider: {0}",
|
"ProviderValue": "Szolgáltató: {0}",
|
||||||
"ScheduledTaskFailedWithName": "{0} hiba",
|
"ScheduledTaskFailedWithName": "{0} sikertelen",
|
||||||
"ScheduledTaskStartedWithName": "{0} elkezdve",
|
"ScheduledTaskStartedWithName": "{0} elkezdve",
|
||||||
"ServerNameNeedsToBeRestarted": "{0}-t újra kell indítani",
|
"ServerNameNeedsToBeRestarted": "{0}-t újra kell indítani",
|
||||||
"Shows": "Műsorok",
|
"Shows": "Műsorok",
|
||||||
@ -76,10 +76,10 @@
|
|||||||
"StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek próbáld újra később.",
|
"StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek próbáld újra később.",
|
||||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||||
"SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0} ehhez: {1}",
|
"SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0} ehhez: {1}",
|
||||||
"SubtitlesDownloadedForItem": "Letöltött feliratok a következőhöz {0}",
|
"SubtitlesDownloadedForItem": "Letöltött feliratok a következőhöz: {0}",
|
||||||
"Sync": "Szinkronizál",
|
"Sync": "Szinkronizál",
|
||||||
"System": "Rendszer",
|
"System": "Rendszer",
|
||||||
"TvShows": "TV Műsorok",
|
"TvShows": "TV műsorok",
|
||||||
"User": "Felhasználó",
|
"User": "Felhasználó",
|
||||||
"UserCreatedWithName": "{0} felhasználó létrehozva",
|
"UserCreatedWithName": "{0} felhasználó létrehozva",
|
||||||
"UserDeletedWithName": "{0} felhasználó törölve",
|
"UserDeletedWithName": "{0} felhasználó törölve",
|
||||||
@ -88,7 +88,7 @@
|
|||||||
"UserOfflineFromDevice": "{0} kijelentkezett innen: {1}",
|
"UserOfflineFromDevice": "{0} kijelentkezett innen: {1}",
|
||||||
"UserOnlineFromDevice": "{0} online itt: {1}",
|
"UserOnlineFromDevice": "{0} online itt: {1}",
|
||||||
"UserPasswordChangedWithName": "Jelszó megváltozott a következő felhasználó számára: {0}",
|
"UserPasswordChangedWithName": "Jelszó megváltozott a következő felhasználó számára: {0}",
|
||||||
"UserPolicyUpdatedWithName": "A felhasználói házirend frissítve lett {0}",
|
"UserPolicyUpdatedWithName": "A felhasználói házirend frissítve lett neki: {0}",
|
||||||
"UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt: {1} itt: {2}",
|
"UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt: {1} itt: {2}",
|
||||||
"UserStoppedPlayingItemWithValues": "{0} befejezte a következőt: {1} itt: {2}",
|
"UserStoppedPlayingItemWithValues": "{0} befejezte a következőt: {1} itt: {2}",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} hozzáadva a médiatárhoz",
|
"ValueHasBeenAddedToLibrary": "{0} hozzáadva a médiatárhoz",
|
||||||
|
@ -5,26 +5,26 @@
|
|||||||
"Artists": "Sanatçılar",
|
"Artists": "Sanatçılar",
|
||||||
"AuthenticationSucceededWithUserName": "{0} kimlik başarıyla doğrulandı",
|
"AuthenticationSucceededWithUserName": "{0} kimlik başarıyla doğrulandı",
|
||||||
"Books": "Kitaplar",
|
"Books": "Kitaplar",
|
||||||
"CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
|
"CameraImageUploadedFrom": "{0} 'den yeni bir kamera resmi yüklendi",
|
||||||
"Channels": "Kanallar",
|
"Channels": "Kanallar",
|
||||||
"ChapterNameValue": "Chapter {0}",
|
"ChapterNameValue": "Bölüm {0}",
|
||||||
"Collections": "Collections",
|
"Collections": "Koleksiyonlar",
|
||||||
"DeviceOfflineWithName": "{0} has disconnected",
|
"DeviceOfflineWithName": "{0} bağlantısı kesildi",
|
||||||
"DeviceOnlineWithName": "{0} is connected",
|
"DeviceOnlineWithName": "{0} bağlı",
|
||||||
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
|
"FailedLoginAttemptWithUserName": "{0} adresinden giriş başarısız oldu",
|
||||||
"Favorites": "Favorites",
|
"Favorites": "Favoriler",
|
||||||
"Folders": "Folders",
|
"Folders": "Klasörler",
|
||||||
"Genres": "Genres",
|
"Genres": "Türler",
|
||||||
"HeaderAlbumArtists": "Album Artists",
|
"HeaderAlbumArtists": "Albüm Sanatçıları",
|
||||||
"HeaderCameraUploads": "Camera Uploads",
|
"HeaderCameraUploads": "Kamera Yüklemeleri",
|
||||||
"HeaderContinueWatching": "İzlemeye Devam Et",
|
"HeaderContinueWatching": "İzlemeye Devam Et",
|
||||||
"HeaderFavoriteAlbums": "Favori Albümler",
|
"HeaderFavoriteAlbums": "Favori Albümler",
|
||||||
"HeaderFavoriteArtists": "Favorite Artists",
|
"HeaderFavoriteArtists": "Favori Sanatçılar",
|
||||||
"HeaderFavoriteEpisodes": "Favorite Episodes",
|
"HeaderFavoriteEpisodes": "Favori Bölümler",
|
||||||
"HeaderFavoriteShows": "Favori Showlar",
|
"HeaderFavoriteShows": "Favori Diziler",
|
||||||
"HeaderFavoriteSongs": "Favorite Songs",
|
"HeaderFavoriteSongs": "Favori Şarkılar",
|
||||||
"HeaderLiveTV": "Live TV",
|
"HeaderLiveTV": "Canlı TV",
|
||||||
"HeaderNextUp": "Next Up",
|
"HeaderNextUp": "Sonraki hafta",
|
||||||
"HeaderRecordingGroups": "Recording Groups",
|
"HeaderRecordingGroups": "Recording Groups",
|
||||||
"HomeVideos": "Home videos",
|
"HomeVideos": "Home videos",
|
||||||
"Inherit": "Inherit",
|
"Inherit": "Inherit",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
|
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
|
||||||
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
||||||
"MixedContent": "Mixed content",
|
"MixedContent": "Mixed content",
|
||||||
"Movies": "Movies",
|
"Movies": "Filmler",
|
||||||
"Music": "Müzik",
|
"Music": "Müzik",
|
||||||
"MusicVideos": "Müzik videoları",
|
"MusicVideos": "Müzik videoları",
|
||||||
"NameInstallFailed": "{0} kurulum başarısız",
|
"NameInstallFailed": "{0} kurulum başarısız",
|
||||||
@ -61,8 +61,8 @@
|
|||||||
"NotificationOptionUserLockedOut": "User locked out",
|
"NotificationOptionUserLockedOut": "User locked out",
|
||||||
"NotificationOptionVideoPlayback": "Video playback started",
|
"NotificationOptionVideoPlayback": "Video playback started",
|
||||||
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
|
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
|
||||||
"Photos": "Photos",
|
"Photos": "Fotoğraflar",
|
||||||
"Playlists": "Playlists",
|
"Playlists": "Çalma listeleri",
|
||||||
"Plugin": "Plugin",
|
"Plugin": "Plugin",
|
||||||
"PluginInstalledWithName": "{0} was installed",
|
"PluginInstalledWithName": "{0} was installed",
|
||||||
"PluginUninstalledWithName": "{0} was uninstalled",
|
"PluginUninstalledWithName": "{0} was uninstalled",
|
||||||
@ -71,13 +71,13 @@
|
|||||||
"ScheduledTaskFailedWithName": "{0} failed",
|
"ScheduledTaskFailedWithName": "{0} failed",
|
||||||
"ScheduledTaskStartedWithName": "{0} started",
|
"ScheduledTaskStartedWithName": "{0} started",
|
||||||
"ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
|
"ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
|
||||||
"Shows": "Shows",
|
"Shows": "Diziler",
|
||||||
"Songs": "Songs",
|
"Songs": "Şarkılar",
|
||||||
"StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
|
"StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
|
||||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||||
"SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
|
"SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
|
||||||
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
|
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
|
||||||
"Sync": "Sync",
|
"Sync": "Eşitle",
|
||||||
"System": "System",
|
"System": "System",
|
||||||
"TvShows": "TV Shows",
|
"TvShows": "TV Shows",
|
||||||
"User": "User",
|
"User": "User",
|
||||||
@ -92,6 +92,6 @@
|
|||||||
"UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}",
|
"UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}",
|
||||||
"UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
|
"UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
|
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
|
||||||
"ValueSpecialEpisodeName": "Special - {0}",
|
"ValueSpecialEpisodeName": "Özel -{0}",
|
||||||
"VersionNumber": "Version {0}"
|
"VersionNumber": "Version {0}"
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
private IPAddress[] _localIpAddresses;
|
private IPAddress[] _localIpAddresses;
|
||||||
private readonly object _localIpAddressSyncLock = new object();
|
private readonly object _localIpAddressSyncLock = new object();
|
||||||
|
|
||||||
|
private readonly object _subnetLookupLock = new object();
|
||||||
|
private Dictionary<string, List<string>> _subnetLookup = new Dictionary<string, List<string>>(StringComparer.Ordinal);
|
||||||
|
|
||||||
public NetworkManager(ILogger<NetworkManager> logger)
|
public NetworkManager(ILogger<NetworkManager> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -28,10 +31,10 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
|
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func<string[]> LocalSubnetsFn { get; set; }
|
|
||||||
|
|
||||||
public event EventHandler NetworkChanged;
|
public event EventHandler NetworkChanged;
|
||||||
|
|
||||||
|
public Func<string[]> LocalSubnetsFn { get; set; }
|
||||||
|
|
||||||
private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("NetworkAvailabilityChanged");
|
_logger.LogDebug("NetworkAvailabilityChanged");
|
||||||
@ -179,10 +182,9 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, List<string>> _subnetLookup = new Dictionary<string, List<string>>(StringComparer.Ordinal);
|
|
||||||
private List<string> GetSubnets(string endpointFirstPart)
|
private List<string> GetSubnets(string endpointFirstPart)
|
||||||
{
|
{
|
||||||
lock (_subnetLookup)
|
lock (_subnetLookupLock)
|
||||||
{
|
{
|
||||||
if (_subnetLookup.TryGetValue(endpointFirstPart, out var subnets))
|
if (_subnetLookup.TryGetValue(endpointFirstPart, out var subnets))
|
||||||
{
|
{
|
||||||
@ -200,7 +202,11 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
int subnet_Test = 0;
|
int subnet_Test = 0;
|
||||||
foreach (string part in unicastIPAddressInformation.IPv4Mask.ToString().Split('.'))
|
foreach (string part in unicastIPAddressInformation.IPv4Mask.ToString().Split('.'))
|
||||||
{
|
{
|
||||||
if (part.Equals("0")) break;
|
if (part.Equals("0", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
subnet_Test++;
|
subnet_Test++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +90,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var folder = item as Folder;
|
if (item is Folder folder)
|
||||||
if (folder != null)
|
|
||||||
{
|
{
|
||||||
options.MediaType = folder.GetRecursiveChildren(i => !i.IsFolder && i.SupportsAddingToPlaylist)
|
options.MediaType = folder.GetRecursiveChildren(i => !i.IsFolder && i.SupportsAddingToPlaylist)
|
||||||
.Select(i => i.MediaType)
|
.Select(i => i.MediaType)
|
||||||
@ -140,7 +139,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
|
|
||||||
parentFolder.AddChild(playlist, CancellationToken.None);
|
parentFolder.AddChild(playlist, CancellationToken.None);
|
||||||
|
|
||||||
await playlist.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) { ForceSave = true }, CancellationToken.None)
|
await playlist.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { ForceSave = true }, CancellationToken.None)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (options.ItemIdList.Length > 0)
|
if (options.ItemIdList.Length > 0)
|
||||||
@ -201,7 +200,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
|
|
||||||
var list = new List<LinkedChild>();
|
var list = new List<LinkedChild>();
|
||||||
|
|
||||||
var items = (GetPlaylistItems(itemIds, playlist.MediaType, user, options))
|
var items = GetPlaylistItems(itemIds, playlist.MediaType, user, options)
|
||||||
.Where(i => i.SupportsAddingToPlaylist)
|
.Where(i => i.SupportsAddingToPlaylist)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -221,18 +220,18 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
SavePlaylistFile(playlist);
|
SavePlaylistFile(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
_providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
_providerManager.QueueRefresh(
|
||||||
|
playlist.Id,
|
||||||
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
|
},
|
||||||
}, RefreshPriority.High);
|
RefreshPriority.High);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveFromPlaylist(string playlistId, IEnumerable<string> entryIds)
|
public void RemoveFromPlaylist(string playlistId, IEnumerable<string> entryIds)
|
||||||
{
|
{
|
||||||
var playlist = _libraryManager.GetItemById(playlistId) as Playlist;
|
if (!(_libraryManager.GetItemById(playlistId) is Playlist playlist))
|
||||||
|
|
||||||
if (playlist == null)
|
|
||||||
{
|
{
|
||||||
throw new ArgumentException("No Playlist exists with the supplied Id");
|
throw new ArgumentException("No Playlist exists with the supplied Id");
|
||||||
}
|
}
|
||||||
@ -254,7 +253,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
SavePlaylistFile(playlist);
|
SavePlaylistFile(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
_providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
_providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
ForceSave = true
|
ForceSave = true
|
||||||
|
|
||||||
@ -263,9 +262,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
|
|
||||||
public void MoveItem(string playlistId, string entryId, int newIndex)
|
public void MoveItem(string playlistId, string entryId, int newIndex)
|
||||||
{
|
{
|
||||||
var playlist = _libraryManager.GetItemById(playlistId) as Playlist;
|
if (!(_libraryManager.GetItemById(playlistId) is Playlist playlist))
|
||||||
|
|
||||||
if (playlist == null)
|
|
||||||
{
|
{
|
||||||
throw new ArgumentException("No Playlist exists with the supplied Id");
|
throw new ArgumentException("No Playlist exists with the supplied Id");
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,17 @@ using Microsoft.Extensions.Logging;
|
|||||||
namespace Emby.Server.Implementations.ScheduledTasks
|
namespace Emby.Server.Implementations.ScheduledTasks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class ChapterImagesTask
|
/// Class ChapterImagesTask.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ChapterImagesTask : IScheduledTask
|
public class ChapterImagesTask : IScheduledTask
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _logger
|
/// The _logger.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _library manager
|
/// The _library manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
@ -53,12 +54,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the triggers that define when the task will run
|
/// Creates the triggers that define when the task will run.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||||
{
|
{
|
||||||
return new[] {
|
return new[]
|
||||||
|
{
|
||||||
new TaskTriggerInfo
|
new TaskTriggerInfo
|
||||||
{
|
{
|
||||||
Type = TaskTriggerInfo.TriggerDaily,
|
Type = TaskTriggerInfo.TriggerDaily,
|
||||||
@ -117,7 +118,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||||||
previouslyFailedImages = new List<string>();
|
previouslyFailedImages = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var directoryService = new DirectoryService(_logger, _fileSystem);
|
var directoryService = new DirectoryService(_fileSystem);
|
||||||
|
|
||||||
foreach (var video in videos)
|
foreach (var video in videos)
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Concurrent;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Serialization
|
namespace Emby.Server.Implementations.Serialization
|
||||||
{
|
{
|
||||||
@ -14,35 +12,13 @@ namespace Emby.Server.Implementations.Serialization
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MyXmlSerializer : IXmlSerializer
|
public class MyXmlSerializer : IXmlSerializer
|
||||||
{
|
{
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public MyXmlSerializer(
|
|
||||||
IFileSystem fileSystem,
|
|
||||||
ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_logger = loggerFactory.CreateLogger("XmlSerializer");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to cache these
|
// Need to cache these
|
||||||
// http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
|
// http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
|
||||||
private readonly Dictionary<string, XmlSerializer> _serializers =
|
private static readonly ConcurrentDictionary<string, XmlSerializer> _serializers =
|
||||||
new Dictionary<string, XmlSerializer>();
|
new ConcurrentDictionary<string, XmlSerializer>();
|
||||||
|
|
||||||
private XmlSerializer GetSerializer(Type type)
|
private static XmlSerializer GetSerializer(Type type)
|
||||||
{
|
=> _serializers.GetOrAdd(type.FullName, _ => new XmlSerializer(type));
|
||||||
var key = type.FullName;
|
|
||||||
lock (_serializers)
|
|
||||||
{
|
|
||||||
if (!_serializers.TryGetValue(key, out var serializer))
|
|
||||||
{
|
|
||||||
serializer = new XmlSerializer(type);
|
|
||||||
_serializers[key] = serializer;
|
|
||||||
}
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serializes to writer.
|
/// Serializes to writer.
|
||||||
@ -91,7 +67,6 @@ namespace Emby.Server.Implementations.Serialization
|
|||||||
/// <param name="file">The file.</param>
|
/// <param name="file">The file.</param>
|
||||||
public void SerializeToFile(object obj, string file)
|
public void SerializeToFile(object obj, string file)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Serializing to file {0}", file);
|
|
||||||
using (var stream = new FileStream(file, FileMode.Create))
|
using (var stream = new FileStream(file, FileMode.Create))
|
||||||
{
|
{
|
||||||
SerializeToStream(obj, stream);
|
SerializeToStream(obj, stream);
|
||||||
@ -106,7 +81,6 @@ namespace Emby.Server.Implementations.Serialization
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object DeserializeFromFile(Type type, string file)
|
public object DeserializeFromFile(Type type, string file)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Deserializing file {0}", file);
|
|
||||||
using (var stream = File.OpenRead(file))
|
using (var stream = File.OpenRead(file))
|
||||||
{
|
{
|
||||||
return DeserializeFromStream(type, stream);
|
return DeserializeFromStream(type, stream);
|
@ -6,7 +6,7 @@ using MediaBrowser.Controller;
|
|||||||
namespace Emby.Server.Implementations
|
namespace Emby.Server.Implementations
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extends BaseApplicationPaths to add paths that are only applicable on the server
|
/// Extends BaseApplicationPaths to add paths that are only applicable on the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerApplicationPaths : BaseApplicationPaths, IServerApplicationPaths
|
public class ServerApplicationPaths : BaseApplicationPaths, IServerApplicationPaths
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -19,7 +18,6 @@ using MediaBrowser.Model.IO;
|
|||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.Updates;
|
using MediaBrowser.Model.Updates;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static MediaBrowser.Common.HexHelper;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Updates
|
namespace Emby.Server.Implementations.Updates
|
||||||
{
|
{
|
||||||
@ -28,43 +26,10 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class InstallationManager : IInstallationManager
|
public class InstallationManager : IInstallationManager
|
||||||
{
|
{
|
||||||
public event EventHandler<InstallationEventArgs> PackageInstalling;
|
|
||||||
public event EventHandler<InstallationEventArgs> PackageInstallationCompleted;
|
|
||||||
public event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
|
|
||||||
public event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current installations
|
/// The _logger.
|
||||||
/// </summary>
|
|
||||||
private List<(InstallationInfo info, CancellationTokenSource token)> _currentInstallations { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The completed installations
|
|
||||||
/// </summary>
|
|
||||||
private ConcurrentBag<InstallationInfo> _completedInstallationsInternal;
|
|
||||||
|
|
||||||
public IEnumerable<InstallationInfo> CompletedInstallations => _completedInstallationsInternal;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when [plugin uninstalled].
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when [plugin updated].
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when [plugin updated].
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _logger
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
@ -79,6 +44,18 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
|
|
||||||
private readonly IZipClient _zipClient;
|
private readonly IZipClient _zipClient;
|
||||||
|
|
||||||
|
private readonly object _currentInstallationsLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current installations.
|
||||||
|
/// </summary>
|
||||||
|
private List<(InstallationInfo info, CancellationTokenSource token)> _currentInstallations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The completed installations.
|
||||||
|
/// </summary>
|
||||||
|
private ConcurrentBag<InstallationInfo> _completedInstallationsInternal;
|
||||||
|
|
||||||
public InstallationManager(
|
public InstallationManager(
|
||||||
ILogger<InstallationManager> logger,
|
ILogger<InstallationManager> logger,
|
||||||
IApplicationHost appHost,
|
IApplicationHost appHost,
|
||||||
@ -107,6 +84,31 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
_zipClient = zipClient;
|
_zipClient = zipClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event EventHandler<InstallationEventArgs> PackageInstalling;
|
||||||
|
|
||||||
|
public event EventHandler<InstallationEventArgs> PackageInstallationCompleted;
|
||||||
|
|
||||||
|
public event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
|
||||||
|
|
||||||
|
public event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a plugin is uninstalled.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a plugin plugin is updated.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a plugin plugin is installed.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
|
||||||
|
|
||||||
|
public IEnumerable<InstallationInfo> CompletedInstallations => _completedInstallationsInternal;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all available packages.
|
/// Gets all available packages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -330,7 +332,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
var tuple = (installationInfo, innerCancellationTokenSource);
|
var tuple = (installationInfo, innerCancellationTokenSource);
|
||||||
|
|
||||||
// Add it to the in-progress list
|
// Add it to the in-progress list
|
||||||
lock (_currentInstallations)
|
lock (_currentInstallationsLock)
|
||||||
{
|
{
|
||||||
_currentInstallations.Add(tuple);
|
_currentInstallations.Add(tuple);
|
||||||
}
|
}
|
||||||
@ -349,7 +351,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
{
|
{
|
||||||
await InstallPackageInternal(package, linkedToken).ConfigureAwait(false);
|
await InstallPackageInternal(package, linkedToken).ConfigureAwait(false);
|
||||||
|
|
||||||
lock (_currentInstallations)
|
lock (_currentInstallationsLock)
|
||||||
{
|
{
|
||||||
_currentInstallations.Remove(tuple);
|
_currentInstallations.Remove(tuple);
|
||||||
}
|
}
|
||||||
@ -360,7 +362,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
lock (_currentInstallations)
|
lock (_currentInstallationsLock)
|
||||||
{
|
{
|
||||||
_currentInstallations.Remove(tuple);
|
_currentInstallations.Remove(tuple);
|
||||||
}
|
}
|
||||||
@ -375,7 +377,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
{
|
{
|
||||||
_logger.LogError(ex, "Package installation failed");
|
_logger.LogError(ex, "Package installation failed");
|
||||||
|
|
||||||
lock (_currentInstallations)
|
lock (_currentInstallationsLock)
|
||||||
{
|
{
|
||||||
_currentInstallations.Remove(tuple);
|
_currentInstallations.Remove(tuple);
|
||||||
}
|
}
|
||||||
@ -455,7 +457,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var hash = ToHexString(md5.ComputeHash(stream));
|
var hash = Hex.Encode(md5.ComputeHash(stream));
|
||||||
if (!string.Equals(package.checksum, hash, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(package.checksum, hash, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_logger.LogError(
|
_logger.LogError(
|
||||||
@ -535,7 +537,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool CancelInstallation(Guid id)
|
public bool CancelInstallation(Guid id)
|
||||||
{
|
{
|
||||||
lock (_currentInstallations)
|
lock (_currentInstallationsLock)
|
||||||
{
|
{
|
||||||
var install = _currentInstallations.Find(x => x.Item1.Id == id);
|
var install = _currentInstallations.Find(x => x.Item1.Id == id);
|
||||||
if (install == default((InstallationInfo, CancellationTokenSource)))
|
if (install == default((InstallationInfo, CancellationTokenSource)))
|
||||||
@ -563,7 +565,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
{
|
{
|
||||||
if (dispose)
|
if (dispose)
|
||||||
{
|
{
|
||||||
lock (_currentInstallations)
|
lock (_currentInstallationsLock)
|
||||||
{
|
{
|
||||||
foreach (var tuple in _currentInstallations)
|
foreach (var tuple in _currentInstallations)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- We need at least C# 7.1 for async main-->
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@ -25,8 +23,9 @@
|
|||||||
<!-- Code analyzers-->
|
<!-- Code analyzers-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" />
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
||||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
||||||
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
@ -35,8 +34,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommandLineParser" Version="2.6.0" />
|
<PackageReference Include="CommandLineParser" Version="2.6.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.4" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="3.0.0" />
|
||||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
|
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
|
||||||
|
@ -376,7 +376,7 @@ namespace Jellyfin.Server
|
|||||||
|
|
||||||
return new ConfigurationBuilder()
|
return new ConfigurationBuilder()
|
||||||
.SetBasePath(appPaths.ConfigurationDirectoryPath)
|
.SetBasePath(appPaths.ConfigurationDirectoryPath)
|
||||||
.AddJsonFile("logging.json")
|
.AddJsonFile("logging.json", false, true)
|
||||||
.AddEnvironmentVariables("JELLYFIN_")
|
.AddEnvironmentVariables("JELLYFIN_")
|
||||||
.AddInMemoryCollection(ConfigurationOptions.Configuration)
|
.AddInMemoryCollection(ConfigurationOptions.Configuration)
|
||||||
.Build();
|
.Build();
|
||||||
|
@ -32,7 +32,7 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(val))
|
if (string.IsNullOrEmpty(val))
|
||||||
{
|
{
|
||||||
return new ItemFields[] { };
|
return Array.Empty<ItemFields>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return val.Split(',').Select(v =>
|
return val.Split(',').Select(v =>
|
||||||
@ -41,6 +41,7 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
return (ItemFields?)value;
|
return (ItemFields?)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}).Where(i => i.HasValue).Select(i => i.Value).ToArray();
|
}).Where(i => i.HasValue).Select(i => i.Value).ToArray();
|
||||||
|
@ -227,15 +227,17 @@ namespace MediaBrowser.Api
|
|||||||
//item.ProductionYear = request.ProductionYear;
|
//item.ProductionYear = request.ProductionYear;
|
||||||
//item.Name = request.Name;
|
//item.Name = request.Name;
|
||||||
|
|
||||||
return _providerManager.RefreshFullItem(item, new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem))
|
return _providerManager.RefreshFullItem(
|
||||||
|
item,
|
||||||
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
ReplaceAllMetadata = true,
|
ReplaceAllMetadata = true,
|
||||||
ReplaceAllImages = request.ReplaceAllImages,
|
ReplaceAllImages = request.ReplaceAllImages,
|
||||||
SearchResult = request
|
SearchResult = request
|
||||||
|
},
|
||||||
}, CancellationToken.None);
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -294,12 +296,10 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
||||||
using (var stream = result.Content)
|
using (var stream = result.Content)
|
||||||
{
|
|
||||||
using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||||
{
|
{
|
||||||
await stream.CopyToAsync(filestream).ConfigureAwait(false);
|
await stream.CopyToAsync(filestream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
||||||
File.WriteAllText(pointerCachePath, fullCachePath);
|
File.WriteAllText(pointerCachePath, fullCachePath);
|
||||||
@ -311,9 +311,6 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="filename">The filename.</param>
|
/// <param name="filename">The filename.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetFullCachePath(string filename)
|
private string GetFullCachePath(string filename)
|
||||||
{
|
=> Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
|
||||||
return Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
private MetadataRefreshOptions GetRefreshOptions(RefreshItem request)
|
private MetadataRefreshOptions GetRefreshOptions(RefreshItem request)
|
||||||
{
|
{
|
||||||
return new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
|
return new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
MetadataRefreshMode = request.MetadataRefreshMode,
|
MetadataRefreshMode = request.MetadataRefreshMode,
|
||||||
ImageRefreshMode = request.ImageRefreshMode,
|
ImageRefreshMode = request.ImageRefreshMode,
|
||||||
|
@ -225,13 +225,15 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
if (displayOrderChanged)
|
if (displayOrderChanged)
|
||||||
{
|
{
|
||||||
_providerManager.QueueRefresh(series.Id, new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem))
|
_providerManager.QueueRefresh(
|
||||||
|
series.Id,
|
||||||
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
ReplaceAllMetadata = true
|
ReplaceAllMetadata = true
|
||||||
|
},
|
||||||
}, RefreshPriority.High);
|
RefreshPriority.High);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Text;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Api.UserLibrary;
|
using MediaBrowser.Api.UserLibrary;
|
||||||
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
@ -25,7 +26,6 @@ using MediaBrowser.Model.LiveTv;
|
|||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using static MediaBrowser.Common.HexHelper;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.LiveTv
|
namespace MediaBrowser.Api.LiveTv
|
||||||
{
|
{
|
||||||
@ -887,8 +887,9 @@ namespace MediaBrowser.Api.LiveTv
|
|||||||
{
|
{
|
||||||
// SchedulesDirect requires a SHA1 hash of the user's password
|
// SchedulesDirect requires a SHA1 hash of the user's password
|
||||||
// https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#obtain-a-token
|
// https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#obtain-a-token
|
||||||
using (SHA1 sha = SHA1.Create()) {
|
using (SHA1 sha = SHA1.Create())
|
||||||
return ToHexString(
|
{
|
||||||
|
return Hex.Encode(
|
||||||
sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
|
sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -289,17 +289,22 @@ namespace MediaBrowser.Api.Playback
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.LogDebug("Launched ffmpeg process");
|
||||||
state.TranscodingJob = transcodingJob;
|
state.TranscodingJob = transcodingJob;
|
||||||
|
|
||||||
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
||||||
_ = new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, logStream);
|
_ = new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, logStream);
|
||||||
|
|
||||||
// Wait for the file to exist before proceeeding
|
// Wait for the file to exist before proceeeding
|
||||||
while (!File.Exists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
|
var ffmpegTargetFile = state.WaitForPath ?? outputPath;
|
||||||
|
Logger.LogDebug("Waiting for the creation of {0}", ffmpegTargetFile);
|
||||||
|
while (!File.Exists(ffmpegTargetFile) && !transcodingJob.HasExited)
|
||||||
{
|
{
|
||||||
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
|
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.LogDebug("File {0} created or transcoding has finished", ffmpegTargetFile);
|
||||||
|
|
||||||
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
|
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
|
||||||
{
|
{
|
||||||
await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
|
await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
@ -314,6 +319,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
{
|
{
|
||||||
StartThrottler(state, transcodingJob);
|
StartThrottler(state, transcodingJob);
|
||||||
}
|
}
|
||||||
|
Logger.LogDebug("StartFfMpeg() finished successfully");
|
||||||
|
|
||||||
return transcodingJob;
|
return transcodingJob;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
if (File.Exists(segmentPath))
|
if (File.Exists(segmentPath))
|
||||||
{
|
{
|
||||||
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||||
|
Logger.LogDebug("returning {0} [it exists, try 1]", segmentPath);
|
||||||
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,6 +208,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||||
transcodingLock.Release();
|
transcodingLock.Release();
|
||||||
released = true;
|
released = true;
|
||||||
|
Logger.LogDebug("returning {0} [it exists, try 2]", segmentPath);
|
||||||
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -243,6 +245,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
|
request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
|
||||||
|
|
||||||
|
state.WaitForPath = segmentPath;
|
||||||
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
|
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -277,7 +280,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
// await Task.Delay(50, cancellationToken).ConfigureAwait(false);
|
// await Task.Delay(50, cancellationToken).ConfigureAwait(false);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
Logger.LogInformation("returning {0}", segmentPath);
|
Logger.LogDebug("returning {0} [general case]", segmentPath);
|
||||||
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||||
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -458,56 +461,68 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
TranscodingJob transcodingJob,
|
TranscodingJob transcodingJob,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var segmentFileExists = File.Exists(segmentPath);
|
var segmentExists = File.Exists(segmentPath);
|
||||||
|
if (segmentExists)
|
||||||
// If all transcoding has completed, just return immediately
|
|
||||||
if (transcodingJob != null && transcodingJob.HasExited && segmentFileExists)
|
|
||||||
{
|
{
|
||||||
|
if (transcodingJob != null && transcodingJob.HasExited)
|
||||||
|
{
|
||||||
|
// Transcoding job is over, so assume all existing files are ready
|
||||||
|
Logger.LogDebug("serving up {0} as transcode is over", segmentPath);
|
||||||
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segmentFileExists)
|
|
||||||
{
|
|
||||||
var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
|
var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
|
||||||
|
|
||||||
// If requested segment is less than transcoding position, we can't transcode backwards, so assume it's ready
|
// If requested segment is less than transcoding position, we can't transcode backwards, so assume it's ready
|
||||||
if (segmentIndex < currentTranscodingIndex)
|
if (segmentIndex < currentTranscodingIndex)
|
||||||
{
|
{
|
||||||
|
Logger.LogDebug("serving up {0} as transcode index {1} is past requested point {2}", segmentPath, currentTranscodingIndex, segmentIndex);
|
||||||
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var segmentFilename = Path.GetFileName(segmentPath);
|
var nextSegmentPath = GetSegmentPath(state, playlistPath, segmentIndex + 1);
|
||||||
|
if (transcodingJob != null)
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
try
|
while (!cancellationToken.IsCancellationRequested && !transcodingJob.HasExited)
|
||||||
{
|
{
|
||||||
var text = File.ReadAllText(playlistPath, Encoding.UTF8);
|
// To be considered ready, the segment file has to exist AND
|
||||||
|
// either the transcoding job should be done or next segment should also exist
|
||||||
// If it appears in the playlist, it's done
|
if (segmentExists)
|
||||||
if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
|
|
||||||
{
|
{
|
||||||
if (!segmentFileExists)
|
if (transcodingJob.HasExited || File.Exists(nextSegmentPath))
|
||||||
{
|
|
||||||
segmentFileExists = File.Exists(segmentPath);
|
|
||||||
}
|
|
||||||
if (segmentFileExists)
|
|
||||||
{
|
{
|
||||||
|
Logger.LogDebug("serving up {0} as it deemed ready", segmentPath);
|
||||||
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
//break;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
catch (IOException)
|
|
||||||
{
|
{
|
||||||
// May get an error if the file is locked
|
segmentExists = File.Exists(segmentPath);
|
||||||
|
if (segmentExists)
|
||||||
|
{
|
||||||
|
continue; // avoid unnecessary waiting if segment just became available
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(segmentPath))
|
||||||
|
{
|
||||||
|
Logger.LogWarning("cannot serve {0} as transcoding quit before we got there", segmentPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogDebug("serving {0} as it's on disk and transcoding stopped", segmentPath);
|
||||||
|
}
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogWarning("cannot serve {0} as it doesn't exist and no transcode is running", segmentPath);
|
||||||
|
}
|
||||||
|
|
||||||
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,6 +536,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
FileShare = FileShareMode.ReadWrite,
|
FileShare = FileShareMode.ReadWrite,
|
||||||
OnComplete = () =>
|
OnComplete = () =>
|
||||||
{
|
{
|
||||||
|
Logger.LogDebug("finished serving {0}", segmentPath);
|
||||||
if (transcodingJob != null)
|
if (transcodingJob != null)
|
||||||
{
|
{
|
||||||
transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
|
transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
|
||||||
@ -909,9 +925,23 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var keyFrameArg = string.Format(
|
var keyFrameArg = string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
" -force_key_frames:0 \"expr:gte(t,{0}+n_forced*{1})\"",
|
" -force_key_frames:0 \"expr:gte(t,{0}+n_forced*{1})\"",
|
||||||
GetStartNumber(state) * state.SegmentLength,
|
GetStartNumber(state) * state.SegmentLength,
|
||||||
state.SegmentLength.ToString(CultureInfo.InvariantCulture));
|
state.SegmentLength);
|
||||||
|
if (state.TargetFramerate.HasValue)
|
||||||
|
{
|
||||||
|
// This is to make sure keyframe interval is limited to our segment,
|
||||||
|
// as forcing keyframes is not enough.
|
||||||
|
// Example: we encoded half of desired length, then codec detected
|
||||||
|
// scene cut and inserted a keyframe; next forced keyframe would
|
||||||
|
// be created outside of segment, which breaks seeking.
|
||||||
|
keyFrameArg += string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
" -g {0} -keyint_min {0}",
|
||||||
|
(int)(state.SegmentLength * state.TargetFramerate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||||
|
|
||||||
@ -955,6 +985,15 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
var threads = EncodingHelper.GetNumberOfThreads(state, encodingOptions, videoCodec);
|
var threads = EncodingHelper.GetNumberOfThreads(state, encodingOptions, videoCodec);
|
||||||
|
|
||||||
|
if (state.BaseRequest.BreakOnNonKeyFrames)
|
||||||
|
{
|
||||||
|
// FIXME: this is actually a workaround, as ideally it really should be the client which decides whether non-keyframe
|
||||||
|
// breakpoints are supported; but current implementation always uses "ffmpeg input seeking" which is liable
|
||||||
|
// to produce a missing part of video stream before first keyframe is encountered, which may lead to
|
||||||
|
// awkward cases like a few starting HLS segments having no video whatsoever, which breaks hls.js
|
||||||
|
Logger.LogInformation("Current HLS implementation doesn't support non-keyframe breaks but one is requested, ignoring that request");
|
||||||
|
state.BaseRequest.BreakOnNonKeyFrames = false;
|
||||||
|
}
|
||||||
var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions);
|
var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions);
|
||||||
|
|
||||||
// If isEncoding is true we're actually starting ffmpeg
|
// If isEncoding is true we're actually starting ffmpeg
|
||||||
@ -965,14 +1004,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
|
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
|
||||||
|
|
||||||
var timeDeltaParam = string.Empty;
|
|
||||||
|
|
||||||
if (isEncoding && state.TargetFramerate > 0)
|
|
||||||
{
|
|
||||||
float startTime = 1 / (state.TargetFramerate.Value * 2);
|
|
||||||
timeDeltaParam = string.Format(CultureInfo.InvariantCulture, "-segment_time_delta {0:F3}", startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
|
var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
|
||||||
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -980,7 +1011,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
}
|
}
|
||||||
|
|
||||||
return string.Format(
|
return string.Format(
|
||||||
"{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
|
"{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f hls -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {6} -individual_header_trailer 0 -hls_segment_type {7} -start_number {8} -hls_segment_filename \"{9}\" -hls_playlist_type vod -hls_list_size 0 -y \"{10}\"",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
EncodingHelper.GetInputArgument(state, encodingOptions),
|
EncodingHelper.GetInputArgument(state, encodingOptions),
|
||||||
threads,
|
threads,
|
||||||
@ -988,11 +1019,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
GetVideoArguments(state, encodingOptions),
|
GetVideoArguments(state, encodingOptions),
|
||||||
GetAudioArguments(state, encodingOptions),
|
GetAudioArguments(state, encodingOptions),
|
||||||
state.SegmentLength.ToString(CultureInfo.InvariantCulture),
|
state.SegmentLength.ToString(CultureInfo.InvariantCulture),
|
||||||
|
segmentFormat,
|
||||||
startNumberParam,
|
startNumberParam,
|
||||||
outputPath,
|
|
||||||
outputTsArg,
|
outputTsArg,
|
||||||
timeDeltaParam,
|
outputPath
|
||||||
segmentFormat
|
|
||||||
).Trim();
|
).Trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,13 +279,12 @@ namespace MediaBrowser.Api.Subtitles
|
|||||||
await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
|
await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
_providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem)), RefreshPriority.High);
|
_providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, "Error downloading subtitles");
|
Logger.LogError(ex, "Error downloading subtitles");
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,11 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
NameContains = query.NameContains ?? query.SearchTerm
|
NameContains = query.NameContains ?? query.SearchTerm
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (query.IsFavorite ?? false && query.User != null)
|
||||||
|
{
|
||||||
|
items = items.Where(i => UserDataRepository.GetUserData(query.User, i).IsFavorite).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
return new QueryResult<(BaseItem, ItemCounts)>
|
return new QueryResult<(BaseItem, ItemCounts)>
|
||||||
{
|
{
|
||||||
TotalRecordCount = items.Count,
|
TotalRecordCount = items.Count,
|
||||||
|
@ -413,7 +413,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
if (!hasMetdata)
|
if (!hasMetdata)
|
||||||
{
|
{
|
||||||
var options = new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem))
|
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
{
|
{
|
||||||
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
|
@ -4,7 +4,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using static MediaBrowser.Common.HexHelper;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Cryptography
|
namespace MediaBrowser.Common.Cryptography
|
||||||
{
|
{
|
||||||
@ -102,13 +101,13 @@ namespace MediaBrowser.Common.Cryptography
|
|||||||
// Check if the string also contains a salt
|
// Check if the string also contains a salt
|
||||||
if (splitted.Length - index == 2)
|
if (splitted.Length - index == 2)
|
||||||
{
|
{
|
||||||
salt = FromHexString(splitted[index++]);
|
salt = Hex.Decode(splitted[index++]);
|
||||||
hash = FromHexString(splitted[index++]);
|
hash = Hex.Decode(splitted[index++]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
salt = Array.Empty<byte>();
|
salt = Array.Empty<byte>();
|
||||||
hash = FromHexString(splitted[index++]);
|
hash = Hex.Decode(splitted[index++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PasswordHash(id, hash, salt, parameters);
|
return new PasswordHash(id, hash, salt, parameters);
|
||||||
@ -124,10 +123,10 @@ namespace MediaBrowser.Common.Cryptography
|
|||||||
stringBuilder.Append('$');
|
stringBuilder.Append('$');
|
||||||
foreach (var pair in _parameters)
|
foreach (var pair in _parameters)
|
||||||
{
|
{
|
||||||
stringBuilder.Append(pair.Key);
|
stringBuilder.Append(pair.Key)
|
||||||
stringBuilder.Append('=');
|
.Append('=')
|
||||||
stringBuilder.Append(pair.Value);
|
.Append(pair.Value)
|
||||||
stringBuilder.Append(',');
|
.Append(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove last ','
|
// Remove last ','
|
||||||
@ -137,21 +136,19 @@ namespace MediaBrowser.Common.Cryptography
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
var str = new StringBuilder();
|
var str = new StringBuilder()
|
||||||
str.Append('$');
|
.Append('$')
|
||||||
str.Append(Id);
|
.Append(Id);
|
||||||
SerializeParameters(str);
|
SerializeParameters(str);
|
||||||
|
|
||||||
if (Salt.Length != 0)
|
if (Salt.Length != 0)
|
||||||
{
|
{
|
||||||
str.Append('$');
|
str.Append('$')
|
||||||
str.Append(ToHexString(Salt));
|
.Append(Hex.Encode(Salt, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
str.Append('$');
|
return str.Append('$')
|
||||||
str.Append(ToHexString(Hash));
|
.Append(Hex.Encode(Hash, false)).ToString();
|
||||||
|
|
||||||
return str.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Extensions
|
|
||||||
{
|
|
||||||
// The MS CollectionExtensions are only available in netcoreapp
|
|
||||||
public static class CollectionExtensions
|
|
||||||
{
|
|
||||||
public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)
|
|
||||||
{
|
|
||||||
dictionary.TryGetValue(key, out var ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copies all the elements of the current collection to the specified list
|
|
||||||
/// starting at the specified destination array index. The index is specified as a 32-bit integer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source">The current collection that is the source of the elements.</param>
|
|
||||||
/// <param name="destination">The list that is the destination of the elements copied from the current collection.</param>
|
|
||||||
/// <param name="index">A 32-bit integer that represents the index in <c>destination</c> at which copying begins.</param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public static void CopyTo<T>(this IReadOnlyList<T> source, IList<T> destination, int index = 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < source.Count; i++)
|
|
||||||
{
|
|
||||||
destination[index + i] = source[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copies all the elements of the current collection to the specified list
|
|
||||||
/// starting at the specified destination array index. The index is specified as a 32-bit integer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source">The current collection that is the source of the elements.</param>
|
|
||||||
/// <param name="destination">The list that is the destination of the elements copied from the current collection.</param>
|
|
||||||
/// <param name="index">A 32-bit integer that represents the index in <c>destination</c> at which copying begins.</param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public static void CopyTo<T>(this IReadOnlyCollection<T> source, IList<T> destination, int index = 0)
|
|
||||||
{
|
|
||||||
foreach (T item in source)
|
|
||||||
{
|
|
||||||
destination[index++] = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
26
MediaBrowser.Common/Extensions/CopyToExtensions.cs
Normal file
26
MediaBrowser.Common/Extensions/CopyToExtensions.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides <c>CopyTo</c> extensions methods for <see cref="IReadOnlyList{T}" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class CollectionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Copies all the elements of the current collection to the specified list
|
||||||
|
/// starting at the specified destination array index. The index is specified as a 32-bit integer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The current collection that is the source of the elements.</param>
|
||||||
|
/// <param name="destination">The list that is the destination of the elements copied from the current collection.</param>
|
||||||
|
/// <param name="index">A 32-bit integer that represents the index in <c>destination</c> at which copying begins.</param>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public static void CopyTo<T>(this IReadOnlyList<T> source, IList<T> destination, int index = 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < source.Count; i++)
|
||||||
|
{
|
||||||
|
destination[index + i] = source[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
MediaBrowser.Common/Hex.cs
Normal file
94
MediaBrowser.Common/Hex.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encoding and decoding hex strings.
|
||||||
|
/// </summary>
|
||||||
|
public static class Hex
|
||||||
|
{
|
||||||
|
internal const string HexCharsLower = "0123456789abcdef";
|
||||||
|
internal const string HexCharsUpper = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
internal const int LastHexSymbol = 0x66; // 102: f
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Map from an ASCII char to its hex value shifted,
|
||||||
|
/// e.g. <c>b</c> -> 11. 0xFF means it's not a hex symbol.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
internal static ReadOnlySpan<byte> HexLookup => new byte[] {
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encodes <c>bytes</c> as a hex string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bytes"></param>
|
||||||
|
/// <param name="lowercase"></param>
|
||||||
|
/// <returns><c>bytes</c> as a hex string.</returns>
|
||||||
|
public static string Encode(ReadOnlySpan<byte> bytes, bool lowercase = true)
|
||||||
|
{
|
||||||
|
var hexChars = lowercase ? HexCharsLower : HexCharsUpper;
|
||||||
|
|
||||||
|
// TODO: use string.Create when it's supports spans
|
||||||
|
// Ref: https://github.com/dotnet/corefx/issues/29120
|
||||||
|
char[] s = new char[bytes.Length * 2];
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < bytes.Length; i++)
|
||||||
|
{
|
||||||
|
s[j++] = hexChars[bytes[i] >> 4];
|
||||||
|
s[j++] = hexChars[bytes[i] & 0x0f];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a hex string into bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The <see cref="string" />.</param>
|
||||||
|
/// <returns>The decoded bytes.</returns>
|
||||||
|
public static byte[] Decode(ReadOnlySpan<char> str)
|
||||||
|
{
|
||||||
|
if (str.Length == 0)
|
||||||
|
{
|
||||||
|
return Array.Empty<byte>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var unHex = HexLookup;
|
||||||
|
|
||||||
|
int byteLen = str.Length / 2;
|
||||||
|
byte[] bytes = new byte[byteLen];
|
||||||
|
int i = 0;
|
||||||
|
for (int j = 0; j < byteLen; j++)
|
||||||
|
{
|
||||||
|
byte a;
|
||||||
|
byte b;
|
||||||
|
if (str[i] > LastHexSymbol
|
||||||
|
|| (a = unHex[str[i++]]) == 0xFF
|
||||||
|
|| str[i] > LastHexSymbol
|
||||||
|
|| (b = unHex[str[i++]]) == 0xFF)
|
||||||
|
{
|
||||||
|
ThrowArgumentException(nameof(str));
|
||||||
|
break; // Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes[j] = (byte)((a * 16) | b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
private static void ThrowArgumentException(string paramName)
|
||||||
|
=> throw new ArgumentException("Character is not a hex symbol.", paramName);
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common
|
|
||||||
{
|
|
||||||
public static class HexHelper
|
|
||||||
{
|
|
||||||
public static byte[] FromHexString(string str)
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[str.Length / 2];
|
|
||||||
for (int i = 0; i < str.Length; i += 2)
|
|
||||||
{
|
|
||||||
bytes[i / 2] = byte.Parse(str.Substring(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToHexString(byte[] bytes)
|
|
||||||
=> BitConverter.ToString(bytes).Replace("-", "");
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,7 +12,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
@ -89,7 +89,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
var locations = PhysicalLocations;
|
var locations = PhysicalLocations;
|
||||||
|
|
||||||
var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations;
|
var newLocations = CreateResolveArgs(new DirectoryService(FileSystem), false).PhysicalLocations;
|
||||||
|
|
||||||
if (!locations.SequenceEqual(newLocations))
|
if (!locations.SequenceEqual(newLocations))
|
||||||
{
|
{
|
||||||
|
@ -1345,7 +1345,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
public Task RefreshMetadata(CancellationToken cancellationToken)
|
public Task RefreshMetadata(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken);
|
return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void TriggerOnRefreshStart()
|
protected virtual void TriggerOnRefreshStart()
|
||||||
@ -2198,7 +2198,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public virtual void ChangedExternally()
|
public virtual void ChangedExternally()
|
||||||
{
|
{
|
||||||
ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
|
ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(new DirectoryService(FileSystem))
|
||||||
{
|
{
|
||||||
|
|
||||||
}, RefreshPriority.High);
|
}, RefreshPriority.High);
|
||||||
|
@ -171,7 +171,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
var locations = PhysicalLocations;
|
var locations = PhysicalLocations;
|
||||||
|
|
||||||
var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations;
|
var newLocations = CreateResolveArgs(new DirectoryService(FileSystem), false).PhysicalLocations;
|
||||||
|
|
||||||
if (!locations.SequenceEqual(newLocations))
|
if (!locations.SequenceEqual(newLocations))
|
||||||
{
|
{
|
||||||
|
@ -216,7 +216,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
|
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)));
|
return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(FileSystem)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -148,7 +148,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
Name = newName;
|
Name = newName;
|
||||||
|
|
||||||
return RefreshMetadata(
|
return RefreshMetadata(
|
||||||
new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
|
new MetadataRefreshOptions(new DirectoryService(FileSystem))
|
||||||
{
|
{
|
||||||
ReplaceAllMetadata = true,
|
ReplaceAllMetadata = true,
|
||||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -2168,7 +2168,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
// Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking
|
// Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking
|
||||||
if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase)
|
if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase)
|
||||||
&& state.TranscodingType != TranscodingJobType.Progressive
|
&& state.TranscodingType != TranscodingJobType.Progressive
|
||||||
&& state.EnableBreakOnNonKeyFrames(outputVideoCodec))
|
&& !state.EnableBreakOnNonKeyFrames(outputVideoCodec)
|
||||||
|
&& (state.BaseRequest.StartTimeTicks ?? 0) > 0)
|
||||||
{
|
{
|
||||||
inputModifier += " -noaccurate_seek";
|
inputModifier += " -noaccurate_seek";
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public class DirectoryService : IDirectoryService
|
public class DirectoryService : IDirectoryService
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
|
||||||
private readonly Dictionary<string, FileSystemMetadata[]> _cache = new Dictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, FileSystemMetadata[]> _cache = new Dictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
|
||||||
@ -17,9 +15,8 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
|
|
||||||
private readonly Dictionary<string, List<string>> _filePathCache = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, List<string>> _filePathCache = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
public DirectoryService(ILogger logger, IFileSystem fileSystem)
|
public DirectoryService(IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +24,6 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
{
|
{
|
||||||
if (!_cache.TryGetValue(path, out FileSystemMetadata[] entries))
|
if (!_cache.TryGetValue(path, out FileSystemMetadata[] entries))
|
||||||
{
|
{
|
||||||
//_logger.LogDebug("Getting files for " + path);
|
|
||||||
|
|
||||||
entries = _fileSystem.GetFileSystemEntries(path).ToArray();
|
entries = _fileSystem.GetFileSystemEntries(path).ToArray();
|
||||||
|
|
||||||
//_cache.TryAdd(path, entries);
|
//_cache.TryAdd(path, entries);
|
||||||
@ -49,6 +44,7 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
list.Add(item);
|
list.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +85,5 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ namespace MediaBrowser.Controller.Subtitles
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Searches the subtitles.
|
/// Searches the subtitles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<RemoteSubtitleInfo[]> SearchSubtitles(Video video,
|
Task<RemoteSubtitleInfo[]> SearchSubtitles(
|
||||||
|
Video video,
|
||||||
string language,
|
string language,
|
||||||
bool? isPerfectMatch,
|
bool? isPerfectMatch,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
@ -34,8 +35,9 @@ namespace MediaBrowser.Controller.Subtitles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{IEnumerable{RemoteSubtitleInfo}}.</returns>
|
/// <returns>Task{RemoteSubtitleInfo[]}.</returns>
|
||||||
Task<RemoteSubtitleInfo[]> SearchSubtitles(SubtitleSearchRequest request,
|
Task<RemoteSubtitleInfo[]> SearchSubtitles(
|
||||||
|
SubtitleSearchRequest request,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -53,7 +55,7 @@ namespace MediaBrowser.Controller.Subtitles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The identifier.</param>
|
/// <param name="id">The identifier.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{SubtitleResponse}.</returns>
|
/// <returns><see cref="Task{SubtitleResponse}" />.</returns>
|
||||||
Task<SubtitleResponse> GetRemoteSubtitles(string id, CancellationToken cancellationToken);
|
Task<SubtitleResponse> GetRemoteSubtitles(string id, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.6.0" />
|
||||||
<PackageReference Include="UTF.Unknown" Version="2.1.0" />
|
<PackageReference Include="UTF.Unknown" Version="2.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
namespace MediaBrowser.Model.IO
|
namespace MediaBrowser.Model.IO
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class StreamDefaults
|
/// Class StreamDefaults.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StreamDefaults
|
public static class StreamDefaults
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default copy to buffer size
|
/// The default copy to buffer size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int DefaultCopyToBufferSize = 81920;
|
public const int DefaultCopyToBufferSize = 81920;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default file stream buffer size
|
/// The default file stream buffer size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int DefaultFileStreamBufferSize = 4096;
|
public const int DefaultFileStreamBufferSize = 4096;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="4.6.0" />
|
<PackageReference Include="System.Text.Json" Version="4.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -16,9 +16,8 @@ namespace MediaBrowser.Providers.Books
|
|||||||
ILogger logger,
|
ILogger logger,
|
||||||
IProviderManager providerManager,
|
IProviderManager providerManager,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IUserDataManager userDataManager,
|
|
||||||
ILibraryManager libraryManager)
|
ILibraryManager libraryManager)
|
||||||
: base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,17 @@ namespace MediaBrowser.Providers.Books
|
|||||||
{
|
{
|
||||||
public class BookMetadataService : MetadataService<Book, BookInfo>
|
public class BookMetadataService : MetadataService<Book, BookInfo>
|
||||||
{
|
{
|
||||||
|
public BookMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<Book> source, MetadataResult<Book> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<Book> source, MetadataResult<Book> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
@ -20,9 +31,5 @@ namespace MediaBrowser.Providers.Books
|
|||||||
target.Item.SeriesName = source.Item.SeriesName;
|
target.Item.SeriesName = source.Item.SeriesName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BookMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,35 @@ namespace MediaBrowser.Providers.BoxSets
|
|||||||
{
|
{
|
||||||
public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo>
|
public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo>
|
||||||
{
|
{
|
||||||
|
public BoxSetMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool EnableUpdatingGenresFromChildren => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool EnableUpdatingOfficialRatingFromChildren => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool EnableUpdatingStudiosFromChildren => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool EnableUpdatingPremiereDateFromChildren => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override IList<BaseItem> GetChildrenForMetadataUpdates(BoxSet item)
|
protected override IList<BaseItem> GetChildrenForMetadataUpdates(BoxSet item)
|
||||||
{
|
{
|
||||||
return item.GetLinkedChildren();
|
return item.GetLinkedChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<BoxSet> source, MetadataResult<BoxSet> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<BoxSet> source, MetadataResult<BoxSet> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
@ -32,6 +56,7 @@ namespace MediaBrowser.Providers.BoxSets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override ItemUpdateType BeforeSaveInternal(BoxSet item, bool isFullRefresh, ItemUpdateType currentUpdateType)
|
protected override ItemUpdateType BeforeSaveInternal(BoxSet item, bool isFullRefresh, ItemUpdateType currentUpdateType)
|
||||||
{
|
{
|
||||||
var updateType = base.BeforeSaveInternal(item, isFullRefresh, currentUpdateType);
|
var updateType = base.BeforeSaveInternal(item, isFullRefresh, currentUpdateType);
|
||||||
@ -47,17 +72,5 @@ namespace MediaBrowser.Providers.BoxSets
|
|||||||
|
|
||||||
return updateType;
|
return updateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool EnableUpdatingGenresFromChildren => true;
|
|
||||||
|
|
||||||
protected override bool EnableUpdatingOfficialRatingFromChildren => true;
|
|
||||||
|
|
||||||
protected override bool EnableUpdatingStudiosFromChildren => true;
|
|
||||||
|
|
||||||
protected override bool EnableUpdatingPremiereDateFromChildren => true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,20 @@ namespace MediaBrowser.Providers.Channels
|
|||||||
{
|
{
|
||||||
public class ChannelMetadataService : MetadataService<Channel, ItemLookupInfo>
|
public class ChannelMetadataService : MetadataService<Channel, ItemLookupInfo>
|
||||||
{
|
{
|
||||||
|
public ChannelMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<Channel> source, MetadataResult<Channel> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<Channel> source, MetadataResult<Channel> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChannelMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,20 @@ namespace MediaBrowser.Providers.Folders
|
|||||||
{
|
{
|
||||||
public class CollectionFolderMetadataService : MetadataService<CollectionFolder, ItemLookupInfo>
|
public class CollectionFolderMetadataService : MetadataService<CollectionFolder, ItemLookupInfo>
|
||||||
{
|
{
|
||||||
|
public CollectionFolderMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<CollectionFolder> source, MetadataResult<CollectionFolder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<CollectionFolder> source, MetadataResult<CollectionFolder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CollectionFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,24 @@ namespace MediaBrowser.Providers.Folders
|
|||||||
{
|
{
|
||||||
public class FolderMetadataService : MetadataService<Folder, ItemLookupInfo>
|
public class FolderMetadataService : MetadataService<Folder, ItemLookupInfo>
|
||||||
{
|
{
|
||||||
|
public FolderMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
// Make sure the type-specific services get picked first
|
// Make sure the type-specific services get picked first
|
||||||
public override int Order => 10;
|
public override int Order => 10;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<Folder> source, MetadataResult<Folder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<Folder> source, MetadataResult<Folder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,20 @@ namespace MediaBrowser.Providers.Folders
|
|||||||
{
|
{
|
||||||
public class UserViewMetadataService : MetadataService<UserView, ItemLookupInfo>
|
public class UserViewMetadataService : MetadataService<UserView, ItemLookupInfo>
|
||||||
{
|
{
|
||||||
|
public UserViewMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<UserView> source, MetadataResult<UserView> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<UserView> source, MetadataResult<UserView> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserViewMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,20 @@ namespace MediaBrowser.Providers.Genres
|
|||||||
{
|
{
|
||||||
public class GenreMetadataService : MetadataService<Genre, ItemLookupInfo>
|
public class GenreMetadataService : MetadataService<Genre, ItemLookupInfo>
|
||||||
{
|
{
|
||||||
|
public GenreMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<Genre> source, MetadataResult<Genre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<Genre> source, MetadataResult<Genre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,20 @@ namespace MediaBrowser.Providers.LiveTv
|
|||||||
{
|
{
|
||||||
public class LiveTvMetadataService : MetadataService<LiveTvChannel, ItemLookupInfo>
|
public class LiveTvMetadataService : MetadataService<LiveTvChannel, ItemLookupInfo>
|
||||||
{
|
{
|
||||||
|
public LiveTvMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<LiveTvChannel> source, MetadataResult<LiveTvChannel> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<LiveTvChannel> source, MetadataResult<LiveTvChannel> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveTvMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
|
|
||||||
if (deleted)
|
if (deleted)
|
||||||
{
|
{
|
||||||
item.ValidateImages(new DirectoryService(_logger, _fileSystem));
|
item.ValidateImages(new DirectoryService(_fileSystem));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,16 +23,14 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
protected readonly ILogger Logger;
|
protected readonly ILogger Logger;
|
||||||
protected readonly IProviderManager ProviderManager;
|
protected readonly IProviderManager ProviderManager;
|
||||||
protected readonly IFileSystem FileSystem;
|
protected readonly IFileSystem FileSystem;
|
||||||
protected readonly IUserDataManager UserDataManager;
|
|
||||||
protected readonly ILibraryManager LibraryManager;
|
protected readonly ILibraryManager LibraryManager;
|
||||||
|
|
||||||
protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager)
|
protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
ServerConfigurationManager = serverConfigurationManager;
|
ServerConfigurationManager = serverConfigurationManager;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
ProviderManager = providerManager;
|
ProviderManager = providerManager;
|
||||||
FileSystem = fileSystem;
|
FileSystem = fileSystem;
|
||||||
UserDataManager = userDataManager;
|
|
||||||
LibraryManager = libraryManager;
|
LibraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, "Error getting file {path}", path);
|
Logger.LogError(ex, "Error getting file {Path}", path);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
|
|
||||||
return GetImageProviders(item, libraryOptions, options,
|
return GetImageProviders(item, libraryOptions, options,
|
||||||
new ImageRefreshOptions(
|
new ImageRefreshOptions(
|
||||||
new DirectoryService(_logger, _fileSystem)),
|
new DirectoryService(_fileSystem)),
|
||||||
includeDisabled)
|
includeDisabled)
|
||||||
.OfType<IRemoteImageProvider>();
|
.OfType<IRemoteImageProvider>();
|
||||||
}
|
}
|
||||||
@ -507,7 +507,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
|
|
||||||
var imageProviders = GetImageProviders(dummy, libraryOptions, options,
|
var imageProviders = GetImageProviders(dummy, libraryOptions, options,
|
||||||
new ImageRefreshOptions(
|
new ImageRefreshOptions(
|
||||||
new DirectoryService(_logger, _fileSystem)),
|
new DirectoryService(_fileSystem)),
|
||||||
true)
|
true)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
@ -11,15 +11,15 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.0.0" />
|
||||||
<PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
|
<PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
|
||||||
<PackageReference Include="PlaylistsNET" Version="1.0.4" />
|
<PackageReference Include="PlaylistsNET" Version="1.0.4" />
|
||||||
<PackageReference Include="TvDbSharper" Version="2.0.0" />
|
<PackageReference Include="TvDbSharper" Version="2.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -9,17 +9,20 @@ namespace MediaBrowser.Providers.Movies
|
|||||||
{
|
{
|
||||||
public class ImdbExternalId : IExternalId
|
public class ImdbExternalId : IExternalId
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public string Name => "IMDb";
|
public string Name => "IMDb";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Key => MetadataProviders.Imdb.ToString();
|
public string Key => MetadataProviders.Imdb.ToString();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string UrlFormatString => "https://www.imdb.com/title/{0}";
|
public string UrlFormatString => "https://www.imdb.com/title/{0}";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
{
|
{
|
||||||
// Supports images for tv movies
|
// Supports images for tv movies
|
||||||
var tvProgram = item as LiveTvProgram;
|
if (item is LiveTvProgram tvProgram && tvProgram.IsMovie)
|
||||||
if (tvProgram != null && tvProgram.IsMovie)
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -28,18 +31,18 @@ namespace MediaBrowser.Providers.Movies
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ImdbPersonExternalId : IExternalId
|
public class ImdbPersonExternalId : IExternalId
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public string Name => "IMDb";
|
public string Name => "IMDb";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Key => MetadataProviders.Imdb.ToString();
|
public string Key => MetadataProviders.Imdb.ToString();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string UrlFormatString => "https://www.imdb.com/name/{0}";
|
public string UrlFormatString => "https://www.imdb.com/name/{0}";
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
/// <inheritdoc />
|
||||||
{
|
public bool Supports(IHasProviderIds item) => item is Person;
|
||||||
return item is Person;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
@ -12,6 +11,17 @@ namespace MediaBrowser.Providers.Movies
|
|||||||
{
|
{
|
||||||
public class MovieMetadataService : MetadataService<Movie, MovieInfo>
|
public class MovieMetadataService : MetadataService<Movie, MovieInfo>
|
||||||
{
|
{
|
||||||
|
public MovieMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override bool IsFullLocalMetadata(Movie item)
|
protected override bool IsFullLocalMetadata(Movie item)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(item.Overview))
|
if (string.IsNullOrWhiteSpace(item.Overview))
|
||||||
@ -25,6 +35,7 @@ namespace MediaBrowser.Providers.Movies
|
|||||||
return base.IsFullLocalMetadata(item);
|
return base.IsFullLocalMetadata(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void MergeData(MetadataResult<Movie> source, MetadataResult<Movie> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<Movie> source, MetadataResult<Movie> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
@ -37,40 +48,5 @@ namespace MediaBrowser.Providers.Movies
|
|||||||
targetItem.CollectionName = sourceItem.CollectionName;
|
targetItem.CollectionName = sourceItem.CollectionName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MovieMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TrailerMetadataService : MetadataService<Trailer, TrailerInfo>
|
|
||||||
{
|
|
||||||
protected override bool IsFullLocalMetadata(Trailer item)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(item.Overview))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!item.ProductionYear.HasValue)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.IsFullLocalMetadata(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
|
||||||
{
|
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
|
||||||
|
|
||||||
if (replaceData || target.Item.TrailerTypes.Length == 0)
|
|
||||||
{
|
|
||||||
target.Item.TrailerTypes = source.Item.TrailerTypes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TrailerMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
49
MediaBrowser.Providers/Movies/TrailerMetadataService.cs
Normal file
49
MediaBrowser.Providers/Movies/TrailerMetadataService.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Providers.Manager;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Providers.Movies
|
||||||
|
{
|
||||||
|
public class TrailerMetadataService : MetadataService<Trailer, TrailerInfo>
|
||||||
|
{
|
||||||
|
public TrailerMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool IsFullLocalMetadata(Trailer item)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(item.Overview))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!item.ProductionYear.HasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return base.IsFullLocalMetadata(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
|
{
|
||||||
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
|
|
||||||
|
if (replaceData || target.Item.TrailerTypes.Length == 0)
|
||||||
|
{
|
||||||
|
target.Item.TrailerTypes = source.Item.TrailerTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,9 +20,8 @@ namespace MediaBrowser.Providers.Music
|
|||||||
ILogger logger,
|
ILogger logger,
|
||||||
IProviderManager providerManager,
|
IProviderManager providerManager,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IUserDataManager userDataManager,
|
|
||||||
ILibraryManager libraryManager)
|
ILibraryManager libraryManager)
|
||||||
: base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,10 +36,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override IList<BaseItem> GetChildrenForMetadataUpdates(MusicAlbum item)
|
protected override IList<BaseItem> GetChildrenForMetadataUpdates(MusicAlbum item)
|
||||||
{
|
=> item.GetRecursiveChildren(i => i is Audio);
|
||||||
return item.GetRecursiveChildren(i => i is Audio)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override ItemUpdateType UpdateMetadataFromChildren(MusicAlbum item, IList<BaseItem> children, bool isFullRefresh, ItemUpdateType currentUpdateType)
|
protected override ItemUpdateType UpdateMetadataFromChildren(MusicAlbum item, IList<BaseItem> children, bool isFullRefresh, ItemUpdateType currentUpdateType)
|
||||||
@ -53,20 +49,18 @@ namespace MediaBrowser.Providers.Music
|
|||||||
{
|
{
|
||||||
var name = children.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
var name = children.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(name))
|
if (!string.IsNullOrEmpty(name)
|
||||||
{
|
&& !string.Equals(item.Name, name, StringComparison.Ordinal))
|
||||||
if (!string.Equals(item.Name, name, StringComparison.Ordinal))
|
|
||||||
{
|
{
|
||||||
item.Name = name;
|
item.Name = name;
|
||||||
updateType = updateType | ItemUpdateType.MetadataEdit;
|
updateType |= ItemUpdateType.MetadataEdit;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var songs = children.Cast<Audio>().ToArray();
|
var songs = children.Cast<Audio>().ToArray();
|
||||||
|
|
||||||
updateType = updateType | SetAlbumArtistFromSongs(item, songs);
|
updateType |= SetAlbumArtistFromSongs(item, songs);
|
||||||
updateType = updateType | SetArtistsFromSongs(item, songs);
|
updateType |= SetArtistsFromSongs(item, songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateType;
|
return updateType;
|
||||||
|
@ -13,26 +13,35 @@ namespace MediaBrowser.Providers.Music
|
|||||||
{
|
{
|
||||||
public class ArtistMetadataService : MetadataService<MusicArtist, ArtistInfo>
|
public class ArtistMetadataService : MetadataService<MusicArtist, ArtistInfo>
|
||||||
{
|
{
|
||||||
|
public ArtistMetadataService(
|
||||||
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
ILogger logger,
|
||||||
|
IProviderManager providerManager,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool EnableUpdatingGenresFromChildren => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override IList<BaseItem> GetChildrenForMetadataUpdates(MusicArtist item)
|
protected override IList<BaseItem> GetChildrenForMetadataUpdates(MusicArtist item)
|
||||||
{
|
{
|
||||||
return item.IsAccessedByName ?
|
return item.IsAccessedByName
|
||||||
item.GetTaggedItems(new InternalItemsQuery
|
? item.GetTaggedItems(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IsFolder = false
|
IsFolder = false
|
||||||
}) :
|
})
|
||||||
item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder);
|
: item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool EnableUpdatingGenresFromChildren => true;
|
/// <inheritdoc />
|
||||||
|
|
||||||
protected override void MergeData(MetadataResult<MusicArtist> source, MetadataResult<MusicArtist> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
protected override void MergeData(MetadataResult<MusicArtist> source, MetadataResult<MusicArtist> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,14 @@ namespace MediaBrowser.Providers.Music
|
|||||||
_json = json;
|
_json = json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "TheAudioDB";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
// After embedded and fanart
|
||||||
|
public int Order => 2;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||||
{
|
{
|
||||||
return new List<ImageType>
|
return new List<ImageType>
|
||||||
@ -34,6 +42,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var id = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
var id = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||||
@ -82,6 +91,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return _httpClient.GetResponse(new HttpRequestOptions
|
return _httpClient.GetResponse(new HttpRequestOptions
|
||||||
@ -91,13 +101,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "TheAudioDB";
|
/// <inheritdoc />
|
||||||
// After embedded and fanart
|
public bool Supports(BaseItem item) => item is MusicAlbum;
|
||||||
public int Order => 2;
|
|
||||||
|
|
||||||
public bool Supports(BaseItem item)
|
|
||||||
{
|
|
||||||
return item is MusicAlbum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
@ -26,8 +27,6 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
public static AudioDbAlbumProvider Current;
|
public static AudioDbAlbumProvider Current;
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
|
||||||
|
|
||||||
public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClient httpClient, IJsonSerializer json)
|
public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClient httpClient, IJsonSerializer json)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
@ -38,11 +37,18 @@ namespace MediaBrowser.Providers.Music
|
|||||||
Current = this;
|
Current = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken)
|
/// <inheritdoc />
|
||||||
{
|
public string Name => "TheAudioDB";
|
||||||
return Task.FromResult((IEnumerable<RemoteSearchResult>)new List<RemoteSearchResult>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
// After music brainz
|
||||||
|
public int Order => 1;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken)
|
||||||
|
=> Task.FromResult(Enumerable.Empty<RemoteSearchResult>());
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo info, CancellationToken cancellationToken)
|
public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = new MetadataResult<MusicAlbum>();
|
var result = new MetadataResult<MusicAlbum>();
|
||||||
@ -77,7 +83,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(result.intYearReleased))
|
if (!string.IsNullOrEmpty(result.intYearReleased))
|
||||||
{
|
{
|
||||||
item.ProductionYear = int.Parse(result.intYearReleased, _usCulture);
|
item.ProductionYear = int.Parse(result.intYearReleased, CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(result.strGenre))
|
if (!string.IsNullOrEmpty(result.strGenre))
|
||||||
@ -126,8 +132,6 @@ namespace MediaBrowser.Providers.Music
|
|||||||
item.Overview = (overview ?? string.Empty).StripHtml();
|
item.Overview = (overview ?? string.Empty).StripHtml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "TheAudioDB";
|
|
||||||
|
|
||||||
internal Task EnsureInfo(string musicBrainzReleaseGroupId, CancellationToken cancellationToken)
|
internal Task EnsureInfo(string musicBrainzReleaseGroupId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var xmlPath = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
|
var xmlPath = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
|
||||||
@ -155,22 +159,20 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
|
||||||
using (var httpResponse = await _httpClient.SendAsync(new HttpRequestOptions
|
using (var httpResponse = await _httpClient.SendAsync(
|
||||||
|
new HttpRequestOptions
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
CancellationToken = cancellationToken
|
CancellationToken = cancellationToken
|
||||||
|
|
||||||
}, "GET").ConfigureAwait(false))
|
},
|
||||||
{
|
"GET").ConfigureAwait(false))
|
||||||
using (var response = httpResponse.Content)
|
using (var response = httpResponse.Content)
|
||||||
{
|
|
||||||
using (var xmlFileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
using (var xmlFileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||||
{
|
{
|
||||||
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
|
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetAlbumDataPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId)
|
private static string GetAlbumDataPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId)
|
||||||
{
|
{
|
||||||
@ -192,8 +194,6 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
return Path.Combine(dataPath, "album.json");
|
return Path.Combine(dataPath, "album.json");
|
||||||
}
|
}
|
||||||
// After music brainz
|
|
||||||
public int Order => 1;
|
|
||||||
|
|
||||||
public class Album
|
public class Album
|
||||||
{
|
{
|
||||||
@ -242,6 +242,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
public List<Album> album { get; set; }
|
public List<Album> album { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -25,6 +25,14 @@ namespace MediaBrowser.Providers.Music
|
|||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "TheAudioDB";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
// After fanart
|
||||||
|
public int Order => 1;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||||
{
|
{
|
||||||
return new List<ImageType>
|
return new List<ImageType>
|
||||||
@ -36,6 +44,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
|
var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
|
||||||
@ -133,13 +142,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "TheAudioDB";
|
/// <inheritdoc />
|
||||||
|
public bool Supports(BaseItem item) => item is MusicArtist;
|
||||||
public bool Supports(BaseItem item)
|
|
||||||
{
|
|
||||||
return item is MusicArtist;
|
|
||||||
}
|
|
||||||
// After fanart
|
|
||||||
public int Order => 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
@ -37,11 +38,18 @@ namespace MediaBrowser.Providers.Music
|
|||||||
Current = this;
|
Current = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
|
/// <inheritdoc />
|
||||||
{
|
public string Name => "TheAudioDB";
|
||||||
return Task.FromResult((IEnumerable<RemoteSearchResult>)new List<RemoteSearchResult>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
// After musicbrainz
|
||||||
|
public int Order => 1;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
|
||||||
|
=> Task.FromResult(Enumerable.Empty<RemoteSearchResult>());
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo info, CancellationToken cancellationToken)
|
public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = new MetadataResult<MusicArtist>();
|
var result = new MetadataResult<MusicArtist>();
|
||||||
@ -114,21 +122,17 @@ namespace MediaBrowser.Providers.Music
|
|||||||
item.Overview = (overview ?? string.Empty).StripHtml();
|
item.Overview = (overview ?? string.Empty).StripHtml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "TheAudioDB";
|
|
||||||
|
|
||||||
internal Task EnsureArtistInfo(string musicBrainzId, CancellationToken cancellationToken)
|
internal Task EnsureArtistInfo(string musicBrainzId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var xmlPath = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
var xmlPath = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath);
|
var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath);
|
||||||
|
|
||||||
if (fileInfo.Exists)
|
if (fileInfo.Exists
|
||||||
{
|
&& (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
||||||
if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return DownloadArtistInfo(musicBrainzId, cancellationToken);
|
return DownloadArtistInfo(musicBrainzId, cancellationToken);
|
||||||
}
|
}
|
||||||
@ -141,14 +145,14 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
||||||
|
|
||||||
using (var httpResponse = await _httpClient.SendAsync(new HttpRequestOptions
|
using (var httpResponse = await _httpClient.SendAsync(
|
||||||
|
new HttpRequestOptions
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
CancellationToken = cancellationToken,
|
CancellationToken = cancellationToken,
|
||||||
BufferContent = true
|
BufferContent = true
|
||||||
|
},
|
||||||
}, "GET").ConfigureAwait(false))
|
"GET").ConfigureAwait(false))
|
||||||
{
|
|
||||||
using (var response = httpResponse.Content)
|
using (var response = httpResponse.Content)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
@ -159,7 +163,6 @@ namespace MediaBrowser.Providers.Music
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the artist data path.
|
/// Gets the artist data path.
|
||||||
@ -168,11 +171,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
/// <param name="musicBrainzArtistId">The music brainz artist identifier.</param>
|
/// <param name="musicBrainzArtistId">The music brainz artist identifier.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private static string GetArtistDataPath(IApplicationPaths appPaths, string musicBrainzArtistId)
|
private static string GetArtistDataPath(IApplicationPaths appPaths, string musicBrainzArtistId)
|
||||||
{
|
=> Path.Combine(GetArtistDataPath(appPaths), musicBrainzArtistId);
|
||||||
var dataPath = Path.Combine(GetArtistDataPath(appPaths), musicBrainzArtistId);
|
|
||||||
|
|
||||||
return dataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the artist data path.
|
/// Gets the artist data path.
|
||||||
@ -180,11 +179,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
/// <param name="appPaths">The application paths.</param>
|
/// <param name="appPaths">The application paths.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private static string GetArtistDataPath(IApplicationPaths appPaths)
|
private static string GetArtistDataPath(IApplicationPaths appPaths)
|
||||||
{
|
=> Path.Combine(appPaths.CachePath, "audiodb-artist");
|
||||||
var dataPath = Path.Combine(appPaths.CachePath, "audiodb-artist");
|
|
||||||
|
|
||||||
return dataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetArtistInfoPath(IApplicationPaths appPaths, string musicBrainzArtistId)
|
internal static string GetArtistInfoPath(IApplicationPaths appPaths, string musicBrainzArtistId)
|
||||||
{
|
{
|
||||||
@ -242,9 +237,8 @@ namespace MediaBrowser.Providers.Music
|
|||||||
{
|
{
|
||||||
public List<Artist> artists { get; set; }
|
public List<Artist> artists { get; set; }
|
||||||
}
|
}
|
||||||
// After musicbrainz
|
|
||||||
public int Order => 1;
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -6,58 +6,63 @@ namespace MediaBrowser.Providers.Music
|
|||||||
{
|
{
|
||||||
public class AudioDbAlbumExternalId : IExternalId
|
public class AudioDbAlbumExternalId : IExternalId
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public string Name => "TheAudioDb";
|
public string Name => "TheAudioDb";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Key => MetadataProviders.AudioDbAlbum.ToString();
|
public string Key => MetadataProviders.AudioDbAlbum.ToString();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
|
public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
{
|
=> item is MusicAlbum;
|
||||||
return item is MusicAlbum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AudioDbOtherAlbumExternalId : IExternalId
|
public class AudioDbOtherAlbumExternalId : IExternalId
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public string Name => "TheAudioDb Album";
|
public string Name => "TheAudioDb Album";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Key => MetadataProviders.AudioDbAlbum.ToString();
|
public string Key => MetadataProviders.AudioDbAlbum.ToString();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
|
public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
/// <inheritdoc />
|
||||||
{
|
public bool Supports(IHasProviderIds item) => item is Audio;
|
||||||
return item is Audio;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AudioDbArtistExternalId : IExternalId
|
public class AudioDbArtistExternalId : IExternalId
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public string Name => "TheAudioDb";
|
public string Name => "TheAudioDb";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Key => MetadataProviders.AudioDbArtist.ToString();
|
public string Key => MetadataProviders.AudioDbArtist.ToString();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
|
public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
/// <inheritdoc />
|
||||||
{
|
public bool Supports(IHasProviderIds item) => item is MusicArtist;
|
||||||
return item is MusicArtist;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AudioDbOtherArtistExternalId : IExternalId
|
public class AudioDbOtherArtistExternalId : IExternalId
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public string Name => "TheAudioDb Artist";
|
public string Name => "TheAudioDb Artist";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Key => MetadataProviders.AudioDbArtist.ToString();
|
public string Key => MetadataProviders.AudioDbArtist.ToString();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
|
public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
{
|
=> item is Audio || item is MusicAlbum;
|
||||||
return item is Audio || item is MusicAlbum;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -16,9 +16,8 @@ namespace MediaBrowser.Providers.Music
|
|||||||
ILogger logger,
|
ILogger logger,
|
||||||
IProviderManager providerManager,
|
IProviderManager providerManager,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IUserDataManager userDataManager,
|
|
||||||
ILibraryManager libraryManager)
|
ILibraryManager libraryManager)
|
||||||
: base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user