diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 0189cafb4..6e08dfb2a 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1 +1 @@
-github: [Fallenbagel]
\ No newline at end of file
+github: [Fallenbagel]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9734a65ab..e938f429c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
container: node:18.18-alpine
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install dependencies
env:
HUSKY: 0
@@ -34,18 +34,18 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Log in to GitHub Container Registry
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -56,7 +56,7 @@ jobs:
env:
OWNER: ${{ github.repository_owner }}
- name: Build and push
- uses: docker/build-push-action@v3
+ uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 10926bbd9..ed34d7c8b 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -24,7 +24,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
diff --git a/.github/workflows/conflict_labeler.yml b/.github/workflows/conflict_labeler.yml
new file mode 100644
index 000000000..3e3d00f18
--- /dev/null
+++ b/.github/workflows/conflict_labeler.yml
@@ -0,0 +1,26 @@
+name: Merge Conflict Labeler
+
+on:
+ push:
+ branches:
+ - develop
+ pull_request_target:
+ branches:
+ - develop
+ types: [synchronize]
+
+jobs:
+ label:
+ name: Labeling
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'Fallenbagel/jellyseerr' }}
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: Apply label
+ uses: eps1lon/actions-label-merge-conflict@v3
+ with:
+ dirtyLabel: 'merge conflict'
+ commentOnDirty: 'This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.'
+ repoToken: '${{ secrets.GITHUB_TOKEN }}'
diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml
index ecd260dd5..0f0c6f237 100644
--- a/.github/workflows/cypress.yml
+++ b/.github/workflows/cypress.yml
@@ -13,9 +13,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Cypress run
- uses: cypress-io/github-action@v4
+ uses: cypress-io/github-action@v6
with:
build: yarn cypress:build
start: yarn start
diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
index 600551f0a..88ab3364f 100644
--- a/.github/workflows/preview.yml
+++ b/.github/workflows/preview.yml
@@ -11,21 +11,21 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Get the version
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Build and push
- uses: docker/build-push-action@v3
+ uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 449b3e74d..1eeacd77d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,19 +10,19 @@ jobs:
HUSKY: 0
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 16
+ node-version: 18
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
@@ -48,7 +48,7 @@ jobs:
- armhf
steps:
- name: Checkout Code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Switch to main branch
@@ -65,7 +65,7 @@ jobs:
echo "RELEASE=edge" >> $GITHUB_OUTPUT
fi
- name: Set Up QEMU
- uses: docker/setup-qemu-action@v1
+ uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt@sha256:df15403e06a03c2f461c1f7938b171fda34a5849eb63a70e2a2109ed5a778bde
- name: Build Snap Package
@@ -74,7 +74,7 @@ jobs:
with:
architecture: ${{ matrix.architecture }}
- name: Upload Snap Package
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: jellyseerr-snap-package-${{ matrix.architecture }}
path: ${{ steps.build.outputs.snap }}
diff --git a/.github/workflows/snap.yaml b/.github/workflows/snap.yaml
index 0aaa9a651..67f7fbd4e 100644
--- a/.github/workflows/snap.yaml
+++ b/.github/workflows/snap.yaml
@@ -12,7 +12,7 @@ jobs:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- name: Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
+ uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}
@@ -29,7 +29,7 @@ jobs:
- armhf
steps:
- name: Checkout Code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Prepare
id: prepare
run: |
@@ -40,7 +40,7 @@ jobs:
echo "RELEASE=edge" >> $GITHUB_OUTPUT
fi
- name: Set Up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Configure Git
run: git config --add safe.directory /data/parts/jellyseerr/src
- name: Build Snap Package
@@ -49,7 +49,7 @@ jobs:
with:
architecture: ${{ matrix.architecture }}
- name: Upload Snap Package
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: jellyseerr-snap-package-${{ matrix.architecture }}
path: ${{ steps.build.outputs.snap }}
diff --git a/.github/workflows/support.yml b/.github/workflows/support.yml
index 8b45dcdc5..fd81754d6 100644
--- a/.github/workflows/support.yml
+++ b/.github/workflows/support.yml
@@ -6,9 +6,9 @@ on:
jobs:
support:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- - uses: dessant/support-requests@v2
+ - uses: dessant/support-requests@v4
with:
github-token: ${{ github.token }}
support-label: 'support'
diff --git a/overseerr-api.yml b/overseerr-api.yml
index 7a7ea490a..3cb42284c 100644
--- a/overseerr-api.yml
+++ b/overseerr-api.yml
@@ -2092,6 +2092,13 @@ paths:
application/json:
schema:
type: array
+ items:
+ type: object
+ properties:
+ username:
+ type: string
+ userId:
+ type: integer
/settings/jellyfin/sync:
get:
summary: Get status of full Jellyfin library sync
@@ -3395,6 +3402,12 @@ paths:
Updates a single slider and return the newly updated slider. Requires the `ADMIN` permission.
tags:
- settings
+ parameters:
+ - in: path
+ name: sliderId
+ required: true
+ schema:
+ type: number
requestBody:
required: true
content:
@@ -3724,7 +3737,7 @@ paths:
results:
type: array
items:
- $ref: '#/components/schemas/User'
+ $ref: '#/components/schemas/User'
post:
summary: Create new user
description: |
diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png
index d45f2f6cb..6b9a1caf8 100644
Binary files a/public/android-chrome-192x192.png and b/public/android-chrome-192x192.png differ
diff --git a/public/android-chrome-192x192_maskable.png b/public/android-chrome-192x192_maskable.png
index 31ee33aa0..87411a99e 100644
Binary files a/public/android-chrome-192x192_maskable.png and b/public/android-chrome-192x192_maskable.png differ
diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png
index 649213611..fbee9d4c5 100644
Binary files a/public/android-chrome-512x512.png and b/public/android-chrome-512x512.png differ
diff --git a/public/android-chrome-512x512_maskable.png b/public/android-chrome-512x512_maskable.png
index e85a228f3..673c3b5e4 100644
Binary files a/public/android-chrome-512x512_maskable.png and b/public/android-chrome-512x512_maskable.png differ
diff --git a/public/apple-splash-1125-2436.jpg b/public/apple-splash-1125-2436.jpg
index 4f5d56bab..62002d6a3 100644
Binary files a/public/apple-splash-1125-2436.jpg and b/public/apple-splash-1125-2436.jpg differ
diff --git a/public/apple-splash-1136-640.jpg b/public/apple-splash-1136-640.jpg
index b072e6bce..e3704f5e3 100644
Binary files a/public/apple-splash-1136-640.jpg and b/public/apple-splash-1136-640.jpg differ
diff --git a/public/apple-splash-1170-2532.jpg b/public/apple-splash-1170-2532.jpg
index b5c6920b8..1e0d63b5d 100644
Binary files a/public/apple-splash-1170-2532.jpg and b/public/apple-splash-1170-2532.jpg differ
diff --git a/public/apple-splash-1179-2556.jpg b/public/apple-splash-1179-2556.jpg
new file mode 100644
index 000000000..96de00189
Binary files /dev/null and b/public/apple-splash-1179-2556.jpg differ
diff --git a/public/apple-splash-1242-2208.jpg b/public/apple-splash-1242-2208.jpg
index 684efb289..2c70c2741 100644
Binary files a/public/apple-splash-1242-2208.jpg and b/public/apple-splash-1242-2208.jpg differ
diff --git a/public/apple-splash-1242-2688.jpg b/public/apple-splash-1242-2688.jpg
index b1ea4558d..9c654126c 100644
Binary files a/public/apple-splash-1242-2688.jpg and b/public/apple-splash-1242-2688.jpg differ
diff --git a/public/apple-splash-1284-2778.jpg b/public/apple-splash-1284-2778.jpg
index f72ac8a9f..821777f17 100644
Binary files a/public/apple-splash-1284-2778.jpg and b/public/apple-splash-1284-2778.jpg differ
diff --git a/public/apple-splash-1290-2796.jpg b/public/apple-splash-1290-2796.jpg
new file mode 100644
index 000000000..98396d791
Binary files /dev/null and b/public/apple-splash-1290-2796.jpg differ
diff --git a/public/apple-splash-1334-750.jpg b/public/apple-splash-1334-750.jpg
index 8a114e0cc..5dad6ba9a 100644
Binary files a/public/apple-splash-1334-750.jpg and b/public/apple-splash-1334-750.jpg differ
diff --git a/public/apple-splash-1488-2266.jpg b/public/apple-splash-1488-2266.jpg
new file mode 100644
index 000000000..3724d6b25
Binary files /dev/null and b/public/apple-splash-1488-2266.jpg differ
diff --git a/public/apple-splash-1536-2048.jpg b/public/apple-splash-1536-2048.jpg
index e46674aae..fff4a2054 100644
Binary files a/public/apple-splash-1536-2048.jpg and b/public/apple-splash-1536-2048.jpg differ
diff --git a/public/apple-splash-1620-2160.jpg b/public/apple-splash-1620-2160.jpg
index e4e3defef..279ef8d97 100644
Binary files a/public/apple-splash-1620-2160.jpg and b/public/apple-splash-1620-2160.jpg differ
diff --git a/public/apple-splash-1640-2360.jpg b/public/apple-splash-1640-2360.jpg
new file mode 100644
index 000000000..3ad365626
Binary files /dev/null and b/public/apple-splash-1640-2360.jpg differ
diff --git a/public/apple-splash-1668-2224.jpg b/public/apple-splash-1668-2224.jpg
index 3fa4197a9..3f6ab1e96 100644
Binary files a/public/apple-splash-1668-2224.jpg and b/public/apple-splash-1668-2224.jpg differ
diff --git a/public/apple-splash-1668-2388.jpg b/public/apple-splash-1668-2388.jpg
index c67ec23d9..d3bed5d81 100644
Binary files a/public/apple-splash-1668-2388.jpg and b/public/apple-splash-1668-2388.jpg differ
diff --git a/public/apple-splash-1792-828.jpg b/public/apple-splash-1792-828.jpg
index e0cad060d..be8fb6043 100644
Binary files a/public/apple-splash-1792-828.jpg and b/public/apple-splash-1792-828.jpg differ
diff --git a/public/apple-splash-2048-1536.jpg b/public/apple-splash-2048-1536.jpg
index ae78de715..0cf3c7608 100644
Binary files a/public/apple-splash-2048-1536.jpg and b/public/apple-splash-2048-1536.jpg differ
diff --git a/public/apple-splash-2048-2732.jpg b/public/apple-splash-2048-2732.jpg
index 93d0005b6..1d574ab43 100644
Binary files a/public/apple-splash-2048-2732.jpg and b/public/apple-splash-2048-2732.jpg differ
diff --git a/public/apple-splash-2160-1620.jpg b/public/apple-splash-2160-1620.jpg
index 2bc1beb2e..22285bd46 100644
Binary files a/public/apple-splash-2160-1620.jpg and b/public/apple-splash-2160-1620.jpg differ
diff --git a/public/apple-splash-2208-1242.jpg b/public/apple-splash-2208-1242.jpg
index 764492ba0..d3d451e9f 100644
Binary files a/public/apple-splash-2208-1242.jpg and b/public/apple-splash-2208-1242.jpg differ
diff --git a/public/apple-splash-2224-1668.jpg b/public/apple-splash-2224-1668.jpg
index a118bde2e..813722758 100644
Binary files a/public/apple-splash-2224-1668.jpg and b/public/apple-splash-2224-1668.jpg differ
diff --git a/public/apple-splash-2266-1488.jpg b/public/apple-splash-2266-1488.jpg
new file mode 100644
index 000000000..e739c7ba5
Binary files /dev/null and b/public/apple-splash-2266-1488.jpg differ
diff --git a/public/apple-splash-2360-1640.jpg b/public/apple-splash-2360-1640.jpg
new file mode 100644
index 000000000..ad5836281
Binary files /dev/null and b/public/apple-splash-2360-1640.jpg differ
diff --git a/public/apple-splash-2388-1668.jpg b/public/apple-splash-2388-1668.jpg
index 3858e9bb6..fc7e8c62d 100644
Binary files a/public/apple-splash-2388-1668.jpg and b/public/apple-splash-2388-1668.jpg differ
diff --git a/public/apple-splash-2436-1125.jpg b/public/apple-splash-2436-1125.jpg
index 5ae37d3fe..c79522192 100644
Binary files a/public/apple-splash-2436-1125.jpg and b/public/apple-splash-2436-1125.jpg differ
diff --git a/public/apple-splash-2532-1170.jpg b/public/apple-splash-2532-1170.jpg
index fd673e2e4..afb763e49 100644
Binary files a/public/apple-splash-2532-1170.jpg and b/public/apple-splash-2532-1170.jpg differ
diff --git a/public/apple-splash-2556-1179.jpg b/public/apple-splash-2556-1179.jpg
new file mode 100644
index 000000000..7b5b64d4c
Binary files /dev/null and b/public/apple-splash-2556-1179.jpg differ
diff --git a/public/apple-splash-2688-1242.jpg b/public/apple-splash-2688-1242.jpg
index 120758611..5ee8a37de 100644
Binary files a/public/apple-splash-2688-1242.jpg and b/public/apple-splash-2688-1242.jpg differ
diff --git a/public/apple-splash-2732-2048.jpg b/public/apple-splash-2732-2048.jpg
index d0194b5c2..3a63e0ce9 100644
Binary files a/public/apple-splash-2732-2048.jpg and b/public/apple-splash-2732-2048.jpg differ
diff --git a/public/apple-splash-2778-1284.jpg b/public/apple-splash-2778-1284.jpg
index db0f99a69..077de33e3 100644
Binary files a/public/apple-splash-2778-1284.jpg and b/public/apple-splash-2778-1284.jpg differ
diff --git a/public/apple-splash-2796-1290.jpg b/public/apple-splash-2796-1290.jpg
new file mode 100644
index 000000000..4b3a0e597
Binary files /dev/null and b/public/apple-splash-2796-1290.jpg differ
diff --git a/public/apple-splash-640-1136.jpg b/public/apple-splash-640-1136.jpg
index 67b64b48c..a701eb5e2 100644
Binary files a/public/apple-splash-640-1136.jpg and b/public/apple-splash-640-1136.jpg differ
diff --git a/public/apple-splash-750-1334.jpg b/public/apple-splash-750-1334.jpg
index 8520b0bc5..1376f3e48 100644
Binary files a/public/apple-splash-750-1334.jpg and b/public/apple-splash-750-1334.jpg differ
diff --git a/public/apple-splash-828-1792.jpg b/public/apple-splash-828-1792.jpg
index 2431af1fa..fa00f21b0 100644
Binary files a/public/apple-splash-828-1792.jpg and b/public/apple-splash-828-1792.jpg differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
index f034e3255..388324239 100644
Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ
diff --git a/public/badge-128x128.png b/public/badge-128x128.png
index 17cdf57ca..affeaecde 100644
Binary files a/public/badge-128x128.png and b/public/badge-128x128.png differ
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
index 6f1e8178a..632338b37 100644
Binary files a/public/favicon-16x16.png and b/public/favicon-16x16.png differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
index 3de86659c..cefb76668 100644
Binary files a/public/favicon-32x32.png and b/public/favicon-32x32.png differ
diff --git a/public/favicon.ico b/public/favicon.ico
index 2aa020816..dbca29f14 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/images/overseerr_poster_not_found.png b/public/images/overseerr_poster_not_found.png
index 0cdf9cb00..65b4f365e 100644
Binary files a/public/images/overseerr_poster_not_found.png and b/public/images/overseerr_poster_not_found.png differ
diff --git a/public/images/overseerr_poster_not_found_logo_center.png b/public/images/overseerr_poster_not_found_logo_center.png
index 941932881..cdc9d8cde 100644
Binary files a/public/images/overseerr_poster_not_found_logo_center.png and b/public/images/overseerr_poster_not_found_logo_center.png differ
diff --git a/public/images/overseerr_poster_not_found_logo_top.png b/public/images/overseerr_poster_not_found_logo_top.png
index 5d92bb4bb..cdc9d8cde 100644
Binary files a/public/images/overseerr_poster_not_found_logo_top.png and b/public/images/overseerr_poster_not_found_logo_top.png differ
diff --git a/public/logo_full.png b/public/logo_full.png
index e92a3feaa..5bc14bcf3 100644
Binary files a/public/logo_full.png and b/public/logo_full.png differ
diff --git a/public/logo_full.svg b/public/logo_full.svg
index fee7e68f2..df6c8c6a1 100644
--- a/public/logo_full.svg
+++ b/public/logo_full.svg
@@ -1,69 +1,185 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/public/logo_stacked.svg b/public/logo_stacked.svg
index aa1edcae6..eb2296d87 100644
--- a/public/logo_stacked.svg
+++ b/public/logo_stacked.svg
@@ -1,70 +1,139 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/public/os_icon.svg b/public/os_icon.svg
index 46dbb480b..cda2394d9 100644
--- a/public/os_icon.svg
+++ b/public/os_icon.svg
@@ -1,45 +1,118 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/public/os_logo_filled.png b/public/os_logo_filled.png
index ebfd8da0f..37ad421d7 100644
Binary files a/public/os_logo_filled.png and b/public/os_logo_filled.png differ
diff --git a/public/os_logo_square.png b/public/os_logo_square.png
index ebfd8da0f..37ad421d7 100644
Binary files a/public/os_logo_square.png and b/public/os_logo_square.png differ
diff --git a/public/preview.jpg b/public/preview.jpg
index ffde6932d..a21f1b973 100644
Binary files a/public/preview.jpg and b/public/preview.jpg differ
diff --git a/server/api/jellyfin.ts b/server/api/jellyfin.ts
index 768398a06..cd7fb1cfc 100644
--- a/server/api/jellyfin.ts
+++ b/server/api/jellyfin.ts
@@ -9,6 +9,9 @@ export interface JellyfinUserResponse {
ServerId: string;
ServerName: string;
Id: string;
+ Configuration: {
+ GroupedFolders: string[];
+ };
Policy: {
IsAdministrator: boolean;
};
@@ -24,6 +27,13 @@ export interface JellyfinUserListResponse {
users: JellyfinUserResponse[];
}
+interface JellyfinMediaFolder {
+ Name: string;
+ Id: string;
+ Type: string;
+ CollectionType: string;
+}
+
export interface JellyfinLibrary {
type: 'show' | 'movie';
key: string;
@@ -175,24 +185,45 @@ class JellyfinAPI {
public async getLibraries(): Promise {
try {
- // TODO: Try to fix automatic grouping without fucking up LDAP users
- // const libraries = await this.axios.get('/Library/VirtualFolders');
+ const mediaFolders = await this.axios.get(`/Library/MediaFolders`);
- const account = await this.axios.get(
- `/Users/${this.userId ?? 'Me'}/Views`
- );
+ return this.mapLibraries(mediaFolders.data.Items);
+ } catch (mediaFoldersError) {
+ // fallback to user views to get libraries
+ // this only affects LDAP users
+ try {
+ const mediaFolders = await this.axios.get(
+ `/Users/${this.userId ?? 'Me'}/Views`
+ );
- const response: JellyfinLibrary[] = account.data.Items.filter(
- (Item: any) => {
- return (
- Item.Type === 'CollectionFolder' &&
- Item.CollectionType !== 'music' &&
- Item.CollectionType !== 'books' &&
- Item.CollectionType !== 'musicvideos' &&
- Item.CollectionType !== 'homevideos'
- );
- }
- ).map((Item: any) => {
+ return this.mapLibraries(mediaFolders.data.Items);
+ } catch (e) {
+ logger.error(
+ `Something went wrong while getting libraries from the Jellyfin server: ${e.message}`,
+ { label: 'Jellyfin API' }
+ );
+ return [];
+ }
+ }
+ }
+
+ private mapLibraries(mediaFolders: JellyfinMediaFolder[]): JellyfinLibrary[] {
+ const excludedTypes = [
+ 'music',
+ 'books',
+ 'musicvideos',
+ 'homevideos',
+ 'boxsets',
+ ];
+
+ return mediaFolders
+ .filter((Item: JellyfinMediaFolder) => {
+ return (
+ Item.Type === 'CollectionFolder' &&
+ !excludedTypes.includes(Item.CollectionType)
+ );
+ })
+ .map((Item: JellyfinMediaFolder) => {
return {
key: Item.Id,
title: Item.Name,
@@ -200,21 +231,12 @@ class JellyfinAPI {
agent: 'jellyfin',
};
});
-
- return response;
- } catch (e) {
- logger.error(
- `Something went wrong while getting libraries from the Jellyfin server: ${e.message}`,
- { label: 'Jellyfin API' }
- );
- return [];
- }
}
public async getLibraryContents(id: string): Promise {
try {
const contents = await this.axios.get(
- `/Users/${this.userId}/Items?SortBy=SortName&SortOrder=Ascending&IncludeItemTypes=Series,Movie,Others&Recursive=true&StartIndex=0&ParentId=${id}`
+ `/Users/${this.userId}/Items?SortBy=SortName&SortOrder=Ascending&IncludeItemTypes=Series,Movie,Others&Recursive=true&StartIndex=0&ParentId=${id}&collapseBoxSetItems=false`
);
return contents.data.Items.filter(
diff --git a/server/routes/settings/index.ts b/server/routes/settings/index.ts
index de86ed71b..41821dcac 100644
--- a/server/routes/settings/index.ts
+++ b/server/routes/settings/index.ts
@@ -261,7 +261,7 @@ settingsRoutes.post('/jellyfin', (req, res) => {
return res.status(200).json(settings.jellyfin);
});
-settingsRoutes.get('/jellyfin/library', async (req, res) => {
+settingsRoutes.get('/jellyfin/library', async (req, res, next) => {
const settings = getSettings();
if (req.query.sync) {
@@ -281,6 +281,19 @@ settingsRoutes.get('/jellyfin/library', async (req, res) => {
const libraries = await jellyfinClient.getLibraries();
+ if (libraries.length === 0) {
+ // Check if no libraries are found due to the fallback to user views
+ // This only affects LDAP users
+ const account = await jellyfinClient.getUser();
+
+ // Automatic Library grouping is not supported when user views are used to get library
+ if (account.Configuration.GroupedFolders.length > 0) {
+ return next({ status: 501, message: 'SYNC_ERROR_GROUPED_FOLDERS' });
+ }
+
+ return next({ status: 404, message: 'SYNC_ERROR_NO_LIBRARIES' });
+ }
+
const newLibraries: Library[] = libraries.map((library) => {
const existing = settings.jellyfin.libraries.find(
(l) => l.id === library.key && l.name === library.title
diff --git a/src/components/Settings/SettingsJellyfin.tsx b/src/components/Settings/SettingsJellyfin.tsx
index 584a98fde..180010c93 100644
--- a/src/components/Settings/SettingsJellyfin.tsx
+++ b/src/components/Settings/SettingsJellyfin.tsx
@@ -34,6 +34,11 @@ const messages = defineMessages({
externalUrl: 'External URL',
internalUrl: 'Internal URL',
jellyfinForgotPasswordUrl: 'Forgot Password URL',
+ jellyfinSyncFailedNoLibrariesFound: 'No libraries were found',
+ jellyfinSyncFailedAutomaticGroupedFolders:
+ 'Custom authentication with Automatic Library Grouping not supported',
+ jellyfinSyncFailedGenericError:
+ 'Something went wrong while syncing libraries',
validationUrl: 'You must provide a valid URL',
syncing: 'Syncing',
syncJellyfin: 'Sync Libraries',
@@ -70,6 +75,7 @@ const SettingsJellyfin: React.FC = ({
showAdvancedSettings,
}) => {
const [isSyncing, setIsSyncing] = useState(false);
+ const toasts = useToasts();
const {
data,
@@ -117,11 +123,43 @@ const SettingsJellyfin: React.FC = ({
params.enable = activeLibraries.join(',');
}
- await axios.get('/api/v1/settings/jellyfin/library', {
- params,
- });
- setIsSyncing(false);
- revalidate();
+ try {
+ await axios.get('/api/v1/settings/jellyfin/library', {
+ params,
+ });
+ setIsSyncing(false);
+ revalidate();
+ } catch (e) {
+ if (e.response.data.message === 'SYNC_ERROR_GROUPED_FOLDERS') {
+ toasts.addToast(
+ intl.formatMessage(
+ messages.jellyfinSyncFailedAutomaticGroupedFolders
+ ),
+ {
+ autoDismiss: true,
+ appearance: 'warning',
+ }
+ );
+ } else if (e.response.data.message === 'SYNC_ERROR_NO_LIBRARIES') {
+ toasts.addToast(
+ intl.formatMessage(messages.jellyfinSyncFailedNoLibrariesFound),
+ {
+ autoDismiss: true,
+ appearance: 'error',
+ }
+ );
+ } else {
+ toasts.addToast(
+ intl.formatMessage(messages.jellyfinSyncFailedGenericError),
+ {
+ autoDismiss: true,
+ appearance: 'error',
+ }
+ );
+ }
+ setIsSyncing(false);
+ revalidate();
+ }
};
const startScan = async () => {
diff --git a/src/components/Settings/SonarrModal/index.tsx b/src/components/Settings/SonarrModal/index.tsx
index 5267ef4e3..729a40a7b 100644
--- a/src/components/Settings/SonarrModal/index.tsx
+++ b/src/components/Settings/SonarrModal/index.tsx
@@ -1,10 +1,8 @@
import Modal from '@app/components/Common/Modal';
import SensitiveInput from '@app/components/Common/SensitiveInput';
-import useSettings from '@app/hooks/useSettings';
import globalMessages from '@app/i18n/globalMessages';
import { Transition } from '@headlessui/react';
-import { MediaServerType } from '@server/constants/server';
-import { type SonarrSettings } from '@server/lib/settings';
+import type { SonarrSettings } from '@server/lib/settings';
import axios from 'axios';
import { Field, Formik } from 'formik';
import { useCallback, useEffect, useRef, useState } from 'react';
@@ -111,7 +109,6 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
const { addToast } = useToasts();
const [isValidated, setIsValidated] = useState(sonarr ? true : false);
const [isTesting, setIsTesting] = useState(false);
- const settings = useSettings();
const [testResponse, setTestResponse] = useState({
profiles: [],
rootFolders: [],
@@ -258,9 +255,7 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
animeTags: sonarr?.animeTags ?? [],
isDefault: sonarr?.isDefault ?? false,
is4k: sonarr?.is4k ?? false,
- enableSeasonFolders:
- sonarr?.enableSeasonFolders ??
- settings.currentSettings.mediaServerType !== MediaServerType.PLEX,
+ enableSeasonFolders: sonarr?.enableSeasonFolders ?? false,
externalUrl: sonarr?.externalUrl,
syncEnabled: sonarr?.syncEnabled ?? false,
enableSearch: !sonarr?.preventSearch,
@@ -966,24 +961,11 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
>
{intl.formatMessage(messages.seasonfolders)}
-
+
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json
index 9ebbed252..73e6170fb 100644
--- a/src/i18n/locale/en.json
+++ b/src/i18n/locale/en.json
@@ -946,6 +946,9 @@
"components.Settings.jellyfinlibrariesDescription": "The libraries {mediaServerName} scans for titles. Click the button below if no libraries are listed.",
"components.Settings.jellyfinsettings": "{mediaServerName} Settings",
"components.Settings.jellyfinsettingsDescription": "Configure the settings for your {mediaServerName} server. {mediaServerName} scans your {mediaServerName} libraries to see what content is available.",
+ "components.Settings.jellyfinSyncFailedNoLibrariesFound": "No libraries were found",
+ "components.Settings.jellyfinSyncFailedAutomaticGroupedFolders": "Custom authentication with Automatic Library Grouping not supported",
+ "components.Settings.jellyfinSyncFailedGenericError": "Something went wrong while syncing libraries",
"components.Settings.librariesRemaining": "Libraries Remaining: {count}",
"components.Settings.manualscan": "Manual Library Scan",
"components.Settings.manualscanDescription": "Normally, this will only be run once every 24 hours. Jellyseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one-time full manual library scan is recommended!",