diff --git a/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs b/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs index 1cc0a9cfd..d1b2d3f99 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Ombi.Core.Settings; @@ -106,6 +107,9 @@ namespace Ombi.Schedule.Jobs.Ombi await _plexRepo.ExecuteSql(episodeSQL); await _plexRepo.ExecuteSql(seasonsSql); await _plexRepo.ExecuteSql(mainSql); + + + await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IPlexContentSync), "Plex"), new JobDataMap(new Dictionary { { "recentlyAddedSearch", "false" } })); } catch (Exception e) { diff --git a/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.html b/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.html index 97d3d9f60..d218d9c9f 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.html +++ b/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.html @@ -12,7 +12,7 @@ {{result.title}}
- +
{{result.title}}
{{result.overview}}
diff --git a/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.scss b/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.scss index 21318e02b..ecefeb96c 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.scss +++ b/src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.scss @@ -236,4 +236,8 @@ a.poster-overlay:hover{ .top-right span.indicator{ padding-right:1em; } +} + +.ombi-card #cardImage:hover{ + cursor: pointer; } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.html b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.html index ecd15dc45..9cd6666b8 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.html +++ b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.html @@ -206,4 +206,4 @@
-
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts index a3ad3bfa3..06a1cf0e4 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts +++ b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewEncapsulation } from "@angular/core"; +import { AfterViewInit, Component, ViewChild, ViewEncapsulation } from "@angular/core"; import { ImageService, SearchV2Service, RequestService, MessageService, RadarrService } from "../../../services"; import { ActivatedRoute } from "@angular/router"; import { DomSanitizer } from "@angular/platform-browser"; @@ -12,6 +12,7 @@ import { NewIssueComponent } from "../shared/new-issue/new-issue.component"; import { MovieAdvancedOptionsComponent } from "./panels/movie-advanced-options/movie-advanced-options.component"; import { RequestServiceV2 } from "../../../services/requestV2.service"; import { RequestBehalfComponent } from "../shared/request-behalf/request-behalf.component"; +import { forkJoin } from "rxjs"; @Component({ templateUrl: "./movie-details.component.html", @@ -70,6 +71,7 @@ export class MovieDetailsComponent { // Load up this request this.hasRequest = true; this.movieRequest = await this.requestService.getMovieRequest(this.movie.requestId); + this.loadAdvancedInfo(); } this.loadBanner(); }); @@ -138,10 +140,10 @@ export class MovieDetailsComponent { public setAdvancedOptions(data: IAdvancedData) { this.advancedOptions = data; if (data.rootFolderId) { - this.movieRequest.qualityOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path; + this.movieRequest.qualityOverrideTitle = data.profiles.filter(x => x.id == data.profileId)[0].name; } if (data.profileId) { - this.movieRequest.rootPathOverrideTitle = data.profiles.filter(x => x.id == data.profileId)[0].name; + this.movieRequest.rootPathOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path; } } @@ -177,4 +179,30 @@ export class MovieDetailsComponent { } }); } + + private loadAdvancedInfo() { + const profile = this.radarrService.getQualityProfilesFromSettings(); + const folders = this.radarrService.getRootFoldersFromSettings(); + + forkJoin([profile, folders]).subscribe(x => { + debugger; + const radarrProfiles = x[0]; + const radarrRootFolders = x[1]; + + const profile = radarrProfiles.filter((p) => { + return p.id === this.movieRequest.qualityOverride; + }); + if (profile.length > 0) { + this.movieRequest.qualityOverrideTitle = profile[0].name; + } + + const path = radarrRootFolders.filter((folder) => { + return folder.id === this.movieRequest.rootPathOverride; + }); + if (path.length > 0) { + this.movieRequest.rootPathOverrideTitle = path[0].path; + } + + }); + } } diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html index cb23212d2..86e037002 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html @@ -9,7 +9,7 @@
+ src="https://www.gravatar.com/avatar/{{emailHash}}?d={{applicationLogo ? applicationLogo : 'https://raw.githubusercontent.com/Ombi-app/Ombi/gh-pages/img/android-chrome-512x512.png'}}" />

{{username}}

diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html index 90a3e8784..4a8c17f7c 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html +++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html @@ -30,6 +30,20 @@ + + + + @@ -71,4 +85,11 @@
+ + + + + + {{ 'Requests.RequestsTitle' | translate}}
-
\ No newline at end of file +
+ + + + + + \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts index 93cf37a64..c73084c2b 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts +++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts @@ -1,14 +1,18 @@ import { Component, AfterViewInit, ViewChild, EventEmitter, Output, ChangeDetectorRef, OnInit } from "@angular/core"; -import { IMovieRequests, IRequestsViewModel } from "../../../interfaces"; +import { IMovieRequests, IRequestEngineResult, IRequestsViewModel } from "../../../interfaces"; import { MatPaginator } from "@angular/material/paginator"; import { MatSort } from "@angular/material/sort"; -import { merge, Observable, of as observableOf } from 'rxjs'; +import { merge, Observable, of as observableOf, forkJoin } from 'rxjs'; import { catchError, map, startWith, switchMap } from 'rxjs/operators'; import { RequestServiceV2 } from "../../../services/requestV2.service"; import { AuthService } from "../../../auth/auth.service"; import { StorageService } from "../../../shared/storage/storage-service"; import { RequestFilterType } from "../../models/RequestFilterType"; +import { SelectionModel } from "@angular/cdk/collections"; +import { NotificationService, RequestService } from "../../../services"; +import { TranslateService } from "@ngx-translate/core"; +import { MatTableDataSource } from "@angular/material/table"; @Component({ templateUrl: "./movies-grid.component.html", @@ -16,7 +20,7 @@ import { RequestFilterType } from "../../models/RequestFilterType"; styleUrls: ["./movies-grid.component.scss"] }) export class MoviesGridComponent implements OnInit, AfterViewInit { - public dataSource: IMovieRequests[] = []; + public dataSource: MatTableDataSource; public resultsLength: number; public isLoadingResults = true; public displayedColumns: string[] = ['title', 'requestedUser.requestedBy', 'status', 'requestStatus','requestedDate', 'actions']; @@ -25,6 +29,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { public defaultSort: string = "requestedDate"; public defaultOrder: string = "desc"; public currentFilter: RequestFilterType = RequestFilterType.All; + public selection = new SelectionModel(true, []); public RequestFilter = RequestFilterType; @@ -40,13 +45,17 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { @ViewChild(MatSort) sort: MatSort; constructor(private requestService: RequestServiceV2, private ref: ChangeDetectorRef, - private auth: AuthService, private storageService: StorageService) { + private auth: AuthService, private storageService: StorageService, + private requestServiceV1: RequestService, private notification: NotificationService, + private translateService: TranslateService) { } - - public ngOnInit() { - this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); + public ngOnInit() { + this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); + if (this.isAdmin) { + this.displayedColumns.unshift('select'); + } const defaultCount = this.storageService.get(this.storageKeyGridCount); const defaultSort = this.storageService.get(this.storageKey); const defaultOrder = this.storageService.get(this.storageKeyOrder); @@ -96,7 +105,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { this.isLoadingResults = false; return observableOf([]); }) - ).subscribe(data => this.dataSource = data); + ).subscribe(data => this.dataSource = new MatTableDataSource(data)); } public loadData(): Observable> { @@ -117,9 +126,9 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { public openOptions(request: IMovieRequests) { const filter = () => { - this.dataSource = this.dataSource.filter((req) => { - return req.id !== request.id; - }) + this.dataSource.data = this.dataSource.data.filter((req) => { + return req.id !== request.id; + }); }; const onChange = () => { @@ -133,4 +142,56 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { this.currentFilter = type; this.ngAfterViewInit(); } -} + + public isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + public masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.dataSource.data.forEach(row => this.selection.select(row)); + } + + public async bulkDelete() { + if (this.selection.isEmpty()) { + return; + } + let tasks = new Array(); + this.selection.selected.forEach((selected) => { + tasks.push(this.requestServiceV1.removeMovieRequestAsync(selected.id)); + }); + + await Promise.all(tasks); + + this.notification.success(this.translateService.instant('Requests.RequestPanel.Deleted')) + this.selection.clear(); + this.ngAfterViewInit(); + } + + public bulkApprove() { + if (this.selection.isEmpty()) { + return; + } + let tasks = new Array>(); + this.selection.selected.forEach((selected) => { + tasks.push(this.requestServiceV1.approveMovie({ id: selected.id })); + }); + + this.isLoadingResults = true; + forkJoin(tasks).subscribe((result: IRequestEngineResult[]) => { + this.isLoadingResults = false; + const failed = result.filter(x => !x.result); + if(failed.length > 0) { + this.notification.error("Some requests failed to approve: " + failed[0].errorMessage); + this.selection.clear(); + return; + } + this.notification.success(this.translateService.instant('Requests.RequestPanel.Approved')); + this.selection.clear(); + this.ngAfterViewInit(); + }) + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss b/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss index 1c6a9f617..78fd3f91f 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss +++ b/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss @@ -62,4 +62,11 @@ ::ng-deep table.requests button{ margin:5px; -} \ No newline at end of file +} + +::ng-deep .floating-fab { + position: fixed; + right: 3%; + bottom: 6%; + z-index: 10; +} diff --git a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html index 2750fe756..6ade3261d 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html +++ b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html @@ -74,7 +74,7 @@ Episode Batch Size @@ -185,4 +185,4 @@ - \ No newline at end of file + diff --git a/src/Ombi/ClientApp/src/app/wizard/welcome/welcome.component.html b/src/Ombi/ClientApp/src/app/wizard/welcome/welcome.component.html index 6f46803c4..c1189051c 100644 --- a/src/Ombi/ClientApp/src/app/wizard/welcome/welcome.component.html +++ b/src/Ombi/ClientApp/src/app/wizard/welcome/welcome.component.html @@ -1,6 +1,5 @@ 
-
diff --git a/src/Ombi/ClientApp/src/styles/shared.scss b/src/Ombi/ClientApp/src/styles/shared.scss index 2dd922173..7184d96fb 100644 --- a/src/Ombi/ClientApp/src/styles/shared.scss +++ b/src/Ombi/ClientApp/src/styles/shared.scss @@ -137,4 +137,4 @@ table { ::ng-deep .mat-form-field.mat-focused .mat-form-field-label { color: $accent; -} +} \ No newline at end of file diff --git a/src/Ombi/Controllers/V2/SystemController.cs b/src/Ombi/Controllers/V2/SystemController.cs index d172eb37a..6b76d053d 100644 --- a/src/Ombi/Controllers/V2/SystemController.cs +++ b/src/Ombi/Controllers/V2/SystemController.cs @@ -25,7 +25,7 @@ namespace Ombi.Controllers.V2 [HttpGet("news")] public async Task GetNews() { - var result = await _client.GetAsync("https://raw.githubusercontent.com/tidusjar/Ombi.News/main/README.md"); + var result = await _client.GetAsync("https://raw.githubusercontent.com/Ombi-app/Ombi.News/main/README.md"); var content = await result.Content.ReadAsStringAsync(); var md = Markdown.ToHtml(content); return Ok(md); diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index c75a74a99..0efb3fe88 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -180,7 +180,9 @@ "RequestPanel": { "Delete":"Delete Request", "Approve":"Approve Request", - "ChangeAvailability":"Mark Available" + "ChangeAvailability":"Mark Available", + "Deleted": "Successfully deleted selected items", + "Approved": "Successfully approved selected items" } }, "Issues": {