Skip to content

Commit

Permalink
feat(usersettings): add separate setting for streaming region (#993)
Browse files Browse the repository at this point in the history
* feat: add separate setting for streaming region

Currently, the "Currently Streaming On" information is based on the Discover Region setting. This PR
adds a new setting to specify which region should be used to display the streaming region.

re #890

* fix: add missing newline

* fix: rename migration function
  • Loading branch information
gauthier-th authored Dec 8, 2024
1 parent 84fd884 commit 89831f7
Show file tree
Hide file tree
Showing 23 changed files with 243 additions and 78 deletions.
3 changes: 2 additions & 1 deletion cypress/config/settings.cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"hideAvailable": false,
"localLogin": true,
"newPlexLogin": true,
"region": "",
"discoverRegion": "",
"streamingRegion": "",
"originalLanguage": "",
"trustProxy": false,
"mediaServerType": 1,
Expand Down
4 changes: 2 additions & 2 deletions docs/using-jellyseerr/settings/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ You should enable this if you are having issues with loading images directly fro

Set the default display language for Jellyseerr. Users can override this setting in their user settings.

## Discover Region & Discover Language
## Discover Region, Discover Language & Streaming Region

These settings filter content shown on the "Discover" home page based on regional availability and original language, respectively. Users can override these global settings by configuring these same options in their user settings.
These settings filter content shown on the "Discover" home page based on regional availability and original language, respectively. The Streaming Region filters the available streaming providers on the media page. Users can override these global settings by configuring these same options in their user settings.

## Hide Available Media

Expand Down
2 changes: 1 addition & 1 deletion docs/using-jellyseerr/users/editing-users.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Users can override the [global display language](/using-jellyseerr/settings/gene

### Discover Region & Discover Language

Users can override the [global filter settings](/using-jellyseerr/settings/general#discover-region--discover-language) to suit their own preferences.
Users can override the [global filter settings](/using-jellyseerr/settings/general#discover-region-discover-language--streaming-region) to suit their own preferences.

### Movie Request Limit & Series Request Limit

Expand Down
4 changes: 3 additions & 1 deletion overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,12 @@ components:
properties:
locale:
type: string
region:
discoverRegion:
type: string
originalLanguage:
type: string
streamingRegion:
type: string
MainSettings:
type: object
properties:
Expand Down
16 changes: 8 additions & 8 deletions server/api/themoviedb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ interface DiscoverTvOptions {
}

class TheMovieDb extends ExternalAPI {
private region?: string;
private discoverRegion?: string;
private originalLanguage?: string;
constructor({
region,
discoverRegion,
originalLanguage,
}: { region?: string; originalLanguage?: string } = {}) {
}: { discoverRegion?: string; originalLanguage?: string } = {}) {
super(
'https://api.themoviedb.org/3',
{
Expand All @@ -118,7 +118,7 @@ class TheMovieDb extends ExternalAPI {
},
}
);
this.region = region;
this.discoverRegion = discoverRegion;
this.originalLanguage = originalLanguage;
}

Expand Down Expand Up @@ -469,7 +469,7 @@ class TheMovieDb extends ExternalAPI {
page: page.toString(),
include_adult: includeAdult ? 'true' : 'false',
language,
region: this.region || '',
region: this.discoverRegion || '',
with_original_language:
originalLanguage && originalLanguage !== 'all'
? originalLanguage
Expand Down Expand Up @@ -541,7 +541,7 @@ class TheMovieDb extends ExternalAPI {
sort_by: sortBy,
page: page.toString(),
language,
region: this.region || '',
region: this.discoverRegion || '',
// Set our release date values, but check if one is set and not the other,
// so we can force a past date or a future date. TMDB Requires both values if one is set!
'first_air_date.gte':
Expand Down Expand Up @@ -594,7 +594,7 @@ class TheMovieDb extends ExternalAPI {
{
page: page.toString(),
language,
region: this.region || '',
region: this.discoverRegion || '',
originalLanguage: this.originalLanguage || '',
}
);
Expand All @@ -620,7 +620,7 @@ class TheMovieDb extends ExternalAPI {
{
page: page.toString(),
language,
region: this.region || '',
region: this.discoverRegion || '',
}
);

Expand Down
5 changes: 4 additions & 1 deletion server/entity/UserSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ export class UserSettings {
public locale?: string;

@Column({ nullable: true })
public region?: string;
public discoverRegion?: string;

@Column({ nullable: true })
public streamingRegion?: string;

@Column({ nullable: true })
public originalLanguage?: string;
Expand Down
3 changes: 2 additions & 1 deletion server/interfaces/api/settingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export interface PublicSettingsResponse {
localLogin: boolean;
movie4kEnabled: boolean;
series4kEnabled: boolean;
region: string;
discoverRegion: string;
streamingRegion: string;
originalLanguage: string;
mediaServerType: number;
partialRequestsEnabled: boolean;
Expand Down
3 changes: 2 additions & 1 deletion server/interfaces/api/userSettingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export interface UserSettingsGeneralResponse {
email?: string;
discordId?: string;
locale?: string;
region?: string;
discoverRegion?: string;
streamingRegion?: string;
originalLanguage?: string;
movieQuotaLimit?: number;
movieQuotaDays?: number;
Expand Down
12 changes: 8 additions & 4 deletions server/lib/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ export interface MainSettings {
hideAvailable: boolean;
localLogin: boolean;
newPlexLogin: boolean;
region: string;
discoverRegion: string;
streamingRegion: string;
originalLanguage: string;
trustProxy: boolean;
mediaServerType: number;
Expand All @@ -144,7 +145,8 @@ interface FullPublicSettings extends PublicSettings {
localLogin: boolean;
movie4kEnabled: boolean;
series4kEnabled: boolean;
region: string;
discoverRegion: string;
streamingRegion: string;
originalLanguage: string;
mediaServerType: number;
jellyfinExternalHost?: string;
Expand Down Expand Up @@ -333,7 +335,8 @@ class Settings {
hideAvailable: false,
localLogin: true,
newPlexLogin: true,
region: '',
discoverRegion: '',
streamingRegion: '',
originalLanguage: '',
trustProxy: false,
mediaServerType: MediaServerType.NOT_CONFIGURED,
Expand Down Expand Up @@ -576,7 +579,8 @@ class Settings {
series4kEnabled: this.data.sonarr.some(
(sonarr) => sonarr.is4k && sonarr.isDefault
),
region: this.data.main.region,
discoverRegion: this.data.main.discoverRegion,
streamingRegion: this.data.main.streamingRegion,
originalLanguage: this.data.main.originalLanguage,
mediaServerType: this.main.mediaServerType,
partialRequestsEnabled: this.data.main.partialRequestsEnabled,
Expand Down
17 changes: 17 additions & 0 deletions server/lib/settings/migrations/0004_migrate_region_setting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { AllSettings } from '@server/lib/settings';

const migrateRegionSetting = (settings: any): AllSettings => {
const oldRegion = settings.main.region;
if (oldRegion) {
settings.main.discoverRegion = oldRegion;
settings.main.streamingRegion = oldRegion;
} else {
settings.main.discoverRegion = '';
settings.main.streamingRegion = 'US';
}
delete settings.main.region;

return settings;
};

export default migrateRegionSetting;
53 changes: 53 additions & 0 deletions server/migration/1727907530757-AddUserSettingsStreamingRegion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { MigrationInterface, QueryRunner } from 'typeorm';

export class AddUserSettingsStreamingRegion1727907530757
implements MigrationInterface
{
name = 'AddUserSettingsStreamingRegion1727907530757';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "pushoverSound" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
);
await queryRunner.query(
`INSERT INTO "temporary_user_settings"("id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound") SELECT "id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound" FROM "user_settings"`
);
await queryRunner.query(`DROP TABLE "user_settings"`);
await queryRunner.query(
`ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"`
);
await queryRunner.query(
`CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "pushoverSound" varchar, "discoverRegion" varchar, "streamingRegion" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
);
await queryRunner.query(
`INSERT INTO "temporary_user_settings"("id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound") SELECT "id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound" FROM "user_settings"`
);
await queryRunner.query(`DROP TABLE "user_settings"`);
await queryRunner.query(
`ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "user_settings" RENAME TO "temporary_user_settings"`
);
await queryRunner.query(
`CREATE TABLE "user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "pushoverSound" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
);
await queryRunner.query(
`INSERT INTO "user_settings"("id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound") SELECT "id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound" FROM "temporary_user_settings"`
);
await queryRunner.query(`DROP TABLE "temporary_user_settings"`);
await queryRunner.query(
`ALTER TABLE "user_settings" RENAME TO "temporary_user_settings"`
);
await queryRunner.query(
`CREATE TABLE "user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "pushoverSound" varchar, "region" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
);
await queryRunner.query(
`INSERT INTO "user_settings"("id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound") SELECT "id", "notificationTypes", "discordId", "userId", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv", "pushoverSound" FROM "temporary_user_settings"`
);
await queryRunner.query(`DROP TABLE "temporary_user_settings"`);
}
}
12 changes: 6 additions & 6 deletions server/routes/discover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ import { z } from 'zod';
export const createTmdbWithRegionLanguage = (user?: User): TheMovieDb => {
const settings = getSettings();

const region =
user?.settings?.region === 'all'
const discoverRegion =
user?.settings?.streamingRegion === 'all'
? ''
: user?.settings?.region
? user?.settings?.region
: settings.main.region;
: user?.settings?.streamingRegion
? user?.settings?.streamingRegion
: settings.main.discoverRegion;

const originalLanguage =
user?.settings?.originalLanguage === 'all'
Expand All @@ -44,7 +44,7 @@ export const createTmdbWithRegionLanguage = (user?: User): TheMovieDb => {
: settings.main.originalLanguage;

return new TheMovieDb({
region,
discoverRegion,
originalLanguage,
});
};
Expand Down
12 changes: 8 additions & 4 deletions server/routes/user/usersettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ userSettingsRoutes.get<{ id: string }, UserSettingsGeneralResponse>(
email: user.email,
discordId: user.settings?.discordId,
locale: user.settings?.locale,
region: user.settings?.region,
discoverRegion: user.settings?.discoverRegion,
streamingRegion: user.settings?.streamingRegion,
originalLanguage: user.settings?.originalLanguage,
movieQuotaLimit: user.movieQuotaLimit,
movieQuotaDays: user.movieQuotaDays,
Expand Down Expand Up @@ -147,15 +148,17 @@ userSettingsRoutes.post<
user: req.user,
discordId: req.body.discordId,
locale: req.body.locale,
region: req.body.region,
discoverRegion: req.body.discoverRegion,
streamingRegion: req.body.streamingRegion,
originalLanguage: req.body.originalLanguage,
watchlistSyncMovies: req.body.watchlistSyncMovies,
watchlistSyncTv: req.body.watchlistSyncTv,
});
} else {
user.settings.discordId = req.body.discordId;
user.settings.locale = req.body.locale;
user.settings.region = req.body.region;
user.settings.discoverRegion = req.body.discoverRegion;
user.settings.streamingRegion = req.body.streamingRegion;
user.settings.originalLanguage = req.body.originalLanguage;
user.settings.watchlistSyncMovies = req.body.watchlistSyncMovies;
user.settings.watchlistSyncTv = req.body.watchlistSyncTv;
Expand All @@ -167,7 +170,8 @@ userSettingsRoutes.post<
username: savedUser.username,
discordId: savedUser.settings?.discordId,
locale: savedUser.settings?.locale,
region: savedUser.settings?.region,
discoverRegion: savedUser.settings?.discoverRegion,
streamingRegion: savedUser.settings?.streamingRegion,
originalLanguage: savedUser.settings?.originalLanguage,
watchlistSyncMovies: savedUser.settings?.watchlistSyncMovies,
watchlistSyncTv: savedUser.settings?.watchlistSyncTv,
Expand Down
20 changes: 13 additions & 7 deletions src/components/MovieDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,14 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
});
}

const region = user?.settings?.region
? user.settings.region
: settings.currentSettings.region
? settings.currentSettings.region
const discoverRegion = user?.settings?.discoverRegion
? user.settings.discoverRegion
: settings.currentSettings.discoverRegion
? settings.currentSettings.discoverRegion
: 'US';

const releases = data.releases.results.find(
(r) => r.iso_3166_1 === region
(r) => r.iso_3166_1 === discoverRegion
)?.release_dates;

// Release date types:
Expand Down Expand Up @@ -282,9 +282,15 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
);
}

const streamingRegion = user?.settings?.streamingRegion
? user.settings.streamingRegion
: settings.currentSettings.streamingRegion
? settings.currentSettings.streamingRegion
: 'US';
const streamingProviders =
data?.watchProviders?.find((provider) => provider.iso_3166_1 === region)
?.flatrate ?? [];
data?.watchProviders?.find(
(provider) => provider.iso_3166_1 === streamingRegion
)?.flatrate ?? [];

function getAvalaibleMediaServerName() {
if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {
Expand Down
Loading

0 comments on commit 89831f7

Please sign in to comment.