mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-02-17 18:12:24 +00:00
Compare commits
42 Commits
v10.11.0-r
...
v10.11.0-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2c0799489 | ||
|
|
ad133eb6b9 | ||
|
|
50180adc53 | ||
|
|
bd94ca3071 | ||
|
|
869b4f8bbf | ||
|
|
a4d856360b | ||
|
|
beca405ad4 | ||
|
|
c0be325b89 | ||
|
|
dea500b26b | ||
|
|
47634e731a | ||
|
|
cd1d11366e | ||
|
|
76dfaead8b | ||
|
|
5eef85f027 | ||
|
|
e6a7530ced | ||
|
|
00be664b9e | ||
|
|
e1d0f7d1e5 | ||
|
|
0a4ff3f3c0 | ||
|
|
21f214b1a6 | ||
|
|
0650666497 | ||
|
|
877899dcc2 | ||
|
|
bf2f8ec633 | ||
|
|
2eff03b03e | ||
|
|
103932e4fb | ||
|
|
2b94b3b5f6 | ||
|
|
64032e8656 | ||
|
|
329ce8d4c2 | ||
|
|
2a7c924904 | ||
|
|
72664a68bc | ||
|
|
3ec123b616 | ||
|
|
376220661b | ||
|
|
9e88121647 | ||
|
|
c7c7b30d28 | ||
|
|
601ce4c3b1 | ||
|
|
fcc7f53e81 | ||
|
|
e3acf08acc | ||
|
|
c60139a32c | ||
|
|
6d4efe6523 | ||
|
|
43a955dded | ||
|
|
7320e10329 | ||
|
|
5b544bf1ed | ||
|
|
1a1d9b2404 | ||
|
|
96a05276a6 |
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "9.0.7",
|
||||
"version": "9.0.8",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
|
||||
8
.github/workflows/ci-codeql-analysis.yml
vendored
8
.github/workflows/ci-codeql-analysis.yml
vendored
@@ -20,18 +20,18 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
uses: github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.9
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-extended
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
uses: github/codeql-action/autobuild@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.9
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
uses: github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.9
|
||||
|
||||
8
.github/workflows/ci-compat.yml
vendored
8
.github/workflows/ci-compat.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
permissions: read-all
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
permissions: read-all
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
@@ -85,13 +85,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download abi-head
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: abi-head
|
||||
path: abi-head
|
||||
|
||||
- name: Download abi-base
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: abi-base
|
||||
path: abi-base
|
||||
|
||||
12
.github/workflows/ci-openapi.yml
vendored
12
.github/workflows/ci-openapi.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
permissions: read-all
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
permissions: read-all
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
@@ -80,12 +80,12 @@ jobs:
|
||||
- openapi-base
|
||||
steps:
|
||||
- name: Download openapi-head
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: openapi-head
|
||||
path: openapi-head
|
||||
- name: Download openapi-base
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: openapi-base
|
||||
path: openapi-base
|
||||
@@ -158,7 +158,7 @@ jobs:
|
||||
run: |-
|
||||
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
|
||||
- name: Download openapi-head
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: openapi-head
|
||||
path: openapi-head
|
||||
@@ -220,7 +220,7 @@ jobs:
|
||||
run: |-
|
||||
echo "JELLYFIN_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
- name: Download openapi-head
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: openapi-head
|
||||
path: openapi-head
|
||||
|
||||
4
.github/workflows/ci-tests.yml
vendored
4
.github/workflows/ci-tests.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
runs-on: "${{ matrix.os }}"
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
||||
with:
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
--verbosity minimal
|
||||
|
||||
- name: Merge code coverage results
|
||||
uses: danielpalme/ReportGenerator-GitHub-Action@c1dd332d00304c5aa5d506aab698a5224a8fa24e # 5.4.11
|
||||
uses: danielpalme/ReportGenerator-GitHub-Action@c4c5175a441c6603ec614f5084386dabe0e2295b # v5.4.12
|
||||
with:
|
||||
reports: "**/coverage.cobertura.xml"
|
||||
targetdir: "merged/"
|
||||
|
||||
4
.github/workflows/commands.yml
vendored
4
.github/workflows/commands.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
reactions: '+1'
|
||||
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: pull in script
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: jellyfin/jellyfin-triage-script
|
||||
- name: install python
|
||||
|
||||
2
.github/workflows/issue-template-check.yml
vendored
2
.github/workflows/issue-template-check.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
issues: write
|
||||
steps:
|
||||
- name: pull in script
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: jellyfin/jellyfin-triage-script
|
||||
- name: install python
|
||||
|
||||
4
.github/workflows/release-bump-version.yaml
vendored
4
.github/workflows/release-bump-version.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
yq-version: v4.9.8
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ env.TAG_BRANCH }}
|
||||
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ env.TAG_BRANCH }}
|
||||
|
||||
|
||||
@@ -197,7 +197,6 @@
|
||||
- [Kenneth Cochran](https://github.com/kennethcochran)
|
||||
- [benedikt257](https://github.com/benedikt257)
|
||||
- [revam](https://github.com/revam)
|
||||
- [Jxiced](https://github.com/Jxiced)
|
||||
- [allesmi](https://github.com/allesmi)
|
||||
- [ThunderClapLP](https://github.com/ThunderClapLP)
|
||||
- [Shoham Peller](https://github.com/spellr)
|
||||
|
||||
@@ -26,29 +26,29 @@
|
||||
<PackageVersion Include="libse" Version="4.0.12" />
|
||||
<PackageVersion Include="LrcParser" Version="2025.623.0" />
|
||||
<PackageVersion Include="MetaBrainz.MusicBrainz" Version="6.1.0" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="4.14.0" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageVersion Include="MimeTypes" Version="2.5.2" />
|
||||
<PackageVersion Include="Morestachio" Version="5.0.1.631" />
|
||||
@@ -76,18 +76,18 @@
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.116.1" />
|
||||
<PackageVersion Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<PackageVersion Include="Svg.Skia" Version="3.0.4" />
|
||||
<PackageVersion Include="Svg.Skia" Version="3.0.5" />
|
||||
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
|
||||
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||
<PackageVersion Include="System.Globalization" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="9.0.8" />
|
||||
<PackageVersion Include="TagLibSharp" Version="2.3.0" />
|
||||
<PackageVersion Include="z440.atl.core" Version="7.2.0" />
|
||||
<PackageVersion Include="z440.atl.core" Version="7.3.0" />
|
||||
<PackageVersion Include="TMDbLib" Version="2.2.0" />
|
||||
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
|
||||
<PackageVersion Include="UTF.Unknown" Version="2.6.0" />
|
||||
<PackageVersion Include="Xunit.Priority" Version="1.1.6" />
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@@ -37,6 +38,77 @@ namespace Emby.Server.Implementations.Dto
|
||||
{
|
||||
public class DtoService : IDtoService
|
||||
{
|
||||
private static readonly FrozenDictionary<BaseItemKind, BaseItemKind[]> _relatedItemKinds = new Dictionary<BaseItemKind, BaseItemKind[]>
|
||||
{
|
||||
{
|
||||
BaseItemKind.Genre, [
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.Episode,
|
||||
BaseItemKind.Movie,
|
||||
BaseItemKind.LiveTvProgram,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicArtist,
|
||||
BaseItemKind.MusicVideo,
|
||||
BaseItemKind.Series,
|
||||
BaseItemKind.Trailer
|
||||
]
|
||||
},
|
||||
{
|
||||
BaseItemKind.MusicArtist, [
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicVideo
|
||||
]
|
||||
},
|
||||
{
|
||||
BaseItemKind.MusicGenre, [
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicArtist,
|
||||
BaseItemKind.MusicVideo
|
||||
]
|
||||
},
|
||||
{
|
||||
BaseItemKind.Person, [
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.Episode,
|
||||
BaseItemKind.Movie,
|
||||
BaseItemKind.LiveTvProgram,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicArtist,
|
||||
BaseItemKind.MusicVideo,
|
||||
BaseItemKind.Series,
|
||||
BaseItemKind.Trailer
|
||||
]
|
||||
},
|
||||
{
|
||||
BaseItemKind.Studio, [
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.Episode,
|
||||
BaseItemKind.Movie,
|
||||
BaseItemKind.LiveTvProgram,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicArtist,
|
||||
BaseItemKind.MusicVideo,
|
||||
BaseItemKind.Series,
|
||||
BaseItemKind.Trailer
|
||||
]
|
||||
},
|
||||
{
|
||||
BaseItemKind.Year, [
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.Episode,
|
||||
BaseItemKind.Movie,
|
||||
BaseItemKind.LiveTvProgram,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicArtist,
|
||||
BaseItemKind.MusicVideo,
|
||||
BaseItemKind.Series,
|
||||
BaseItemKind.Trailer
|
||||
]
|
||||
}
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
private readonly ILogger<DtoService> _logger;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserDataManager _userDataRepository;
|
||||
@@ -102,21 +174,9 @@ namespace Emby.Server.Implementations.Dto
|
||||
(programTuples ??= []).Add((item, dto));
|
||||
}
|
||||
|
||||
if (item is IItemByName byName)
|
||||
if (options.ContainsField(ItemFields.ItemCounts))
|
||||
{
|
||||
if (options.ContainsField(ItemFields.ItemCounts))
|
||||
{
|
||||
var libraryItems = byName.GetTaggedItems(new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
DtoOptions = new DtoOptions(false)
|
||||
{
|
||||
EnableImages = false
|
||||
}
|
||||
});
|
||||
|
||||
SetItemByNameInfo(item, dto, libraryItems);
|
||||
}
|
||||
SetItemByNameInfo(dto, user);
|
||||
}
|
||||
|
||||
returnItems[index] = dto;
|
||||
@@ -147,34 +207,14 @@ namespace Emby.Server.Implementations.Dto
|
||||
LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (item is IItemByName itemByName
|
||||
&& options.ContainsField(ItemFields.ItemCounts))
|
||||
if (options.ContainsField(ItemFields.ItemCounts))
|
||||
{
|
||||
SetItemByNameInfo(
|
||||
item,
|
||||
dto,
|
||||
GetTaggedItems(
|
||||
itemByName,
|
||||
user,
|
||||
new DtoOptions(false)
|
||||
{
|
||||
EnableImages = false
|
||||
}));
|
||||
SetItemByNameInfo(dto, user);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<BaseItem> GetTaggedItems(IItemByName byName, User? user, DtoOptions options)
|
||||
{
|
||||
return byName.GetTaggedItems(
|
||||
new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
DtoOptions = options
|
||||
});
|
||||
}
|
||||
|
||||
private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User? user = null, BaseItem? owner = null)
|
||||
{
|
||||
var dto = new BaseItemDto
|
||||
@@ -315,11 +355,15 @@ namespace Emby.Server.Implementations.Dto
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// TODO refactor this to use the new SetItemByNameInfo.
|
||||
/// Some callers already have the counts extracted so no reason to retrieve them again.
|
||||
public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem>? taggedItems, User? user = null)
|
||||
{
|
||||
var dto = GetBaseItemDtoInternal(item, options, user);
|
||||
|
||||
if (taggedItems is not null && options.ContainsField(ItemFields.ItemCounts))
|
||||
if (options.ContainsField(ItemFields.ItemCounts)
|
||||
&& taggedItems is not null
|
||||
&& taggedItems.Count != 0)
|
||||
{
|
||||
SetItemByNameInfo(item, dto, taggedItems);
|
||||
}
|
||||
@@ -327,6 +371,57 @@ namespace Emby.Server.Implementations.Dto
|
||||
return dto;
|
||||
}
|
||||
|
||||
private void SetItemByNameInfo(BaseItemDto dto, User? user)
|
||||
{
|
||||
if (!_relatedItemKinds.TryGetValue(dto.Type, out var relatedItemKinds))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
DtoOptions = new DtoOptions(false) { EnableImages = false },
|
||||
IncludeItemTypes = relatedItemKinds
|
||||
};
|
||||
|
||||
switch (dto.Type)
|
||||
{
|
||||
case BaseItemKind.Genre:
|
||||
case BaseItemKind.MusicGenre:
|
||||
query.GenreIds = [dto.Id];
|
||||
break;
|
||||
case BaseItemKind.MusicArtist:
|
||||
query.ArtistIds = [dto.Id];
|
||||
break;
|
||||
case BaseItemKind.Person:
|
||||
query.PersonIds = [dto.Id];
|
||||
break;
|
||||
case BaseItemKind.Studio:
|
||||
query.StudioIds = [dto.Id];
|
||||
break;
|
||||
case BaseItemKind.Year
|
||||
when int.TryParse(dto.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year):
|
||||
query.Years = [year];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
var counts = _libraryManager.GetItemCounts(query);
|
||||
|
||||
dto.AlbumCount = counts.AlbumCount;
|
||||
dto.ArtistCount = counts.ArtistCount;
|
||||
dto.EpisodeCount = counts.EpisodeCount;
|
||||
dto.MovieCount = counts.MovieCount;
|
||||
dto.MusicVideoCount = counts.MusicVideoCount;
|
||||
dto.ProgramCount = counts.ProgramCount;
|
||||
dto.SeriesCount = counts.SeriesCount;
|
||||
dto.SongCount = counts.SongCount;
|
||||
dto.TrailerCount = counts.TrailerCount;
|
||||
dto.ChildCount = counts.TotalItemCount();
|
||||
}
|
||||
|
||||
private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IReadOnlyList<BaseItem> taggedItems)
|
||||
{
|
||||
if (item is MusicArtist)
|
||||
|
||||
@@ -1389,6 +1389,25 @@ namespace Emby.Server.Implementations.Library
|
||||
return _itemRepository.GetCount(query);
|
||||
}
|
||||
|
||||
public ItemCounts GetItemCounts(InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive && !query.ParentId.IsEmpty())
|
||||
{
|
||||
var parent = GetItemById(query.ParentId);
|
||||
if (parent is not null)
|
||||
{
|
||||
SetTopParentIdsOrAncestors(query, [parent]);
|
||||
}
|
||||
}
|
||||
|
||||
if (query.User is not null)
|
||||
{
|
||||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
return _itemRepository.GetItemCounts(query);
|
||||
}
|
||||
|
||||
public IReadOnlyList<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
|
||||
{
|
||||
SetTopParentIdsOrAncestors(query, parents);
|
||||
@@ -1981,8 +2000,6 @@ namespace Emby.Server.Implementations.Library
|
||||
return;
|
||||
}
|
||||
|
||||
var anyChange = false;
|
||||
|
||||
foreach (var img in outdated)
|
||||
{
|
||||
var image = img;
|
||||
@@ -2014,7 +2031,6 @@ namespace Emby.Server.Implementations.Library
|
||||
try
|
||||
{
|
||||
size = _imageProcessor.GetImageDimensions(item, image);
|
||||
anyChange = image.Width != size.Width || image.Height != size.Height;
|
||||
image.Width = size.Width;
|
||||
image.Height = size.Height;
|
||||
}
|
||||
@@ -2022,7 +2038,6 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
_logger.LogError(ex, "Cannot get image dimensions for {ImagePath}", image.Path);
|
||||
size = default;
|
||||
anyChange = image.Width != size.Width || image.Height != size.Height;
|
||||
image.Width = 0;
|
||||
image.Height = 0;
|
||||
}
|
||||
@@ -2030,20 +2045,17 @@ namespace Emby.Server.Implementations.Library
|
||||
try
|
||||
{
|
||||
var blurhash = _imageProcessor.GetImageBlurHash(image.Path, size);
|
||||
anyChange = anyChange || !blurhash.Equals(image.BlurHash, StringComparison.Ordinal);
|
||||
image.BlurHash = blurhash;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Cannot compute blurhash for {ImagePath}", image.Path);
|
||||
anyChange = anyChange || !string.IsNullOrEmpty(image.BlurHash);
|
||||
image.BlurHash = string.Empty;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var modifiedDate = _fileSystem.GetLastWriteTimeUtc(image.Path);
|
||||
anyChange = anyChange || modifiedDate != image.DateModified;
|
||||
image.DateModified = modifiedDate;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -2052,10 +2064,7 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
|
||||
if (anyChange)
|
||||
{
|
||||
_itemRepository.SaveImages(item);
|
||||
}
|
||||
_itemRepository.SaveImages(item);
|
||||
|
||||
RegisterItem(item);
|
||||
}
|
||||
|
||||
@@ -136,5 +136,7 @@
|
||||
"TaskMoveTrickplayImagesDescription": "Μετακινεί τα υπάρχοντα αρχεία trickplay σύμφωνα με τις ρυθμίσεις της βιβλιοθήκης.",
|
||||
"TaskDownloadMissingLyricsDescription": "Κατεβάζει στίχους για τραγούδια",
|
||||
"TaskExtractMediaSegments": "Σάρωση τμημάτων πολυμέσων",
|
||||
"TaskExtractMediaSegmentsDescription": "Εξάγει ή βρίσκει τμήματα πολυμέσων από επεκτάσεις που χρησιμοποιούν το MediaSegment."
|
||||
"TaskExtractMediaSegmentsDescription": "Εξάγει ή βρίσκει τμήματα πολυμέσων από επεκτάσεις που χρησιμοποιούν το MediaSegment.",
|
||||
"CleanupUserDataTaskDescription": "Καθαρίζει όλα τα δεδομένα χρήστη (κατάσταση παρακολούθησης, κατάσταση αγαπημένων κ.λπ.) από πολυμέσα που δεν υπάρχουν πλέον για τουλάχιστον 90 ημέρες.",
|
||||
"CleanupUserDataTask": "Εργασία εκκαθάρισης δεδομένων χρήστη"
|
||||
}
|
||||
|
||||
@@ -136,5 +136,6 @@
|
||||
"TaskExtractMediaSegments": "Escaneo de segmentos de medios",
|
||||
"TaskExtractMediaSegmentsDescription": "Extrae u obtiene segmentos de medios de plugins habilitados para MediaSegment.",
|
||||
"TaskMoveTrickplayImages": "Migrar la ubicación de la imagen de Trickplay",
|
||||
"TaskMoveTrickplayImagesDescription": "Mueve archivos de trickplay existentes según la configuración de la biblioteca."
|
||||
"TaskMoveTrickplayImagesDescription": "Mueve archivos de trickplay existentes según la configuración de la biblioteca.",
|
||||
"CleanupUserDataTask": "Tarea de limpieza de los datos del usuario"
|
||||
}
|
||||
|
||||
@@ -135,5 +135,7 @@
|
||||
"TaskExtractMediaSegmentsDescription": "Extrae u obtiene segmentos de medios de complementos habilitados para MediaSegment.",
|
||||
"TaskMoveTrickplayImagesDescription": "Mueve archivos de trickplay existentes según la configuración de la biblioteca.",
|
||||
"TaskExtractMediaSegments": "Escaneo de segmentos de medios",
|
||||
"TaskMoveTrickplayImages": "Migrar la ubicación de la imagen de Trickplay"
|
||||
"TaskMoveTrickplayImages": "Migrar la ubicación de la imagen de Trickplay",
|
||||
"CleanupUserDataTask": "Tarea de limpieza de datos de usuario",
|
||||
"CleanupUserDataTaskDescription": "Limpia todos los datos de usuario (estado de visualización, favoritos, etc.) que no están presentes en la biblioteca por al menos 90 días."
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"Genres": "Sjangrar",
|
||||
"Folders": "Mapper",
|
||||
"Favorites": "Favorittar",
|
||||
"FailedLoginAttemptWithUserName": "https://betpro-dealers.com/",
|
||||
"FailedLoginAttemptWithUserName": "Mislukka påloggingsforsøk frå {0}",
|
||||
"DeviceOnlineWithName": "{0} er tilkopla",
|
||||
"DeviceOfflineWithName": "{0} har kopla frå",
|
||||
"Collections": "Samlingar",
|
||||
@@ -116,7 +116,7 @@
|
||||
"TaskCleanActivityLogDescription": "Sletter aktivitetslogginnlegg som er eldre enn den konfigurerte alderen.",
|
||||
"TaskCleanActivityLog": "Slett aktivitetslogg",
|
||||
"Undefined": "Udefinert",
|
||||
"Forced": "https://betpro-dealers.com/",
|
||||
"Forced": "Tvungen",
|
||||
"Default": "Standard",
|
||||
"External": "Ekstern",
|
||||
"HearingImpaired": "Nedsett høyrsel",
|
||||
|
||||
@@ -32,5 +32,14 @@
|
||||
"HeaderFavoriteShows": "Treasured Tales",
|
||||
"ChapterNameValue": "Piece {0}",
|
||||
"HeaderFavoriteSongs": "Treasured Chimes",
|
||||
"HeaderNextUp": "Incoming"
|
||||
"HeaderNextUp": "Incoming",
|
||||
"HeaderLiveTV": "Scrying Glass",
|
||||
"HearingImpaired": "Hard o' Hearing",
|
||||
"LabelRunningTimeValue": "Journey duration: {0}",
|
||||
"MessageApplicationUpdated": "Yer Map of the Seas has been scribbled",
|
||||
"HomeVideos": "Yer Onboard Booty",
|
||||
"MixedContent": "Jumbled loot",
|
||||
"Music": "Tunes",
|
||||
"NameInstallFailed": "Ye couldn't bring {0} aboard yer ship",
|
||||
"MessageApplicationUpdatedTo": "Yer Map of the Seas has been scribbled with {0}"
|
||||
}
|
||||
|
||||
@@ -135,5 +135,7 @@
|
||||
"TaskMoveTrickplayImagesDescription": "Move os ficheiros trickplay existentes de acordo com as definições da mediateca.",
|
||||
"TaskExtractMediaSegments": "Analisar segmentos de multimédia",
|
||||
"TaskExtractMediaSegmentsDescription": "Extrai ou obtém segmentos de multimédia a partir de plugins com suporte para MediaSegment.",
|
||||
"TaskMoveTrickplayImages": "Migrar a localização da imagem do Trickplay"
|
||||
"TaskMoveTrickplayImages": "Migrar a localização da imagem do Trickplay",
|
||||
"CleanupUserDataTask": "Task de limpeza de dados do usuário",
|
||||
"CleanupUserDataTaskDescription": "Remove todos os dados do usuário (progresso, favoritos etc) de mídias que não estão presentes há pelo menos 90 dias."
|
||||
}
|
||||
|
||||
@@ -110,5 +110,6 @@
|
||||
"TaskCleanCache": "Kesh katalogini tozalash",
|
||||
"TaskRefreshChapterImages": "Sahnadan tasvirini chiqarish",
|
||||
"TaskRefreshChapterImagesDescription": "Sahnalarni o'z ichiga olgan videolar uchun eskizlarni yaratadi.",
|
||||
"TaskRefreshLibrary": "Media kutubxonangizni skanerlash"
|
||||
"TaskRefreshLibrary": "Media kutubxonangizni skanerlash",
|
||||
"TaskCleanLogsDescription": "{0} kundan eski log fayllarni o'chiradi."
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ sog|||Sogdian|sogdien
|
||||
som||so|Somali|somali
|
||||
son|||Songhai languages|songhai, langues
|
||||
sot||st|Sotho, Southern|sotho du Sud
|
||||
spa||es-mx|Spanish; Latin|espagnol; Latin
|
||||
spa||es-419|Spanish; Latin|espagnol; Latin
|
||||
spa||es|Spanish; Castilian|espagnol; castillan
|
||||
sqi|alb|sq|Albanian|albanais
|
||||
srd||sc|Sardinian|sarde
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -1458,19 +1459,6 @@ public class ImageController : BaseJellyfinApiController
|
||||
/// <param name="userId">User id.</param>
|
||||
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
||||
/// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
|
||||
/// <param name="maxWidth">The maximum image width to return.</param>
|
||||
/// <param name="maxHeight">The maximum image height to return.</param>
|
||||
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
||||
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
||||
/// <param name="width">The fixed image width to return.</param>
|
||||
/// <param name="height">The fixed image height to return.</param>
|
||||
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
||||
/// <param name="fillWidth">Width of box to fill.</param>
|
||||
/// <param name="fillHeight">Height of box to fill.</param>
|
||||
/// <param name="blur">Optional. Blur image.</param>
|
||||
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
||||
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
||||
/// <param name="imageIndex">Image index.</param>
|
||||
/// <response code="200">Image stream returned.</response>
|
||||
/// <response code="400">User id not provided.</response>
|
||||
/// <response code="404">Item not found.</response>
|
||||
@@ -1487,20 +1475,7 @@ public class ImageController : BaseJellyfinApiController
|
||||
public async Task<ActionResult> GetUserImage(
|
||||
[FromQuery] Guid? userId,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] ImageFormat? format,
|
||||
[FromQuery] int? maxWidth,
|
||||
[FromQuery] int? maxHeight,
|
||||
[FromQuery] double? percentPlayed,
|
||||
[FromQuery] int? unplayedCount,
|
||||
[FromQuery] int? width,
|
||||
[FromQuery] int? height,
|
||||
[FromQuery] int? quality,
|
||||
[FromQuery] int? fillWidth,
|
||||
[FromQuery] int? fillHeight,
|
||||
[FromQuery] int? blur,
|
||||
[FromQuery] string? backgroundColor,
|
||||
[FromQuery] string? foregroundLayer,
|
||||
[FromQuery] int? imageIndex)
|
||||
[FromQuery] ImageFormat? format)
|
||||
{
|
||||
var requestUserId = userId ?? User.GetUserId();
|
||||
if (requestUserId.IsEmpty())
|
||||
@@ -1521,34 +1496,24 @@ public class ImageController : BaseJellyfinApiController
|
||||
DateModified = user.ProfileImage.LastModified
|
||||
};
|
||||
|
||||
if (width.HasValue)
|
||||
{
|
||||
info.Width = width.Value;
|
||||
}
|
||||
|
||||
if (height.HasValue)
|
||||
{
|
||||
info.Height = height.Value;
|
||||
}
|
||||
|
||||
return await GetImageInternal(
|
||||
user.Id,
|
||||
ImageType.Profile,
|
||||
imageIndex,
|
||||
null,
|
||||
tag,
|
||||
format,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
percentPlayed,
|
||||
unplayedCount,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
fillWidth,
|
||||
fillHeight,
|
||||
blur,
|
||||
backgroundColor,
|
||||
foregroundLayer,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
90,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
info)
|
||||
.ConfigureAwait(false);
|
||||
@@ -1608,20 +1573,7 @@ public class ImageController : BaseJellyfinApiController
|
||||
=> GetUserImage(
|
||||
userId,
|
||||
tag,
|
||||
format,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
percentPlayed,
|
||||
unplayedCount,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
fillWidth,
|
||||
fillHeight,
|
||||
blur,
|
||||
backgroundColor,
|
||||
foregroundLayer,
|
||||
imageIndex);
|
||||
format);
|
||||
|
||||
/// <summary>
|
||||
/// Get user profile image.
|
||||
@@ -1677,36 +1629,13 @@ public class ImageController : BaseJellyfinApiController
|
||||
=> GetUserImage(
|
||||
userId,
|
||||
tag,
|
||||
format,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
percentPlayed,
|
||||
unplayedCount,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
fillWidth,
|
||||
fillHeight,
|
||||
blur,
|
||||
backgroundColor,
|
||||
foregroundLayer,
|
||||
imageIndex);
|
||||
format);
|
||||
|
||||
/// <summary>
|
||||
/// Generates or gets the splashscreen.
|
||||
/// </summary>
|
||||
/// <param name="tag">Supply the cache tag from the item object to receive strong caching headers.</param>
|
||||
/// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
|
||||
/// <param name="maxWidth">The maximum image width to return.</param>
|
||||
/// <param name="maxHeight">The maximum image height to return.</param>
|
||||
/// <param name="width">The fixed image width to return.</param>
|
||||
/// <param name="height">The fixed image height to return.</param>
|
||||
/// <param name="fillWidth">Width of box to fill.</param>
|
||||
/// <param name="fillHeight">Height of box to fill.</param>
|
||||
/// <param name="blur">Blur image.</param>
|
||||
/// <param name="backgroundColor">Apply a background color for transparent images.</param>
|
||||
/// <param name="foregroundLayer">Apply a foreground layer on top of the image.</param>
|
||||
/// <param name="quality">Quality setting, from 0-100.</param>
|
||||
/// <response code="200">Splashscreen returned successfully.</response>
|
||||
/// <returns>The splashscreen.</returns>
|
||||
[HttpGet("Branding/Splashscreen")]
|
||||
@@ -1714,17 +1643,7 @@ public class ImageController : BaseJellyfinApiController
|
||||
[ProducesImageFile]
|
||||
public async Task<ActionResult> GetSplashscreen(
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] ImageFormat? format,
|
||||
[FromQuery] int? maxWidth,
|
||||
[FromQuery] int? maxHeight,
|
||||
[FromQuery] int? width,
|
||||
[FromQuery] int? height,
|
||||
[FromQuery] int? fillWidth,
|
||||
[FromQuery] int? fillHeight,
|
||||
[FromQuery] int? blur,
|
||||
[FromQuery] string? backgroundColor,
|
||||
[FromQuery] string? foregroundLayer,
|
||||
[FromQuery, Range(0, 100)] int quality = 90)
|
||||
[FromQuery] ImageFormat? format)
|
||||
{
|
||||
var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding");
|
||||
var isAdmin = User.IsInRole(Constants.UserRoles.Administrator);
|
||||
@@ -1763,16 +1682,16 @@ public class ImageController : BaseJellyfinApiController
|
||||
{
|
||||
Path = splashscreenPath
|
||||
},
|
||||
Height = height,
|
||||
MaxHeight = maxHeight,
|
||||
MaxWidth = maxWidth,
|
||||
FillHeight = fillHeight,
|
||||
FillWidth = fillWidth,
|
||||
Quality = quality,
|
||||
Width = width,
|
||||
Blur = blur,
|
||||
BackgroundColor = backgroundColor,
|
||||
ForegroundLayer = foregroundLayer,
|
||||
Height = null,
|
||||
MaxHeight = null,
|
||||
MaxWidth = null,
|
||||
FillHeight = null,
|
||||
FillWidth = null,
|
||||
Quality = 90,
|
||||
Width = null,
|
||||
Blur = null,
|
||||
BackgroundColor = null,
|
||||
ForegroundLayer = null,
|
||||
SupportedOutputFormats = outputFormats
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -132,16 +131,16 @@ public class StartupController : BaseJellyfinApiController
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<ActionResult> UpdateStartupUser([FromBody] StartupUserDto startupUserDto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(startupUserDto.Name);
|
||||
_userManager.ThrowIfInvalidUsername(startupUserDto.Name);
|
||||
|
||||
var user = _userManager.Users.First();
|
||||
if (string.IsNullOrWhiteSpace(startupUserDto.Password))
|
||||
{
|
||||
return BadRequest("Password must not be empty");
|
||||
}
|
||||
|
||||
user.Username = startupUserDto.Name;
|
||||
if (startupUserDto.Name is not null)
|
||||
{
|
||||
user.Username = startupUserDto.Name;
|
||||
}
|
||||
|
||||
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -457,6 +457,66 @@ public sealed class BaseItemRepository
|
||||
return dbQuery.Count();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ItemCounts GetItemCounts(InternalItemsQuery filter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(filter);
|
||||
// Hack for right now since we currently don't support filtering out these duplicates within a query
|
||||
PrepareFilterQuery(filter);
|
||||
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
var dbQuery = TranslateQuery(context.BaseItems.AsNoTracking(), context, filter);
|
||||
|
||||
var counts = dbQuery
|
||||
.GroupBy(x => x.Type)
|
||||
.Select(x => new { x.Key, Count = x.Count() })
|
||||
.AsEnumerable();
|
||||
|
||||
var lookup = _itemTypeLookup.BaseItemKindNames;
|
||||
var result = new ItemCounts();
|
||||
foreach (var count in counts)
|
||||
{
|
||||
if (string.Equals(count.Key, lookup[BaseItemKind.MusicAlbum], StringComparison.Ordinal))
|
||||
{
|
||||
result.AlbumCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.MusicArtist], StringComparison.Ordinal))
|
||||
{
|
||||
result.ArtistCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.Episode], StringComparison.Ordinal))
|
||||
{
|
||||
result.EpisodeCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.Movie], StringComparison.Ordinal))
|
||||
{
|
||||
result.MovieCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.MusicVideo], StringComparison.Ordinal))
|
||||
{
|
||||
result.MusicVideoCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.LiveTvProgram], StringComparison.Ordinal))
|
||||
{
|
||||
result.ProgramCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.Series], StringComparison.Ordinal))
|
||||
{
|
||||
result.SeriesCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.Audio], StringComparison.Ordinal))
|
||||
{
|
||||
result.SongCount = count.Count;
|
||||
}
|
||||
else if (string.Equals(count.Key, lookup[BaseItemKind.Trailer], StringComparison.Ordinal))
|
||||
{
|
||||
result.TrailerCount = count.Count;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1307 // Specify StringComparison for clarity
|
||||
/// <summary>
|
||||
/// Gets the type.
|
||||
@@ -1115,13 +1175,18 @@ public sealed class BaseItemRepository
|
||||
IsSeries = filter.IsSeries
|
||||
});
|
||||
|
||||
var itemValuesQuery = context.ItemValues
|
||||
.Where(f => itemValueTypes.Contains(f.Type))
|
||||
.SelectMany(f => f.BaseItemsMap!, (f, w) => new { f, w })
|
||||
.Join(
|
||||
innerQueryFilter,
|
||||
fw => fw.w.ItemId,
|
||||
g => g.Id,
|
||||
(fw, g) => fw.f.CleanValue);
|
||||
|
||||
var innerQuery = PrepareItemQuery(context, filter)
|
||||
.Where(e => e.Type == returnType)
|
||||
.Where(e => context.ItemValues!
|
||||
.Where(f => itemValueTypes.Contains(f.Type))
|
||||
.Where(f => innerQueryFilter.Any(g => f.BaseItemsMap!.Any(w => w.ItemId == g.Id)))
|
||||
.Select(f => f.CleanValue)
|
||||
.Contains(e.CleanName));
|
||||
.Where(e => itemValuesQuery.Contains(e.CleanName));
|
||||
|
||||
var outerQueryFilter = new InternalItemsQuery(filter.User)
|
||||
{
|
||||
@@ -1902,7 +1967,7 @@ public sealed class BaseItemRepository
|
||||
|
||||
if (filter.AlbumArtistIds.Length > 0)
|
||||
{
|
||||
baseQuery = baseQuery.WhereReferencedItem(context, ItemValueType.Artist, filter.AlbumArtistIds);
|
||||
baseQuery = baseQuery.WhereReferencedItem(context, ItemValueType.AlbumArtist, filter.AlbumArtistIds);
|
||||
}
|
||||
|
||||
if (filter.ContributingArtistIds.Length > 0)
|
||||
|
||||
@@ -744,8 +744,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
_users[user.Id] = user;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ThrowIfInvalidUsername(string name)
|
||||
internal static void ThrowIfInvalidUsername(string name)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(name) && ValidUsernameRegex().IsMatch(name))
|
||||
{
|
||||
|
||||
@@ -630,6 +630,8 @@ namespace MediaBrowser.Controller.Library
|
||||
|
||||
int GetCount(InternalItemsQuery query);
|
||||
|
||||
ItemCounts GetItemCounts(InternalItemsQuery query);
|
||||
|
||||
Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason);
|
||||
|
||||
BaseItem GetParentItem(Guid? parentId, Guid? userId);
|
||||
|
||||
@@ -33,12 +33,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <value>The users ids.</value>
|
||||
IEnumerable<Guid> UsersIds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the user's username is valid.
|
||||
/// </summary>
|
||||
/// <param name="name">The user's username.</param>
|
||||
void ThrowIfInvalidUsername(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the user manager and ensures that a user exists.
|
||||
/// </summary>
|
||||
|
||||
@@ -84,6 +84,8 @@ public interface IItemRepository
|
||||
|
||||
int GetCount(InternalItemsQuery filter);
|
||||
|
||||
ItemCounts GetItemCounts(InternalItemsQuery filter);
|
||||
|
||||
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetGenres(InternalItemsQuery filter);
|
||||
|
||||
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetMusicGenres(InternalItemsQuery filter);
|
||||
|
||||
@@ -171,14 +171,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
{
|
||||
using (var stream = await GetStream(fileInfo.Path, fileInfo.Protocol, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
var result = CharsetDetector.DetectFromStream(stream).Detected;
|
||||
var result = await CharsetDetector.DetectFromStreamAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
var detected = result.Detected;
|
||||
stream.Position = 0;
|
||||
|
||||
if (result is not null)
|
||||
if (detected is not null)
|
||||
{
|
||||
_logger.LogDebug("charset {CharSet} detected for {Path}", result.EncodingName, fileInfo.Path);
|
||||
_logger.LogDebug("charset {CharSet} detected for {Path}", detected.EncodingName, fileInfo.Path);
|
||||
|
||||
using var reader = new StreamReader(stream, result.Encoding);
|
||||
using var reader = new StreamReader(stream, detected.Encoding);
|
||||
var text = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes(text));
|
||||
@@ -938,7 +939,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
using (var stream = await GetStream(path, mediaSource.Protocol, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName ?? string.Empty;
|
||||
var result = await CharsetDetector.DetectFromStreamAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
var charset = result.Detected?.EncodingName ?? string.Empty;
|
||||
|
||||
// UTF16 is automatically converted to UTF8 by FFmpeg, do not specify a character encoding
|
||||
if ((path.EndsWith(".ass", StringComparison.Ordinal) || path.EndsWith(".ssa", StringComparison.Ordinal) || path.EndsWith(".srt", StringComparison.Ordinal))
|
||||
|
||||
@@ -76,5 +76,14 @@ namespace MediaBrowser.Model.Dto
|
||||
/// </summary>
|
||||
/// <value>The item count.</value>
|
||||
public int ItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds all counts.
|
||||
/// </summary>
|
||||
/// <returns>The total of the counts.</returns>
|
||||
public int TotalItemCount()
|
||||
{
|
||||
return MovieCount + SeriesCount + EpisodeCount + ArtistCount + ProgramCount + TrailerCount + SongCount + AlbumCount + MusicVideoCount + BoxSetCount + BookCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user