Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4K Requests #559

Merged
merged 12 commits into from
Jan 11, 2021
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ yarn-error.log*
.vercel

# database
config/db/db.sqlite3
config/db/*.sqlite3
config/settings.json

# logs
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@

- User profiles.
- User settings page (to give users the ability to modify their Overseerr experience to their liking).
- 4K requests (Includes multi-radarr/sonarr management for media)
- Local user system (for those who don't use Plex).

## Planned Features

- More notification types.
- Issues system. This will allow users to report issues with content on your media server.
- Local user system (for those who don't use Plex).
- Compatibility APIs (to work with existing tools in your system).
- And a ton more! Check out our [issue tracker](https://github.com/sct/overseerr/issues) to see what features people have already requested.

## Getting Started

Expand Down Expand Up @@ -142,4 +141,5 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->
18 changes: 18 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,15 @@ components:
- $ref: '#/components/schemas/User'
- type: string
nullable: true
is4k:
type: boolean
example: false
serverId:
type: number
profileId:
type: number
rootFolder:
type: string
required:
- id
- status
Expand Down Expand Up @@ -2364,6 +2373,15 @@ paths:
type: array
items:
type: number
is4k:
type: boolean
example: false
serverId:
type: number
profileId:
type: number
rootFolder:
type: string
required:
- mediaType
- mediaId
Expand Down
17 changes: 17 additions & 0 deletions server/api/plexapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ export interface PlexMetadata {
parentIndex?: number;
leafCount: number;
viewedLeafCount: number;
Media: Media[];
}

interface Media {
id: number;
duration: number;
bitrate: number;
width: number;
height: number;
aspectRatio: number;
audioChannels: number;
audioCodec: string;
videoCodec: string;
videoResolution: string;
container: string;
videoFrameRate: string;
videoProfile: string;
}

interface PlexMetadataResponse {
Expand Down
3 changes: 3 additions & 0 deletions server/entity/Media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class Media {
@Column({ type: 'int', default: MediaStatus.UNKNOWN })
public status: MediaStatus;

@Column({ type: 'int', default: MediaStatus.UNKNOWN })
public status4k: MediaStatus;

@OneToMany(() => MediaRequest, (request) => request.media, { cascade: true })
public requests: MediaRequest[];

Expand Down
55 changes: 46 additions & 9 deletions server/entity/MediaRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ export class MediaRequest {
})
public seasons: SeasonRequest[];

@Column({ default: false })
public is4k: boolean;

@Column({ nullable: true })
public serverId: number;

@Column({ nullable: true })
public profileId: number;

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

constructor(init?: Partial<MediaRequest>) {
Object.assign(this, init);
}
Expand Down Expand Up @@ -181,15 +193,23 @@ export class MediaRequest {
}
const seasonRequestRepository = getRepository(SeasonRequest);
if (this.status === MediaRequestStatus.APPROVED) {
media.status = MediaStatus.PROCESSING;
if (this.is4k) {
media.status4k = MediaStatus.PROCESSING;
} else {
media.status = MediaStatus.PROCESSING;
}
mediaRepository.save(media);
}

if (
this.media.mediaType === MediaType.MOVIE &&
this.status === MediaRequestStatus.DECLINED
) {
media.status = MediaStatus.UNKNOWN;
if (this.is4k) {
media.status4k = MediaStatus.UNKNOWN;
} else {
media.status = MediaStatus.UNKNOWN;
}
mediaRepository.save(media);
}

Expand Down Expand Up @@ -224,15 +244,28 @@ export class MediaRequest {
}

@AfterRemove()
private async _handleRemoveParentUpdate() {
public async handleRemoveParentUpdate(): Promise<void> {
const mediaRepository = getRepository(Media);
const fullMedia = await mediaRepository.findOneOrFail({
where: { id: this.media.id },
relations: ['requests'],
});
if (!fullMedia.requests || fullMedia.requests.length === 0) {

if (
!fullMedia.requests.some((request) => !request.is4k) &&
fullMedia.status !== MediaStatus.AVAILABLE
) {
fullMedia.status = MediaStatus.UNKNOWN;
mediaRepository.save(fullMedia);
}

if (
!fullMedia.requests.some((request) => request.is4k) &&
fullMedia.status4k !== MediaStatus.AVAILABLE
) {
fullMedia.status4k = MediaStatus.UNKNOWN;
}

mediaRepository.save(fullMedia);
}

private async _sendToRadarr() {
Expand All @@ -252,12 +285,14 @@ export class MediaRequest {
}

const radarrSettings = settings.radarr.find(
(radarr) => radarr.isDefault && !radarr.is4k
(radarr) => radarr.isDefault && this.is4k
);

if (!radarrSettings) {
logger.info(
'There is no default radarr configured. Did you set any of your Radarr servers as default?',
`There is no default ${
this.is4k ? '4K ' : ''
}radarr configured. Did you set any of your Radarr servers as default?`,
{ label: 'Media Request' }
);
return;
Expand Down Expand Up @@ -342,12 +377,14 @@ export class MediaRequest {
}

const sonarrSettings = settings.sonarr.find(
(sonarr) => sonarr.isDefault && !sonarr.is4k
(sonarr) => sonarr.isDefault && this.is4k
);

if (!sonarrSettings) {
logger.info(
'There is no default sonarr configured. Did you set any of your Sonarr servers as default?',
`There is no default ${
this.is4k ? '4K ' : ''
}sonarr configured. Did you set any of your Sonarr servers as default?`,
{ label: 'Media Request' }
);
return;
Expand Down
3 changes: 3 additions & 0 deletions server/entity/Season.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class Season {
@Column({ type: 'int', default: MediaStatus.UNKNOWN })
public status: MediaStatus;

@Column({ type: 'int', default: MediaStatus.UNKNOWN })
public status4k: MediaStatus;

@ManyToOne(() => Media, (media) => media.seasons, { onDelete: 'CASCADE' })
public media: Promise<Media>;

Expand Down
1 change: 1 addition & 0 deletions server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ app
};
next();
});

server.use('/api/v1', routes);
server.get('*', (req, res) => handle(req, res));
server.use(
Expand Down
6 changes: 6 additions & 0 deletions server/interfaces/api/settingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ export interface SettingsAboutResponse {
totalMediaItems: number;
tz?: string;
}

export interface PublicSettingsResponse {
initialized: boolean;
movie4kEnabled: boolean;
series4kEnabled: boolean;
}
Loading