Compare commits
34 Commits
preview-is
...
preview-dn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a45a465bea | ||
|
|
aeb8023027 | ||
|
|
f958b11d51 | ||
|
|
e31281cac0 | ||
|
|
4ab79ffb76 | ||
|
|
c17384a339 | ||
|
|
eae78ec728 | ||
|
|
ec4ed21a49 | ||
|
|
1eec1823d5 | ||
|
|
e45a6c530b | ||
|
|
03d905ae98 | ||
|
|
7b2b45b066 | ||
|
|
5c6d7a6f19 | ||
|
|
ab2fd0a324 | ||
|
|
ede79a8ad4 | ||
|
|
54c4e9a6bd | ||
|
|
2266fd43d8 | ||
|
|
753ea43922 | ||
|
|
7fc8d3d4e4 | ||
|
|
00728dafdf | ||
|
|
7ddca119a8 | ||
|
|
ef30ea523f | ||
|
|
bb60926bf7 | ||
|
|
bb47dc6c02 | ||
|
|
18e935d0bb | ||
|
|
145dfe0e14 | ||
|
|
81f4c24b7b | ||
|
|
73fd763890 | ||
|
|
2a12cb84c6 | ||
|
|
73feb07007 | ||
|
|
c856a9be0e | ||
|
|
6828924493 | ||
|
|
2f80a536c3 | ||
|
|
965df89614 |
@@ -1,21 +0,0 @@
|
|||||||
---
|
|
||||||
title: Gotify
|
|
||||||
description: Configure Gotify notifications.
|
|
||||||
sidebar_position: 5
|
|
||||||
---
|
|
||||||
|
|
||||||
# Gotify
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Server URL
|
|
||||||
|
|
||||||
Set this to the URL of your Gotify server.
|
|
||||||
|
|
||||||
### Application Token
|
|
||||||
|
|
||||||
Add an application to your Gotify server, and set this field to the generated application token.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Please refer to the [Gotify API documentation](https://gotify.net/docs) for more details on configuring these notifications.
|
|
||||||
:::
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
title: ntfy.sh
|
|
||||||
description: Configure ntfy.sh notifications.
|
|
||||||
sidebar_position: 6
|
|
||||||
---
|
|
||||||
|
|
||||||
# ntfy.sh
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Server Root URL
|
|
||||||
|
|
||||||
Set this to the URL of your ntfy.sh server.
|
|
||||||
|
|
||||||
### Topic
|
|
||||||
|
|
||||||
Set this to the topic you want to send notifications to.
|
|
||||||
|
|
||||||
### Username + Password authentication (optional)
|
|
||||||
|
|
||||||
Set this to the username and password for your ntfy.sh server.
|
|
||||||
|
|
||||||
### Token authentication (optional)
|
|
||||||
|
|
||||||
Set this to the token for your ntfy.sh server.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Please refer to the [ntfy.sh API documentation](https://docs.ntfy.sh/) for more details on configuring these notifications.
|
|
||||||
:::
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: Pushbullet
|
|
||||||
description: Configure Pushbullet notifications.
|
|
||||||
sidebar_position: 7
|
|
||||||
---
|
|
||||||
|
|
||||||
# Pushbullet
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Users can optionally configure personal notifications in their user settings.
|
|
||||||
|
|
||||||
User notifications are separate from system notifications, and the available notification types are dependent on user permissions.
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Access Token
|
|
||||||
|
|
||||||
[Create an access token](https://www.pushbullet.com/#settings) and set it here to grant Jellyseerr access to the Pushbullet API.
|
|
||||||
|
|
||||||
### Channel Tag (optional)
|
|
||||||
|
|
||||||
Optionally, [create a channel](https://www.pushbullet.com/my-channel) to allow other users to follow the notification feed using the specified channel tag.
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
---
|
|
||||||
title: Pushover
|
|
||||||
description: Configure Pushover notifications.
|
|
||||||
sidebar_position: 8
|
|
||||||
---
|
|
||||||
|
|
||||||
# Pushover
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Users can optionally configure personal notifications in their user settings.
|
|
||||||
|
|
||||||
User notifications are separate from system notifications, and the available notification types are dependent on user permissions.
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Application/API Token
|
|
||||||
|
|
||||||
[Register an application](https://pushover.net/apps/build) and enter the API token in this field. (You can use one of the [official icons in our GitHub repository](https://github.com/fallenbagel/jellyseerr/tree/develop/public) when configuring the application.)
|
|
||||||
|
|
||||||
For more details on registering applications or the API token, please see the [Pushover API documentation](https://pushover.net/api#registration).
|
|
||||||
|
|
||||||
### User Key
|
|
||||||
|
|
||||||
Set this to the user key for your Pushover account. Alternatively, you can set this to a group key to deliver notifications to multiple users.
|
|
||||||
|
|
||||||
For more details, please see the [Pushover API documentation](https://pushover.net/api#identifiers).
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
title: Slack
|
|
||||||
description: Configure Slack notifications.
|
|
||||||
sidebar_position: 9
|
|
||||||
---
|
|
||||||
|
|
||||||
# Slack
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Webhook URL
|
|
||||||
|
|
||||||
Simply [create a webhook](https://my.slack.com/services/new/incoming-webhook/) and enter the URL in this field.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Please refer to the [Slack API documentation](https://api.slack.com/messaging/webhooks) for more details on configuring these notifications.
|
|
||||||
:::
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
title: Telegram
|
|
||||||
description: Configure Telegram notifications.
|
|
||||||
sidebar_position: 10
|
|
||||||
---
|
|
||||||
|
|
||||||
# Telegram
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Users can optionally configure personal notifications in their user settings.
|
|
||||||
|
|
||||||
User notifications are separate from system notifications, and the available notification types are dependent on user permissions.
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
:::info
|
|
||||||
In order to configure Telegram notifications, you first need to [create a bot](https://telegram.me/BotFather).
|
|
||||||
|
|
||||||
Bots **cannot** initiate conversations with users, so users must have your bot added to a conversation in order to receive notifications.
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Bot Username (optional)
|
|
||||||
|
|
||||||
If this value is configured, users will be able to click a link to start a chat with your bot and configure their own personal notifications.
|
|
||||||
|
|
||||||
The bot username should end with `_bot`, and the `@` prefix should be omitted.
|
|
||||||
|
|
||||||
### Bot Authentication Token
|
|
||||||
|
|
||||||
At the end of the bot creation process, [@BotFather](https://telegram.me/botfather) will provide an authentication token.
|
|
||||||
|
|
||||||
### Chat ID
|
|
||||||
|
|
||||||
To obtain your chat ID, simply create a new group chat, add [@get_id_bot](https://telegram.me/get_id_bot), and issue the `/my_id` command.
|
|
||||||
|
|
||||||
### Send Silently (optional)
|
|
||||||
|
|
||||||
Optionally, notifications can be sent silently. Silent notifications send messages without notification sounds.
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
---
|
|
||||||
title: Webhook
|
|
||||||
description: Configure webhook notifications.
|
|
||||||
sidebar_position: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
# Webhook
|
|
||||||
|
|
||||||
The webhook notification agent enables you to send a custom JSON payload to any endpoint for specific notification events.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Webhook URL
|
|
||||||
|
|
||||||
The URL you would like to post notifications to. Your JSON will be sent as the body of the request.
|
|
||||||
|
|
||||||
### Authorization Header (optional)
|
|
||||||
|
|
||||||
:::info
|
|
||||||
This is typically not needed. Please refer to your webhook provider's documentation for details.
|
|
||||||
:::
|
|
||||||
|
|
||||||
This value will be sent as an `Authorization` HTTP header.
|
|
||||||
|
|
||||||
### JSON Payload
|
|
||||||
|
|
||||||
Customize the JSON payload to suit your needs. Jellyseerr provides several [template variables](#template-variables) for use in the payload, which will be replaced with the relevant data when the notifications are triggered.
|
|
||||||
|
|
||||||
## Template Variables
|
|
||||||
|
|
||||||
### General
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| `{{notification_type}}` | The type of notification (e.g. `MEDIA_PENDING` or `ISSUE_COMMENT`) |
|
|
||||||
| `{{event}}` | A friendly description of the notification event |
|
|
||||||
| `{{subject}}` | The notification subject (typically the media title) |
|
|
||||||
| `{{message}}` | The notification message body (the media overview/synopsis for request notifications; the issue description for issue notificatons) |
|
|
||||||
| `{{image}}` | The notification image (typically the media poster) |
|
|
||||||
|
|
||||||
### Notify User
|
|
||||||
|
|
||||||
These variables are for the target recipient of the notification.
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ---------------------------------------- | ------------------------------------------------------------- |
|
|
||||||
| `{{notifyuser_username}}` | The target notification recipient's username |
|
|
||||||
| `{{notifyuser_email}}` | The target notification recipient's email address |
|
|
||||||
| `{{notifyuser_avatar}}` | The target notification recipient's avatar URL |
|
|
||||||
| `{{notifyuser_settings_discordId}}` | The target notification recipient's Discord ID (if set) |
|
|
||||||
| `{{notifyuser_settings_telegramChatId}}` | The target notification recipient's Telegram Chat ID (if set) |
|
|
||||||
|
|
||||||
:::info
|
|
||||||
The `notifyuser` variables are not defined for the following request notification types, as they are intended for application administrators rather than end users:
|
|
||||||
|
|
||||||
- Request Pending Approval
|
|
||||||
- Request Automatically Approved
|
|
||||||
- Request Processing Failed
|
|
||||||
|
|
||||||
On the other hand, the `notifyuser` variables _will_ be replaced with the requesting user's information for the below notification types:
|
|
||||||
|
|
||||||
- Request Approved
|
|
||||||
- Request Declined
|
|
||||||
- Request Available
|
|
||||||
|
|
||||||
If you would like to use the requesting user's information in your webhook, please instead include the relevant variables from the [Request](#request) section below.
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Special
|
|
||||||
|
|
||||||
The following variables must be used as a key in the JSON payload (e.g., `"{{extra}}": []`).
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| `{{media}}` | The relevant media object |
|
|
||||||
| `{{request}}` | The relevant request object |
|
|
||||||
| `{{issue}}` | The relevant issue object |
|
|
||||||
| `{{comment}}` | The relevant issue comment object |
|
|
||||||
| `{{extra}}` | The "extra" array of additional data for certain notifications (e.g., season/episode numbers for series-related notifications) |
|
|
||||||
|
|
||||||
#### Media
|
|
||||||
|
|
||||||
The `{{media}}` will be `null` if there is no relevant media object for the notification.
|
|
||||||
|
|
||||||
These following special variables are only included in media-related notifications, such as requests.
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| -------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| `{{media_type}}` | The media type (`movie` or `tv`) |
|
|
||||||
| `{{media_tmdbid}}` | The media's TMDB ID |
|
|
||||||
| `{{media_tvdbid}}` | The media's TheTVDB ID |
|
|
||||||
| `{{media_status}}` | The media's availability status (`UNKNOWN`, `PENDING`, `PROCESSING`, `PARTIALLY_AVAILABLE`, or `AVAILABLE`) |
|
|
||||||
| `{{media_status4k}}` | The media's 4K availability status (`UNKNOWN`, `PENDING`, `PROCESSING`, `PARTIALLY_AVAILABLE`, or `AVAILABLE`) |
|
|
||||||
|
|
||||||
#### Request
|
|
||||||
|
|
||||||
The `{{request}}` will be `null` if there is no relevant media object for the notification.
|
|
||||||
|
|
||||||
The following special variables are only included in request-related notifications.
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ----------------------------------------- | ----------------------------------------------- |
|
|
||||||
| `{{request_id}}` | The request ID |
|
|
||||||
| `{{requestedBy_username}}` | The requesting user's username |
|
|
||||||
| `{{requestedBy_email}}` | The requesting user's email address |
|
|
||||||
| `{{requestedBy_avatar}}` | The requesting user's avatar URL |
|
|
||||||
| `{{requestedBy_settings_discordId}}` | The requesting user's Discord ID (if set) |
|
|
||||||
| `{{requestedBy_settings_telegramChatId}}` | The requesting user's Telegram Chat ID (if set) |
|
|
||||||
|
|
||||||
#### Issue
|
|
||||||
|
|
||||||
The `{{issue}}` will be `null` if there is no relevant media object for the notification.
|
|
||||||
|
|
||||||
The following special variables are only included in issue-related notifications.
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ---------------------------------------- | ----------------------------------------------- |
|
|
||||||
| `{{issue_id}}` | The issue ID |
|
|
||||||
| `{{reportedBy_username}}` | The requesting user's username |
|
|
||||||
| `{{reportedBy_email}}` | The requesting user's email address |
|
|
||||||
| `{{reportedBy_avatar}}` | The requesting user's avatar URL |
|
|
||||||
| `{{reportedBy_settings_discordId}}` | The requesting user's Discord ID (if set) |
|
|
||||||
| `{{reportedBy_settings_telegramChatId}}` | The requesting user's Telegram Chat ID (if set) |
|
|
||||||
|
|
||||||
#### Comment
|
|
||||||
|
|
||||||
The `{{comment}}` will be `null` if there is no relevant media object for the notification.
|
|
||||||
|
|
||||||
The following special variables are only included in issue comment-related notifications.
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ----------------------------------------- | ----------------------------------------------- |
|
|
||||||
| `{{comment_message}}` | The comment message |
|
|
||||||
| `{{commentedBy_username}}` | The commenting user's username |
|
|
||||||
| `{{commentedBy_email}}` | The commenting user's email address |
|
|
||||||
| `{{commentedBy_avatar}}` | The commenting user's avatar URL |
|
|
||||||
| `{{commentedBy_settings_discordId}}` | The commenting user's Discord ID (if set) |
|
|
||||||
| `{{commentedBy_settings_telegramChatId}}` | The commenting user's Telegram Chat ID (if set) |
|
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"cronstrue": "2.23.0",
|
"cronstrue": "2.23.0",
|
||||||
"date-fns": "2.29.3",
|
"date-fns": "2.29.3",
|
||||||
"dayjs": "1.11.7",
|
"dayjs": "1.11.7",
|
||||||
"dns-caching": "^0.2.5",
|
"dns-caching": "^0.2.4",
|
||||||
"email-templates": "12.0.1",
|
"email-templates": "12.0.1",
|
||||||
"email-validator": "2.0.4",
|
"email-validator": "2.0.4",
|
||||||
"express": "4.21.2",
|
"express": "4.21.2",
|
||||||
|
|||||||
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@@ -84,8 +84,8 @@ importers:
|
|||||||
specifier: 1.11.7
|
specifier: 1.11.7
|
||||||
version: 1.11.7
|
version: 1.11.7
|
||||||
dns-caching:
|
dns-caching:
|
||||||
specifier: ^0.2.5
|
specifier: ^0.2.4
|
||||||
version: 0.2.5
|
version: 0.2.4
|
||||||
email-templates:
|
email-templates:
|
||||||
specifier: 12.0.1
|
specifier: 12.0.1
|
||||||
version: 12.0.1(@babel/core@7.24.7)(encoding@0.1.13)(handlebars@4.7.8)(mustache@4.2.0)(pug@3.0.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(underscore@1.13.7)
|
version: 12.0.1(@babel/core@7.24.7)(encoding@0.1.13)(handlebars@4.7.8)(mustache@4.2.0)(pug@3.0.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(underscore@1.13.7)
|
||||||
@@ -4864,8 +4864,8 @@ packages:
|
|||||||
dlv@1.1.3:
|
dlv@1.1.3:
|
||||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||||
|
|
||||||
dns-caching@0.2.5:
|
dns-caching@0.2.4:
|
||||||
resolution: {integrity: sha512-1cnB6i/OG4zfYbRnDjWZDT+FGLvOBuJlFIxVZvHBiaa62SCfaGoP4Si50O14HyoHmx1gadeGWigYXdX5LQAFvg==}
|
resolution: {integrity: sha512-J48CLnMScOAtWIdExkz+522A0nPUwG5o+w7vVsXBJDipVLugCnps5AVJMn9bOkqQm4GarHtutMHYJEryCTeMjA==}
|
||||||
|
|
||||||
doctrine@2.1.0:
|
doctrine@2.1.0:
|
||||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||||
@@ -15700,7 +15700,7 @@ snapshots:
|
|||||||
|
|
||||||
dlv@1.1.3: {}
|
dlv@1.1.3: {}
|
||||||
|
|
||||||
dns-caching@0.2.5:
|
dns-caching@0.2.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache: 11.1.0
|
lru-cache: 11.1.0
|
||||||
|
|
||||||
@@ -16093,7 +16093,7 @@ snapshots:
|
|||||||
debug: 4.4.0(supports-color@5.5.0)
|
debug: 4.4.0(supports-color@5.5.0)
|
||||||
enhanced-resolve: 5.17.0
|
enhanced-resolve: 5.17.0
|
||||||
eslint: 8.35.0
|
eslint: 8.35.0
|
||||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.35.0))(eslint@8.35.0)
|
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.35.0)
|
||||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.54.0(eslint@8.35.0)(typescript@4.9.5))(eslint@8.35.0)
|
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.54.0(eslint@8.35.0)(typescript@4.9.5))(eslint@8.35.0)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
get-tsconfig: 4.7.5
|
get-tsconfig: 4.7.5
|
||||||
@@ -16115,7 +16115,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.35.0))(eslint@8.35.0):
|
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.35.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7(supports-color@8.1.1)
|
debug: 3.2.7(supports-color@8.1.1)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ export interface IMDBRating {
|
|||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
criticsScore: number;
|
criticsScore: number;
|
||||||
criticsScoreCount: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,7 +187,6 @@ class IMDBRadarrProxy extends ExternalAPI {
|
|||||||
title: data[0].Title,
|
title: data[0].Title,
|
||||||
url: `https://www.imdb.com/title/${data[0].ImdbId}`,
|
url: `https://www.imdb.com/title/${data[0].ImdbId}`,
|
||||||
criticsScore: data[0].MovieRatings.Imdb.Value,
|
criticsScore: data[0].MovieRatings.Imdb.Value,
|
||||||
criticsScoreCount: data[0].MovieRatings.Imdb.Count,
|
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { DnsEntries, DnsStats } from 'dns-caching';
|
|
||||||
import type { PaginatedResponse } from './common';
|
import type { PaginatedResponse } from './common';
|
||||||
|
|
||||||
export type LogMessage = {
|
export type LogMessage = {
|
||||||
@@ -62,12 +61,38 @@ export interface CacheItem {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DNSAddresses {
|
||||||
|
ipv4: number;
|
||||||
|
ipv6: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DNSRecord {
|
||||||
|
addresses: DNSAddresses;
|
||||||
|
activeAddress: string;
|
||||||
|
family: number;
|
||||||
|
age: number;
|
||||||
|
ttl: number;
|
||||||
|
networkErrors: number;
|
||||||
|
hits: number;
|
||||||
|
misses: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DNSStats {
|
||||||
|
size: number;
|
||||||
|
maxSize: number;
|
||||||
|
hits: number;
|
||||||
|
misses: number;
|
||||||
|
failures: number;
|
||||||
|
ipv4Fallbacks: number;
|
||||||
|
hitRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CacheResponse {
|
export interface CacheResponse {
|
||||||
apiCaches: CacheItem[];
|
apiCaches: CacheItem[];
|
||||||
imageCache: Record<'tmdb' | 'avatar', { size: number; imageCount: number }>;
|
imageCache: Record<'tmdb' | 'avatar', { size: number; imageCount: number }>;
|
||||||
dnsCache: {
|
dnsCache: {
|
||||||
stats: DnsStats | undefined;
|
entries: Record<string, DNSRecord>;
|
||||||
entries: DnsEntries | undefined;
|
stats: DNSStats;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ issueRoutes.get<Record<string, string>, IssueResultsResponse>(
|
|||||||
.leftJoinAndSelect('issue.createdBy', 'createdBy')
|
.leftJoinAndSelect('issue.createdBy', 'createdBy')
|
||||||
.leftJoinAndSelect('issue.media', 'media')
|
.leftJoinAndSelect('issue.media', 'media')
|
||||||
.leftJoinAndSelect('issue.modifiedBy', 'modifiedBy')
|
.leftJoinAndSelect('issue.modifiedBy', 'modifiedBy')
|
||||||
.leftJoinAndSelect('issue.comments', 'comments')
|
|
||||||
.leftJoinAndSelect('comments.user', 'user')
|
|
||||||
.where('issue.status IN (:...issueStatus)', {
|
.where('issue.status IN (:...issueStatus)', {
|
||||||
issueStatus: statusFilter,
|
issueStatus: statusFilter,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ import discoverSettingRoutes from '@server/routes/settings/discover';
|
|||||||
import { ApiError } from '@server/types/error';
|
import { ApiError } from '@server/types/error';
|
||||||
import { appDataPath } from '@server/utils/appDataVolume';
|
import { appDataPath } from '@server/utils/appDataVolume';
|
||||||
import { getAppVersion } from '@server/utils/appVersion';
|
import { getAppVersion } from '@server/utils/appVersion';
|
||||||
import { dnsCache } from '@server/utils/dnsCache';
|
import dnsCache from '@server/utils/dnsCache';
|
||||||
import { getHostname } from '@server/utils/getHostname';
|
import { getHostname } from '@server/utils/getHostname';
|
||||||
import type { DnsEntries, DnsStats } from 'dns-caching';
|
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import rateLimit from 'express-rate-limit';
|
import rateLimit from 'express-rate-limit';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
@@ -757,8 +756,8 @@ settingsRoutes.get('/cache', async (_req, res) => {
|
|||||||
const tmdbImageCache = await ImageProxy.getImageStats('tmdb');
|
const tmdbImageCache = await ImageProxy.getImageStats('tmdb');
|
||||||
const avatarImageCache = await ImageProxy.getImageStats('avatar');
|
const avatarImageCache = await ImageProxy.getImageStats('avatar');
|
||||||
|
|
||||||
const stats: DnsStats | undefined = dnsCache?.getStats();
|
const stats = dnsCache?.getStats();
|
||||||
const entries: DnsEntries | undefined = dnsCache?.getCacheEntries();
|
const entries = dnsCache?.getCacheEntries();
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
apiCaches,
|
apiCaches,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import logger from '@server/logger';
|
import logger from '@server/logger';
|
||||||
import { DnsCacheManager } from 'dns-caching';
|
import { DnsCacheManager } from 'dns-caching';
|
||||||
|
|
||||||
export let dnsCache: DnsCacheManager | undefined;
|
let dnsCache: DnsCacheManager | undefined;
|
||||||
|
|
||||||
export function initializeDnsCache({
|
export function initializeDnsCache({
|
||||||
forceMinTtl,
|
forceMinTtl,
|
||||||
@@ -24,3 +24,5 @@ export function initializeDnsCache({
|
|||||||
});
|
});
|
||||||
dnsCache.initialize();
|
dnsCache.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default dnsCache;
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ const SettingsTabs = ({
|
|||||||
Select a Tab
|
Select a Tab
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="tabs"
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
router.push(e.target.value);
|
router.push(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
import Badge from '@app/components/Common/Badge';
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
import CachedImage from '@app/components/Common/CachedImage';
|
import CachedImage from '@app/components/Common/CachedImage';
|
||||||
import Tooltip from '@app/components/Common/Tooltip';
|
|
||||||
import { issueOptions } from '@app/components/IssueModal/constants';
|
import { issueOptions } from '@app/components/IssueModal/constants';
|
||||||
import { Permission, useUser } from '@app/hooks/useUser';
|
import { Permission, useUser } from '@app/hooks/useUser';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
@@ -27,7 +26,6 @@ const messages = defineMessages('components.IssueList.IssueItem', {
|
|||||||
opened: 'Opened',
|
opened: 'Opened',
|
||||||
viewissue: 'View Issue',
|
viewissue: 'View Issue',
|
||||||
unknownissuetype: 'Unknown',
|
unknownissuetype: 'Unknown',
|
||||||
descriptionpreview: 'Issue Description',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
|
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
|
||||||
@@ -109,15 +107,8 @@ const IssueItem = ({ issue }: IssueItemProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const description = issue.comments?.[0]?.message || '';
|
|
||||||
const maxDescriptionLength = 120;
|
|
||||||
const shouldTruncate = description.length > maxDescriptionLength;
|
|
||||||
const truncatedDescription = shouldTruncate
|
|
||||||
? description.substring(0, maxDescriptionLength) + '...'
|
|
||||||
: description;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-gray-700 xl:flex-row">
|
<div className="relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-gray-700 xl:h-28 xl:flex-row">
|
||||||
{title.backdropPath && (
|
{title.backdropPath && (
|
||||||
<div className="absolute inset-0 z-0 w-full bg-cover bg-center xl:w-2/3">
|
<div className="absolute inset-0 z-0 w-full bg-cover bg-center xl:w-2/3">
|
||||||
<CachedImage
|
<CachedImage
|
||||||
@@ -177,38 +168,8 @@ const IssueItem = ({ issue }: IssueItemProps) => {
|
|||||||
>
|
>
|
||||||
{isMovie(title) ? title.title : title.name}
|
{isMovie(title) ? title.title : title.name}
|
||||||
</Link>
|
</Link>
|
||||||
{description && (
|
|
||||||
<div className="mt-1 max-w-full">
|
|
||||||
<div className="overflow-hidden text-sm text-gray-300">
|
|
||||||
{shouldTruncate ? (
|
|
||||||
<Tooltip
|
|
||||||
content={
|
|
||||||
<div className="max-w-sm p-3">
|
|
||||||
<div className="mb-1 text-sm font-medium text-gray-200">
|
|
||||||
Issue Description
|
|
||||||
</div>
|
|
||||||
<div className="whitespace-pre-wrap text-sm leading-relaxed text-gray-300">
|
|
||||||
{description}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
tooltipConfig={{
|
|
||||||
placement: 'top',
|
|
||||||
offset: [0, 8],
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="block cursor-help truncate transition-colors hover:text-gray-200">
|
|
||||||
{truncatedDescription}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
) : (
|
|
||||||
<span className="block break-words">{description}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{problemSeasonEpisodeLine.length > 0 && (
|
{problemSeasonEpisodeLine.length > 0 && (
|
||||||
<div className="card-field mt-1">
|
<div className="card-field">
|
||||||
{problemSeasonEpisodeLine.map((t, k) => (
|
{problemSeasonEpisodeLine.map((t, k) => (
|
||||||
<span key={k}>{t}</span>
|
<span key={k}>{t}</span>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ const messages = defineMessages('components.MovieDetails', {
|
|||||||
rtcriticsscore: 'Rotten Tomatoes Tomatometer',
|
rtcriticsscore: 'Rotten Tomatoes Tomatometer',
|
||||||
rtaudiencescore: 'Rotten Tomatoes Audience Score',
|
rtaudiencescore: 'Rotten Tomatoes Audience Score',
|
||||||
tmdbuserscore: 'TMDB User Score',
|
tmdbuserscore: 'TMDB User Score',
|
||||||
imdbuserscore: 'IMDB User Score – votes: {formattedCount}',
|
imdbuserscore: 'IMDB User Score',
|
||||||
watchlistSuccess: '<strong>{title}</strong> added to watchlist successfully!',
|
watchlistSuccess: '<strong>{title}</strong> added to watchlist successfully!',
|
||||||
watchlistDeleted:
|
watchlistDeleted:
|
||||||
'<strong>{title}</strong> Removed from watchlist successfully!',
|
'<strong>{title}</strong> Removed from watchlist successfully!',
|
||||||
@@ -812,18 +812,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ratingData?.imdb?.criticsScore && (
|
{ratingData?.imdb?.criticsScore && (
|
||||||
<Tooltip
|
<Tooltip content={intl.formatMessage(messages.imdbuserscore)}>
|
||||||
content={intl.formatMessage(messages.imdbuserscore, {
|
|
||||||
formattedCount: intl.formatNumber(
|
|
||||||
ratingData.imdb.criticsScoreCount,
|
|
||||||
{
|
|
||||||
notation: 'compact',
|
|
||||||
compactDisplay: 'short',
|
|
||||||
maximumFractionDigits: 1,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
href={ratingData.imdb.url}
|
href={ratingData.imdb.url}
|
||||||
className="media-rating"
|
className="media-rating"
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ const PWAHeader = ({ applicationTitle = 'Jellyseerr' }: PWAHeaderProps) => {
|
|||||||
href="/apple-splash-1136-640.jpg"
|
href="/apple-splash-1136-640.jpg"
|
||||||
media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
|
media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
|
||||||
/>
|
/>
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta
|
<meta
|
||||||
name="apple-mobile-web-app-status-bar-style"
|
name="apple-mobile-web-app-status-bar-style"
|
||||||
content="black-translucent"
|
content="black-translucent"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
import Badge from '@app/components/Common/Badge';
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
import CachedImage from '@app/components/Common/CachedImage';
|
|
||||||
import Tooltip from '@app/components/Common/Tooltip';
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import RequestModal from '@app/components/RequestModal';
|
import RequestModal from '@app/components/RequestModal';
|
||||||
import useRequestOverride from '@app/hooks/useRequestOverride';
|
import useRequestOverride from '@app/hooks/useRequestOverride';
|
||||||
@@ -96,58 +95,36 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5">
|
<div className="mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5">
|
||||||
<div className="white mb-1 flex flex-nowrap">
|
<div className="white mb-1 flex flex-nowrap">
|
||||||
<span className="flex w-40 items-center truncate md:w-auto">
|
<Tooltip content={intl.formatMessage(messages.requestedby)}>
|
||||||
<Tooltip content={intl.formatMessage(messages.requestedby)}>
|
<UserIcon className="mr-1.5 h-5 w-5 min-w-0 flex-shrink-0" />
|
||||||
<UserIcon className="mr-1.5 h-5 w-5 min-w-0 flex-shrink-0" />
|
</Tooltip>
|
||||||
</Tooltip>
|
<span className="w-40 truncate md:w-auto">
|
||||||
<Link
|
<Link
|
||||||
href={
|
href={
|
||||||
request.requestedBy.id === user?.id
|
request.requestedBy.id === user?.id
|
||||||
? '/profile'
|
? '/profile'
|
||||||
: `/users/${request.requestedBy.id}`
|
: `/users/${request.requestedBy.id}`
|
||||||
}
|
}
|
||||||
className="flex items-center font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
||||||
>
|
>
|
||||||
<span className="avatar-sm">
|
|
||||||
<CachedImage
|
|
||||||
type="avatar"
|
|
||||||
src={request.requestedBy.avatar}
|
|
||||||
alt=""
|
|
||||||
className="avatar-sm object-cover"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
{request.requestedBy.displayName}
|
{request.requestedBy.displayName}
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{request.modifiedBy && (
|
{request.modifiedBy && (
|
||||||
<div className="flex flex-nowrap">
|
<div className="flex flex-nowrap">
|
||||||
<span className="flex w-40 items-center truncate md:w-auto">
|
<Tooltip content={intl.formatMessage(messages.lastmodifiedby)}>
|
||||||
<Tooltip
|
<EyeIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
||||||
content={intl.formatMessage(messages.lastmodifiedby)}
|
</Tooltip>
|
||||||
>
|
<span className="w-40 truncate md:w-auto">
|
||||||
<EyeIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
|
||||||
</Tooltip>
|
|
||||||
<Link
|
<Link
|
||||||
href={
|
href={
|
||||||
request.modifiedBy.id === user?.id
|
request.modifiedBy.id === user?.id
|
||||||
? '/profile'
|
? '/profile'
|
||||||
: `/users/${request.modifiedBy.id}`
|
: `/users/${request.modifiedBy.id}`
|
||||||
}
|
}
|
||||||
className="flex items-center font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
||||||
>
|
>
|
||||||
<span className="avatar-sm">
|
|
||||||
<CachedImage
|
|
||||||
type="avatar"
|
|
||||||
src={request.modifiedBy.avatar}
|
|
||||||
alt=""
|
|
||||||
className="avatar-sm object-cover"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
{request.modifiedBy.displayName}
|
{request.modifiedBy.displayName}
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ const messages: { [messageName: string]: MessageDescriptor } = defineMessages(
|
|||||||
dnscachehits: 'Hits',
|
dnscachehits: 'Hits',
|
||||||
dnscachemisses: 'Misses',
|
dnscachemisses: 'Misses',
|
||||||
dnscacheage: 'Age',
|
dnscacheage: 'Age',
|
||||||
|
dnscachenetworkerrors: 'Network Errors',
|
||||||
flushdnscache: 'Flush DNS Cache',
|
flushdnscache: 'Flush DNS Cache',
|
||||||
dnsCacheGlobalStats: 'Global DNS Cache Stats',
|
dnsCacheGlobalStats: 'Global DNS Cache Stats',
|
||||||
dnsCacheGlobalStatsDescription:
|
dnsCacheGlobalStatsDescription:
|
||||||
@@ -628,6 +629,9 @@ const SettingsJobs = () => {
|
|||||||
<Table.TH>{intl.formatMessage(messages.dnscachehits)}</Table.TH>
|
<Table.TH>{intl.formatMessage(messages.dnscachehits)}</Table.TH>
|
||||||
<Table.TH>{intl.formatMessage(messages.dnscachemisses)}</Table.TH>
|
<Table.TH>{intl.formatMessage(messages.dnscachemisses)}</Table.TH>
|
||||||
<Table.TH>{intl.formatMessage(messages.dnscacheage)}</Table.TH>
|
<Table.TH>{intl.formatMessage(messages.dnscacheage)}</Table.TH>
|
||||||
|
<Table.TH>
|
||||||
|
{intl.formatMessage(messages.dnscachenetworkerrors)}
|
||||||
|
</Table.TH>
|
||||||
<Table.TH></Table.TH>
|
<Table.TH></Table.TH>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -640,6 +644,7 @@ const SettingsJobs = () => {
|
|||||||
<Table.TD>{intl.formatNumber(data.hits)}</Table.TD>
|
<Table.TD>{intl.formatNumber(data.hits)}</Table.TD>
|
||||||
<Table.TD>{intl.formatNumber(data.misses)}</Table.TD>
|
<Table.TD>{intl.formatNumber(data.misses)}</Table.TD>
|
||||||
<Table.TD>{formatAge(data.age)}</Table.TD>
|
<Table.TD>{formatAge(data.age)}</Table.TD>
|
||||||
|
<Table.TD>{intl.formatNumber(data.networkErrors)}</Table.TD>
|
||||||
<Table.TD alignText="right">
|
<Table.TD alignText="right">
|
||||||
<Button
|
<Button
|
||||||
buttonType="danger"
|
buttonType="danger"
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ const UserProfile = () => {
|
|||||||
{user.userType === UserType.PLEX &&
|
{user.userType === UserType.PLEX &&
|
||||||
(user.id === currentUser?.id ||
|
(user.id === currentUser?.id ||
|
||||||
currentHasPermission(Permission.ADMIN)) &&
|
currentHasPermission(Permission.ADMIN)) &&
|
||||||
(!watchData || !!watchData.recentlyWatched?.length) &&
|
(!watchData || !!watchData.recentlyWatched.length) &&
|
||||||
!watchDataError && (
|
!watchDataError && (
|
||||||
<>
|
<>
|
||||||
<div className="slider-header">
|
<div className="slider-header">
|
||||||
@@ -389,7 +389,7 @@ const UserProfile = () => {
|
|||||||
<Slider
|
<Slider
|
||||||
sliderKey="media"
|
sliderKey="media"
|
||||||
isLoading={!watchData}
|
isLoading={!watchData}
|
||||||
items={watchData?.recentlyWatched?.map((item) => (
|
items={watchData?.recentlyWatched.map((item) => (
|
||||||
<TmdbTitleCard
|
<TmdbTitleCard
|
||||||
key={`media-slider-item-${item.id}`}
|
key={`media-slider-item-${item.id}`}
|
||||||
id={item.id}
|
id={item.id}
|
||||||
|
|||||||
@@ -180,7 +180,6 @@
|
|||||||
"components.IssueDetails.toaststatusupdated": "Issue status updated successfully!",
|
"components.IssueDetails.toaststatusupdated": "Issue status updated successfully!",
|
||||||
"components.IssueDetails.toaststatusupdatefailed": "Something went wrong while updating the issue status.",
|
"components.IssueDetails.toaststatusupdatefailed": "Something went wrong while updating the issue status.",
|
||||||
"components.IssueDetails.unknownissuetype": "Unknown",
|
"components.IssueDetails.unknownissuetype": "Unknown",
|
||||||
"components.IssueList.IssueItem.descriptionpreview": "Issue Description",
|
|
||||||
"components.IssueList.IssueItem.episodes": "{episodeCount, plural, one {Episode} other {Episodes}}",
|
"components.IssueList.IssueItem.episodes": "{episodeCount, plural, one {Episode} other {Episodes}}",
|
||||||
"components.IssueList.IssueItem.issuestatus": "Status",
|
"components.IssueList.IssueItem.issuestatus": "Status",
|
||||||
"components.IssueList.IssueItem.issuetype": "Type",
|
"components.IssueList.IssueItem.issuetype": "Type",
|
||||||
@@ -315,7 +314,7 @@
|
|||||||
"components.MovieDetails.cast": "Cast",
|
"components.MovieDetails.cast": "Cast",
|
||||||
"components.MovieDetails.digitalrelease": "Digital Release",
|
"components.MovieDetails.digitalrelease": "Digital Release",
|
||||||
"components.MovieDetails.downloadstatus": "Download Status",
|
"components.MovieDetails.downloadstatus": "Download Status",
|
||||||
"components.MovieDetails.imdbuserscore": "IMDB User Score – votes: {formattedCount}",
|
"components.MovieDetails.imdbuserscore": "IMDB User Score",
|
||||||
"components.MovieDetails.managemovie": "Manage Movie",
|
"components.MovieDetails.managemovie": "Manage Movie",
|
||||||
"components.MovieDetails.mark4kavailable": "Mark as Available in 4K",
|
"components.MovieDetails.mark4kavailable": "Mark as Available in 4K",
|
||||||
"components.MovieDetails.markavailable": "Mark as Available",
|
"components.MovieDetails.markavailable": "Mark as Available",
|
||||||
@@ -884,6 +883,7 @@
|
|||||||
"components.Settings.SettingsJobsCache.dnscachehits": "Hits",
|
"components.Settings.SettingsJobsCache.dnscachehits": "Hits",
|
||||||
"components.Settings.SettingsJobsCache.dnscachemisses": "Misses",
|
"components.Settings.SettingsJobsCache.dnscachemisses": "Misses",
|
||||||
"components.Settings.SettingsJobsCache.dnscachename": "Hostname",
|
"components.Settings.SettingsJobsCache.dnscachename": "Hostname",
|
||||||
|
"components.Settings.SettingsJobsCache.dnscachenetworkerrors": "Network Errors",
|
||||||
"components.Settings.SettingsJobsCache.download-sync": "Download Sync",
|
"components.Settings.SettingsJobsCache.download-sync": "Download Sync",
|
||||||
"components.Settings.SettingsJobsCache.download-sync-reset": "Download Sync Reset",
|
"components.Settings.SettingsJobsCache.download-sync-reset": "Download Sync Reset",
|
||||||
"components.Settings.SettingsJobsCache.editJobSchedule": "Modify Job",
|
"components.Settings.SettingsJobsCache.editJobSchedule": "Modify Job",
|
||||||
@@ -988,8 +988,6 @@
|
|||||||
"components.Settings.SettingsNetwork.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
"components.Settings.SettingsNetwork.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
||||||
"components.Settings.SettingsNetwork.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
"components.Settings.SettingsNetwork.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
||||||
"components.Settings.SettingsNetwork.dnsCache": "DNS Cache",
|
"components.Settings.SettingsNetwork.dnsCache": "DNS Cache",
|
||||||
"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl": "DNS Cache Maximum TTL",
|
|
||||||
"components.Settings.SettingsNetwork.dnsCacheForceMinTtl": "DNS Cache Minimum TTL",
|
|
||||||
"components.Settings.SettingsNetwork.dnsCacheHoverTip": "Do NOT enable this if you are experiencing issues with DNS lookups",
|
"components.Settings.SettingsNetwork.dnsCacheHoverTip": "Do NOT enable this if you are experiencing issues with DNS lookups",
|
||||||
"components.Settings.SettingsNetwork.dnsCacheTip": "Enable caching of DNS lookups to optimize performance and avoid making unnecessary API calls",
|
"components.Settings.SettingsNetwork.dnsCacheTip": "Enable caching of DNS lookups to optimize performance and avoid making unnecessary API calls",
|
||||||
"components.Settings.SettingsNetwork.docs": "documentation",
|
"components.Settings.SettingsNetwork.docs": "documentation",
|
||||||
|
|||||||
Reference in New Issue
Block a user