Skip to content

Commit

Permalink
feat: 4K Requests (#559)
Browse files Browse the repository at this point in the history
  • Loading branch information
sct authored Jan 11, 2021
1 parent 7962964 commit 6b2df24
Show file tree
Hide file tree
Showing 30 changed files with 1,385 additions and 468 deletions.
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

0 comments on commit 6b2df24

Please sign in to comment.