Compare commits
4 Commits
preview-av
...
preview-av
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13c71b5ae3 | ||
|
|
65844a2f23 | ||
|
|
62755692e9 | ||
|
|
beba2ea099 |
@@ -41,6 +41,7 @@
|
||||
"@formatjs/swc-plugin-experimental": "^0.4.0",
|
||||
"@headlessui/react": "1.7.12",
|
||||
"@heroicons/react": "2.2.0",
|
||||
"@seerr-team/react-tailwindcss-datepicker": "^1.3.4",
|
||||
"@supercharge/request-ip": "1.2.0",
|
||||
"@svgr/webpack": "6.5.1",
|
||||
"@tanem/react-nprogress": "5.0.56",
|
||||
@@ -90,7 +91,6 @@
|
||||
"react-popper-tooltip": "4.4.2",
|
||||
"react-select": "5.10.2",
|
||||
"react-spring": "9.7.1",
|
||||
"react-tailwindcss-datepicker-sct": "1.3.4",
|
||||
"react-toast-notifications": "2.5.1",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"react-truncate-markup": "5.1.2",
|
||||
|
||||
28
pnpm-lock.yaml
generated
28
pnpm-lock.yaml
generated
@@ -32,6 +32,9 @@ importers:
|
||||
'@heroicons/react':
|
||||
specifier: 2.2.0
|
||||
version: 2.2.0(react@18.3.1)
|
||||
'@seerr-team/react-tailwindcss-datepicker':
|
||||
specifier: ^1.3.4
|
||||
version: 1.3.4(dayjs@1.11.19)(react@18.3.1)
|
||||
'@supercharge/request-ip':
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0
|
||||
@@ -179,9 +182,6 @@ importers:
|
||||
react-spring:
|
||||
specifier: 9.7.1
|
||||
version: 9.7.1(@react-three/fiber@8.16.8(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)(three@0.165.0))(konva@9.3.12)(react-dom@18.3.1(react@18.3.1))(react-konva@18.2.10(@types/react@18.3.3)(konva@9.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(encoding@0.1.13)(react@18.3.1))(react-zdog@1.2.2)(react@18.3.1)(three@0.165.0)(zdog@1.1.3)
|
||||
react-tailwindcss-datepicker-sct:
|
||||
specifier: 1.3.4
|
||||
version: 1.3.4(dayjs@1.11.19)(react@18.3.1)
|
||||
react-toast-notifications:
|
||||
specifier: 2.5.1
|
||||
version: 2.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -2992,6 +2992,12 @@ packages:
|
||||
'@rushstack/eslint-patch@1.10.3':
|
||||
resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
|
||||
|
||||
'@seerr-team/react-tailwindcss-datepicker@1.3.4':
|
||||
resolution: {integrity: sha512-KZrnl6WL1lvUnAG4RZIkReJ+E0vSpOtMEuatobMqiWAa5Y+Z3d0ZcOOJWHoeRNtF19sIzzBkuLyhFNFlNtXg3A==}
|
||||
peerDependencies:
|
||||
dayjs: ^1.11.6
|
||||
react: ^17.0.2 || ^18.2.0
|
||||
|
||||
'@selderee/plugin-htmlparser2@0.11.0':
|
||||
resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
|
||||
|
||||
@@ -7949,12 +7955,6 @@ packages:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
|
||||
react-tailwindcss-datepicker-sct@1.3.4:
|
||||
resolution: {integrity: sha512-QlLekGZDbmW2DPGS33c4gfIxkk4gcgu4sRzBIm4/mZxfHuo7J+GR6SBVNIb5Xh8aCLlGtgyLqD+o0UmOVFIc4w==}
|
||||
peerDependencies:
|
||||
dayjs: ^1.11.6
|
||||
react: ^17.0.2 || ^18.2.0
|
||||
|
||||
react-toast-notifications@2.5.1:
|
||||
resolution: {integrity: sha512-eYuuiSPGLyuMHojRH2U7CbENvFHsvNia39pLM/s10KipIoNs14T7RIJk4aU2N+l++OsSgtJqnFObx9bpwLMU5A==}
|
||||
peerDependencies:
|
||||
@@ -13179,6 +13179,11 @@ snapshots:
|
||||
|
||||
'@rushstack/eslint-patch@1.10.3': {}
|
||||
|
||||
'@seerr-team/react-tailwindcss-datepicker@1.3.4(dayjs@1.11.19)(react@18.3.1)':
|
||||
dependencies:
|
||||
dayjs: 1.11.19
|
||||
react: 18.3.1
|
||||
|
||||
'@selderee/plugin-htmlparser2@0.11.0':
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
@@ -19185,11 +19190,6 @@ snapshots:
|
||||
- three
|
||||
- zdog
|
||||
|
||||
react-tailwindcss-datepicker-sct@1.3.4(dayjs@1.11.19)(react@18.3.1):
|
||||
dependencies:
|
||||
dayjs: 1.11.19
|
||||
react: 18.3.1
|
||||
|
||||
react-toast-notifications@2.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@emotion/core': 10.3.1(react@18.3.1)
|
||||
|
||||
@@ -332,9 +332,16 @@ export class MediaRequest {
|
||||
if (requestBody.mediaType === MediaType.MOVIE) {
|
||||
await mediaRepository.save(media);
|
||||
|
||||
if (!media.id) {
|
||||
throw new Error(
|
||||
`Failed to save media before creating request. Media type: ${requestBody.mediaType}, TMDB ID: ${requestBody.mediaId}, persisted media id: ${media.id}`
|
||||
);
|
||||
}
|
||||
|
||||
const request = new MediaRequest({
|
||||
type: MediaType.MOVIE,
|
||||
media,
|
||||
mediaId: media.id,
|
||||
requestedBy: requestUser,
|
||||
// If the user is an admin or has the "auto approve" permission, automatically approve the request
|
||||
status: user.hasPermission(
|
||||
@@ -442,9 +449,16 @@ export class MediaRequest {
|
||||
|
||||
await mediaRepository.save(media);
|
||||
|
||||
if (!media.id) {
|
||||
throw new Error(
|
||||
`Failed to save media before creating request. Media type: TV, TMDB ID: ${requestBody.mediaId}, is4k: ${requestBody.is4k}`
|
||||
);
|
||||
}
|
||||
|
||||
const request = new MediaRequest({
|
||||
type: MediaType.TV,
|
||||
media,
|
||||
mediaId: media.id,
|
||||
requestedBy: requestUser,
|
||||
// If the user is an admin or has the "auto approve" permission, automatically approve the request
|
||||
status: user.hasPermission(
|
||||
@@ -521,6 +535,9 @@ export class MediaRequest {
|
||||
})
|
||||
public media: Media;
|
||||
|
||||
@Column({ name: 'mediaId', nullable: true })
|
||||
public mediaId: number;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.requests, {
|
||||
eager: true,
|
||||
onDelete: 'CASCADE',
|
||||
|
||||
@@ -612,6 +612,24 @@ class AvailabilitySync {
|
||||
): Promise<boolean> {
|
||||
let existsInRadarr = false;
|
||||
|
||||
const has4kServer = this.radarrServers.some((s) => s.is4k);
|
||||
const hasNon4kServer = this.radarrServers.some((s) => !s.is4k);
|
||||
|
||||
logger.debug(
|
||||
`Checking Radarr for ${is4k ? '4K' : 'non-4K'} movie [TMDB ID ${
|
||||
media.tmdbId
|
||||
}]`,
|
||||
{
|
||||
label: 'AvailabilitySync',
|
||||
has4kServer,
|
||||
hasNon4kServer,
|
||||
externalServiceId: media.externalServiceId,
|
||||
externalServiceId4k: media.externalServiceId4k,
|
||||
serversToCheck: this.radarrServers.filter((s) => s.is4k === is4k)
|
||||
.length,
|
||||
}
|
||||
);
|
||||
|
||||
// Check for availability in all of the available radarr servers
|
||||
// If any find the media, we will assume the media exists
|
||||
for (const server of this.radarrServers.filter(
|
||||
@@ -642,7 +660,55 @@ class AvailabilitySync {
|
||||
radarr?.movieFile?.mediaInfo?.resolution?.split('x');
|
||||
const is4kMovie =
|
||||
resolution?.length === 2 && Number(resolution[0]) >= 2000;
|
||||
|
||||
logger.debug(
|
||||
`Radarr file found for movie [TMDB ID ${media.tmdbId}]`,
|
||||
{
|
||||
label: 'AvailabilitySync',
|
||||
serverId: server.id,
|
||||
serverIs4k: server.is4k,
|
||||
hasFile: radarr.hasFile,
|
||||
resolution: radarr?.movieFile?.mediaInfo?.resolution,
|
||||
parsedWidth: resolution?.[0],
|
||||
is4kMovie,
|
||||
checkingFor: is4k ? '4K' : 'non-4K',
|
||||
}
|
||||
);
|
||||
|
||||
if (has4kServer && hasNon4kServer) {
|
||||
// User has both server types so use resolution to distinguish
|
||||
// This handles the case where same content exists in both qualities
|
||||
existsInRadarr = is4k ? is4kMovie : !is4kMovie;
|
||||
logger.debug(
|
||||
`Dual-server setup: using resolution check for movie [TMDB ID ${media.tmdbId}]`,
|
||||
{
|
||||
label: 'AvailabilitySync',
|
||||
is4kMovie,
|
||||
is4kCheck: is4k,
|
||||
existsInRadarr,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// User only has one server type so if file exists, count it
|
||||
// Don't penalize users whose Radarr upgrades to 4K on a non-4K server
|
||||
existsInRadarr = true;
|
||||
logger.debug(
|
||||
`Single-server setup: file exists, marking as available for movie [TMDB ID ${media.tmdbId}]`,
|
||||
{
|
||||
label: 'AvailabilitySync',
|
||||
is4kMovie,
|
||||
is4kCheck: is4k,
|
||||
existsInRadarr,
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
logger.debug(`Radarr response for movie [TMDB ID ${media.tmdbId}]`, {
|
||||
label: 'AvailabilitySync',
|
||||
serverId: server.id,
|
||||
found: !!radarr,
|
||||
hasFile: radarr?.hasFile ?? false,
|
||||
});
|
||||
}
|
||||
} catch (ex) {
|
||||
if (!ex.message.includes('404')) {
|
||||
@@ -816,6 +882,50 @@ class AvailabilitySync {
|
||||
this.plexSeasonsCache[ratingKey4k] =
|
||||
await this.plexClient?.getChildrenMetadata(ratingKey4k);
|
||||
}
|
||||
|
||||
if (plexMedia) {
|
||||
if (ratingKey === ratingKey4k) {
|
||||
plexMedia = undefined;
|
||||
}
|
||||
|
||||
if (
|
||||
plexMedia &&
|
||||
media.mediaType === 'movie' &&
|
||||
!plexMedia.Media?.some(
|
||||
(mediaItem) => (mediaItem.width ?? 0) >= 2000
|
||||
)
|
||||
) {
|
||||
plexMedia = undefined;
|
||||
}
|
||||
|
||||
if (plexMedia && media.mediaType === 'tv') {
|
||||
const cachedSeasons = this.plexSeasonsCache[ratingKey4k];
|
||||
if (cachedSeasons?.length) {
|
||||
let has4kInAnySeason = false;
|
||||
for (const season of cachedSeasons) {
|
||||
try {
|
||||
const episodes = await this.plexClient?.getChildrenMetadata(
|
||||
season.ratingKey
|
||||
);
|
||||
const has4kEpisode = episodes?.some((episode) =>
|
||||
episode.Media?.some(
|
||||
(mediaItem) => (mediaItem.width ?? 0) >= 2000
|
||||
)
|
||||
);
|
||||
if (has4kEpisode) {
|
||||
has4kInAnySeason = true;
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// If we can't fetch episodes for a season, continue checking other seasons
|
||||
}
|
||||
}
|
||||
if (!has4kInAnySeason) {
|
||||
plexMedia = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (plexMedia) {
|
||||
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
} from '@app/hooks/useUpdateQueryParams';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { XCircleIcon } from '@heroicons/react/24/outline';
|
||||
import Datepicker from '@seerr-team/react-tailwindcss-datepicker';
|
||||
import { useIntl } from 'react-intl';
|
||||
import Datepicker from 'react-tailwindcss-datepicker-sct';
|
||||
|
||||
const messages = defineMessages('components.Discover.FilterSlideover', {
|
||||
filters: 'Filters',
|
||||
|
||||
@@ -5,7 +5,7 @@ const defaultTheme = require('tailwindcss/defaultTheme');
|
||||
module.exports = {
|
||||
mode: 'jit',
|
||||
content: [
|
||||
'./node_modules/react-tailwindcss-datepicker-sct/dist/index.esm.js',
|
||||
'./node_modules/@seerr-team/react-tailwindcss-datepicker/dist/index.esm.js',
|
||||
'./src/pages/**/*.{ts,tsx}',
|
||||
'./src/components/**/*.{ts,tsx}',
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user