Compare commits

..

6 Commits

Author SHA1 Message Date
fallenbagel
5eaa3ebb67 fix(servarr): increase default API timeout from 5000ms to 10000ms 2026-02-15 20:11:21 +08:00
Ludovic Ortega
39ae32f509 docs: fix migration guide title (#2425)
Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
2026-02-15 03:41:57 +01:00
Ludovic Ortega
c2977f6430 ci(changelog): fix changelog template (#2431) 2026-02-15 00:35:05 +01:00
Ludovic Ortega
92504b7864 ci(release): disable verify attestations for now (#2420)
Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
2026-02-14 19:17:54 +01:00
Gauthier
018e04a657 docs: remove warning about Seerr not being released (#2411) 2026-02-14 18:17:34 +01:00
Gauthier
e503de323a chore: upgrade PWA version (#2418) 2026-02-14 17:09:55 +00:00
9 changed files with 45 additions and 109 deletions

4
.github/cliff.toml vendored
View File

@@ -33,9 +33,9 @@ body = """
{{ self::print_commit(commit=commit) }} {{ self::print_commit(commit=commit) }}
{%- endfor %} {%- endfor %}
{%- for commit in commits %} {%- for commit in commits %}
{%- if not commit.scope -%} {%- if not commit.scope %}
{{ self::print_commit(commit=commit) }} {{ self::print_commit(commit=commit) }}
{%- endif -%} {%- endif %}
{%- endfor -%} {%- endfor -%}
{%- endfor -%} {%- endfor -%}

View File

@@ -6,7 +6,7 @@ on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: branches:
- legacy-jellyseerr - develop
paths: paths:
- 'docs/**' - 'docs/**'
- 'gen-docs/**' - 'gen-docs/**'

View File

@@ -279,17 +279,17 @@ jobs:
--certificate-identity "https://github.com/${{ github.workflow_ref }}" \ --certificate-identity "https://github.com/${{ github.workflow_ref }}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" --certificate-oidc-issuer "https://token.actions.githubusercontent.com"
- name: Verify attestations # - name: Verify attestations
run: | # run: |
cosign verify-attestation "ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}" \ # cosign verify-attestation "ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}" \
--type cyclonedx \ # --type cyclonedx \
--certificate-identity "https://github.com/${{ github.workflow_ref }}" \ # --certificate-identity "https://github.com/${{ github.workflow_ref }}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" > /dev/null # --certificate-oidc-issuer "https://token.actions.githubusercontent.com" > /dev/null
cosign verify-attestation "${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}" \ # cosign verify-attestation "${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}" \
--type cyclonedx \ # --type cyclonedx \
--certificate-identity "https://github.com/${{ github.workflow_ref }}" \ # --certificate-identity "https://github.com/${{ github.workflow_ref }}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" > /dev/null # --certificate-oidc-issuer "https://token.actions.githubusercontent.com" > /dev/null
publish-release: publish-release:
name: Publish release name: Publish release

View File

@@ -1,6 +1,6 @@
<div align="center">⚠️ <strong>NOTE:</strong> We are currently in the process of merging Overseerr and Jellyseerr into this unified repository.</div> <p align="center">
<img src="./public/logo_full.svg" alt="Seerr" style="margin: 20px 0;">
<h1 align="center" style="font-size: 4em;">🚧 Seerr</h1> </p>
<p align="center"> <p align="center">
<img src="https://github.com/seerr-team/seerr/actions/workflows/release.yml/badge.svg" alt="Seerr Release" /> <img src="https://github.com/seerr-team/seerr/actions/workflows/release.yml/badge.svg" alt="Seerr Release" />
<img src="https://github.com/seerr-team/seerr/actions/workflows/ci.yml/badge.svg" alt="Seerr CI"> <img src="https://github.com/seerr-team/seerr/actions/workflows/ci.yml/badge.svg" alt="Seerr CI">
@@ -32,31 +32,19 @@ With more features on the way! Check out our [issue tracker](/../../issues) to s
## Getting Started ## Getting Started
For instructions on how to install and run **Jellyseerr**, please refer to the official documentation: Check out our documentation for instructions on how to install and run Seerr:
https://docs.seerr.dev/getting-started/ https://docs.seerr.dev/getting-started/
> [!IMPORTANT]
> **Seerr is not officially released yet.**
> The project is currently available **only on the `develop` branch** and is intended for **beta testing only**.
The documentation linked above is for running the **latest Jellyseerr** release.
> [!WARNING]
> If you are migrating from **Overseerr** to **Seerr** for beta testing, **do not follow the Jellyseerr latest setup guide**.
Instead, follow the dedicated migration guide (with `:develop` tag):
https://github.com/seerr-team/seerr/blob/develop/docs/migration-guide.mdx
> [!CAUTION]
> **DO NOT run Jellyseerr (latest) using an existing Overseerr database. This includes third-party images with `seerr:latest` (as it points to jellyseerr 2.7.3 and not seerr.**
> Doing so **may cause database corruption and/or irreversible data loss and/or weird unintended behaviour**.
For migration assistance, beta testing questions, or troubleshooting, please join our **Discord** and ask for support there.
## Preview ## Preview
<img src="./public/preview.jpg"> <img src="./public/preview.jpg" alt="Seerr application preview" />
## Migrating from Overseerr/Jellyseerr to Seerr
Read our [release announcement](https://docs.seerr.dev/blog/seerr-release) to learn what Seerr means for Jellyseerr and Overseerr users.
Please follow our [migration guide](https://docs.seerr.dev/migration-guide) for detailed instructions on migrating from Overseerr or Jellyseerr.
## Support ## Support

View File

@@ -200,14 +200,15 @@ Summary of changes :
</TabItem> </TabItem>
</Tabs> </Tabs>
### Nix (Third-party installation methods) ## Third-party installation methods
### Nix
Waiting for https://github.com/NixOS/nixpkgs/pull/450096 and https://github.com/NixOS/nixpkgs/pull/450093 Waiting for https://github.com/NixOS/nixpkgs/pull/450096 and https://github.com/NixOS/nixpkgs/pull/450093
### AUR (Third-party installation methods) ### AUR
See https://aur.archlinux.org/packages/seerr See https://aur.archlinux.org/packages/seerr
### TrueNAS (Third-party installation methods) ### TrueNAS
Waiting for https://github.com/truenas/apps/issues/3374 Waiting for https://github.com/truenas/apps/issues/3374

View File

@@ -3,7 +3,7 @@
// previously cached resources to be updated from the network. // previously cached resources to be updated from the network.
// This variable is intentionally declared and unused. // This variable is intentionally declared and unused.
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const OFFLINE_VERSION = 4; const OFFLINE_VERSION = 5;
const CACHE_NAME = 'offline'; const CACHE_NAME = 'offline';
// Customize this with a different URL if needed. // Customize this with a different URL if needed.
const OFFLINE_URL = '/offline.html'; const OFFLINE_URL = '/offline.html';

View File

@@ -27,13 +27,10 @@ export interface PlexLibraryItem {
Media: Media[]; Media: Media[];
} }
interface PlexLibraryResponseRaw { interface PlexLibraryResponse {
MediaContainer: { MediaContainer: {
totalSize?: number; totalSize: number;
size?: number; Metadata: PlexLibraryItem[];
Metadata?: PlexLibraryItem[];
Directory?: PlexLibraryItem[];
[key: string]: unknown;
}; };
} }
@@ -180,7 +177,7 @@ class PlexAPI extends ExternalAPI {
id: string, id: string,
{ offset = 0, size = 50 }: { offset?: number; size?: number } = {} { offset = 0, size = 50 }: { offset?: number; size?: number } = {}
): Promise<{ totalSize: number; items: PlexLibraryItem[] }> { ): Promise<{ totalSize: number; items: PlexLibraryItem[] }> {
const response = await this.get<PlexLibraryResponseRaw>( const response = await this.get<PlexLibraryResponse>(
`/library/sections/${id}/all?includeGuids=1`, `/library/sections/${id}/all?includeGuids=1`,
{ {
headers: { headers: {
@@ -190,26 +187,9 @@ class PlexAPI extends ExternalAPI {
} }
); );
const container = response.MediaContainer;
const metadataLength = container.Metadata?.length ?? 0;
const directoryLength = container.Directory?.length ?? 0;
logger.debug('Plex getLibraryContents raw response', {
label: 'Plex API',
libraryId: id,
offset,
metadataLength,
directoryLength,
totalSize: container.totalSize,
size: container.size,
keys: Object.keys(container).filter((k) =>
['Metadata', 'Directory', 'totalSize', 'size'].includes(k)
),
});
return { return {
totalSize: container.totalSize ?? 0, totalSize: response.MediaContainer.totalSize,
items: container.Metadata ?? [], items: response.MediaContainer.Metadata ?? [],
}; };
} }
@@ -241,7 +221,7 @@ class PlexAPI extends ExternalAPI {
}, },
mediaType: 'movie' | 'show' mediaType: 'movie' | 'show'
): Promise<PlexLibraryItem[]> { ): Promise<PlexLibraryItem[]> {
const response = await this.get<PlexLibraryResponseRaw>( const response = await this.get<PlexLibraryResponse>(
`/library/sections/${id}/all?type=${ `/library/sections/${id}/all?type=${
mediaType === 'show' ? '4' : '1' mediaType === 'show' ? '4' : '1'
}&sort=addedAt%3Adesc&addedAt>>=${Math.floor(options.addedAt / 1000)}`, }&sort=addedAt%3Adesc&addedAt>>=${Math.floor(options.addedAt / 1000)}`,
@@ -253,21 +233,7 @@ class PlexAPI extends ExternalAPI {
} }
); );
const container = response.MediaContainer; return response.MediaContainer.Metadata;
const items = container.Metadata ?? [];
logger.debug('Plex getRecentlyAdded raw response', {
label: 'Plex API',
libraryId: id,
mediaType,
addedAtFilter: options.addedAt,
addedAtFilterDate: new Date(options.addedAt).toISOString(),
metadataLength: container.Metadata?.length ?? 0,
directoryLength: container.Directory?.length ?? 0,
itemsReturned: items.length,
});
return items;
} }
} }

View File

@@ -92,7 +92,7 @@ class ServarrBase<QueueItemAppendT> extends ExternalAPI {
apiKey, apiKey,
cacheName, cacheName,
apiName, apiName,
timeout = 5000, timeout = 10000,
}: { }: {
url: string; url: string;
apiKey: string; apiKey: string;

View File

@@ -90,41 +90,22 @@ class PlexScanner
if (this.isRecentOnly) { if (this.isRecentOnly) {
for (const library of this.libraries) { for (const library of this.libraries) {
this.currentLibrary = library; this.currentLibrary = library;
const addedAtOpt = library.lastScan this.log(
`Beginning to process recently added for library: ${library.name}`,
'info',
{ lastScan: library.lastScan }
);
const libraryItems = await this.plexClient.getRecentlyAdded(
library.id,
library.lastScan
? { ? {
// We remove 10 minutes from the last scan as a buffer // We remove 10 minutes from the last scan as a buffer
addedAt: library.lastScan - 1000 * 60 * 10, addedAt: library.lastScan - 1000 * 60 * 10,
} }
: undefined;
this.log(
`Beginning to process recently added for library: ${library.name}`,
'info',
{
lastScan: library.lastScan,
addedAtFilter: addedAtOpt?.addedAt,
addedAtFilterDate: addedAtOpt
? new Date(addedAtOpt.addedAt).toISOString()
: undefined, : undefined,
}
);
const libraryItems = await this.plexClient.getRecentlyAdded(
library.id,
addedAtOpt ?? {
addedAt: Date.now() - 1000 * 60 * 60,
},
library.type library.type
); );
this.log(
`Recently added fetched ${libraryItems.length} items for library: ${library.name}`,
'debug',
{
libraryId: library.id,
itemCount: libraryItems.length,
lastScanWillUpdateTo: Date.now(),
}
);
// Bundle items up by rating keys // Bundle items up by rating keys
this.items = uniqWith(libraryItems, (mediaA, mediaB) => { this.items = uniqWith(libraryItems, (mediaA, mediaB) => {
if (mediaA.grandparentRatingKey && mediaB.grandparentRatingKey) { if (mediaA.grandparentRatingKey && mediaB.grandparentRatingKey) {