mirror of
https://github.com/theotherp/nzbhydra2.git
synced 2026-02-06 11:17:18 +00:00
Serialize longs as strings to prevent precision loss (d'oh!)
This commit is contained in:
parent
a38d813b6e
commit
7caae7324f
@ -1,9 +1,6 @@
|
||||
import {Component, EventEmitter, Input, Output} from "@angular/core";
|
||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {take} from "rxjs/operators";
|
||||
import {Downloader, DownloaderService, SearchResultDl} from "../../services/downloader.service";
|
||||
import {Downloader, DownloaderService} from "../../services/downloader.service";
|
||||
import {SearchResultWebTO} from "../../services/search.service";
|
||||
import {CategorySelectionModalComponent} from "../category-selection-modal/category-selection-modal.component";
|
||||
|
||||
|
||||
@Component({
|
||||
@ -15,18 +12,15 @@ import {CategorySelectionModalComponent} from "../category-selection-modal/categ
|
||||
export class AddableNzbComponent {
|
||||
@Input() searchResult!: SearchResultWebTO;
|
||||
@Input() downloader!: Downloader;
|
||||
@Input() alwaysAsk: boolean = false;
|
||||
@Output() downloadComplete = new EventEmitter<{ successful: boolean, message?: string }>();
|
||||
|
||||
cssClass: string = "";
|
||||
isDownloading: boolean = false;
|
||||
|
||||
constructor(
|
||||
private downloaderService: DownloaderService,
|
||||
private modalService: NgbModal
|
||||
private downloaderService: DownloaderService
|
||||
) {
|
||||
this.updateCssClass();
|
||||
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
@ -57,55 +51,26 @@ export class AddableNzbComponent {
|
||||
}
|
||||
|
||||
this.isDownloading = true;
|
||||
const originalClass = this.cssClass;
|
||||
this.cssClass = "nzb-spinning";
|
||||
|
||||
// If alwaysAsk or no default category, open modal
|
||||
if (this.alwaysAsk || !this.downloader.defaultCategory) {
|
||||
this.downloaderService.getCategories(this.downloader).pipe(take(1)).subscribe({
|
||||
next: (categories) => {
|
||||
const modalRef = this.modalService.open(CategorySelectionModalComponent, {size: "sm"});
|
||||
modalRef.componentInstance.categories = categories;
|
||||
modalRef.result.then((selectedCategory: string) => {
|
||||
this.doDownload(this.searchResult, selectedCategory);
|
||||
}, () => {
|
||||
this.cssClass = originalClass;
|
||||
this.isDownloading = false;
|
||||
});
|
||||
},
|
||||
error: () => {
|
||||
this.cssClass = this.buildCssClass("-error");
|
||||
this.downloadComplete.emit({
|
||||
successful: false,
|
||||
message: "Failed to load categories from downloader."
|
||||
});
|
||||
this.isDownloading = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.doDownload(this.searchResult, this.downloader.defaultCategory);
|
||||
}
|
||||
this.doDownload();
|
||||
}
|
||||
|
||||
private buildSearchResultDl(searchResult: SearchResultWebTO): SearchResultDl {
|
||||
return {
|
||||
searchResultId: this.searchResult.searchResultId,
|
||||
originalCategory: this.searchResult.originalCategory,
|
||||
mappedCategory: this.searchResult.category
|
||||
};
|
||||
}
|
||||
|
||||
private buildCssClass(postfix: string) {
|
||||
let baseClass = this.getCssClass(this.downloader.downloaderType);
|
||||
return baseClass + " " + baseClass + postfix;
|
||||
}
|
||||
|
||||
private doDownload(searchResult: SearchResultWebTO, category: string) {
|
||||
this.downloaderService.download(this.downloader, [this.buildSearchResultDl(searchResult)], category)
|
||||
private doDownload() {
|
||||
const searchResultDl = {
|
||||
searchResultId: this.searchResult.searchResultId,
|
||||
originalCategory: this.searchResult.originalCategory,
|
||||
mappedCategory: this.searchResult.category
|
||||
};
|
||||
this.downloaderService.download(this.downloader, [searchResultDl])
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
if (
|
||||
response.successful && response.addedIds?.includes(searchResult.searchResultId)
|
||||
response.successful && response.addedIds?.includes(searchResultDl.searchResultId)
|
||||
) {
|
||||
this.cssClass = this.buildCssClass("-success");
|
||||
this.downloadComplete.emit({successful: true});
|
||||
@ -115,12 +80,20 @@ export class AddableNzbComponent {
|
||||
}
|
||||
this.isDownloading = false;
|
||||
},
|
||||
error: () => {
|
||||
error: (error) => {
|
||||
this.cssClass = this.buildCssClass("-error");
|
||||
this.downloadComplete.emit({
|
||||
successful: false,
|
||||
message: "An unexpected error occurred while trying to contact NZBHydra or add the NZB."
|
||||
});
|
||||
if (error.message === "Category selection cancelled") {
|
||||
this.cssClass = this.getCssClass(this.downloader.downloaderType);
|
||||
this.downloadComplete.emit({
|
||||
successful: false,
|
||||
message: "Download cancelled by user."
|
||||
});
|
||||
} else {
|
||||
this.downloadComplete.emit({
|
||||
successful: false,
|
||||
message: "An unexpected error occurred while trying to contact NZBHydra or add the NZB."
|
||||
});
|
||||
}
|
||||
this.isDownloading = false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -263,7 +263,6 @@
|
||||
*ngFor="let downloader of enabledDownloaders"
|
||||
[searchResult]="groupedResult.result"
|
||||
[downloader]="downloader"
|
||||
[alwaysAsk]="false"
|
||||
(downloadComplete)="onDownloadComplete($event)">
|
||||
</app-addable-nzb>
|
||||
</div>
|
||||
|
||||
@ -83,7 +83,7 @@ export class SearchResultsComponent implements OnInit {
|
||||
groupedResults: GroupedResult[] = [];
|
||||
|
||||
// Selection state
|
||||
selectedResultsIds: Set<number> = new Set();
|
||||
selectedResultsIds: Set<string> = new Set();
|
||||
lastSelectedIndex: number = -1;
|
||||
lastSelectionAction: "select" | "unselect" | null = null;
|
||||
showIndexerStatuses = false;
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Injectable} from "@angular/core";
|
||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {Observable, throwError} from "rxjs";
|
||||
import {catchError, map} from "rxjs/operators";
|
||||
import {catchError, map, switchMap, take} from "rxjs/operators";
|
||||
import {CategorySelectionModalComponent} from "../components/category-selection-modal/category-selection-modal.component";
|
||||
import {ConfigService} from "./config.service";
|
||||
|
||||
export interface Downloader {
|
||||
@ -13,7 +15,7 @@ export interface Downloader {
|
||||
}
|
||||
|
||||
export interface SearchResultDl {
|
||||
searchResultId: number;
|
||||
searchResultId: string;
|
||||
originalCategory: string;
|
||||
mappedCategory: string;
|
||||
}
|
||||
@ -26,7 +28,7 @@ export interface DownloadRequest {
|
||||
|
||||
export interface DownloadResponse {
|
||||
successful: boolean;
|
||||
addedIds?: number[];
|
||||
addedIds?: string[];
|
||||
message?: string;
|
||||
}
|
||||
|
||||
@ -36,7 +38,8 @@ export interface DownloadResponse {
|
||||
export class DownloaderService {
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private configService: ConfigService
|
||||
private configService: ConfigService,
|
||||
private modalService: NgbModal
|
||||
) {
|
||||
}
|
||||
|
||||
@ -55,9 +58,36 @@ export class DownloaderService {
|
||||
|
||||
/**
|
||||
* Download NZB to specified downloader
|
||||
* Opens category selection modal if no default category is set
|
||||
*/
|
||||
download(downloader: Downloader, searchResults: SearchResultDl[], category: string): Observable<DownloadResponse> {
|
||||
return this.sendNzbAddCommand(downloader, searchResults, category);
|
||||
download(downloader: Downloader, searchResults: SearchResultDl[]): Observable<DownloadResponse> {
|
||||
let category = downloader.defaultCategory;
|
||||
if (!category) {
|
||||
return this.getCategories(downloader).pipe(
|
||||
take(1),
|
||||
switchMap(categories => {
|
||||
const modalRef = this.modalService.open(CategorySelectionModalComponent, {size: "sm"});
|
||||
modalRef.componentInstance.categories = categories;
|
||||
|
||||
return new Observable<DownloadResponse>(observer => {
|
||||
modalRef.result.then((selectedCategory: string) => {
|
||||
this.sendNzbAddCommand(downloader, searchResults, selectedCategory).subscribe({
|
||||
next: (response) => observer.next(response),
|
||||
error: (error) => observer.error(error)
|
||||
});
|
||||
}, () => {
|
||||
observer.error(new Error("Category selection cancelled"));
|
||||
});
|
||||
});
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error("Error fetching categories:", error);
|
||||
return throwError(() => error);
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return this.sendNzbAddCommand(downloader, searchResults, category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -54,7 +54,7 @@ export interface IndexerSearchMetaData {
|
||||
}
|
||||
|
||||
export interface SearchResultWebTO {
|
||||
searchResultId: number;
|
||||
searchResultId: string;
|
||||
title: string;
|
||||
link: string;
|
||||
guid: string;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package org.nzbhydra.downloading;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -23,7 +25,7 @@ public class AddFilesRequest {
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SearchResult {
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long searchResultId;
|
||||
private String originalCategory;
|
||||
private String mappedCategory;
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package org.nzbhydra.downloading;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -32,6 +34,8 @@ public class FileZipResponse {
|
||||
private boolean successful;
|
||||
private String zipFilepath;
|
||||
private String message;
|
||||
@JsonSerialize(contentUsing = ToStringSerializer.class)
|
||||
private Collection<Long> addedIds;
|
||||
@JsonSerialize(contentUsing = ToStringSerializer.class)
|
||||
private Collection<Long> missedIds;
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package org.nzbhydra.downloading.downloaders;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -33,6 +35,8 @@ public class AddNzbsResponse {
|
||||
*/
|
||||
private boolean successful;
|
||||
private String message;
|
||||
@JsonSerialize(contentUsing = ToStringSerializer.class)
|
||||
private Collection<Long> addedIds;
|
||||
@JsonSerialize(contentUsing = ToStringSerializer.class)
|
||||
private Collection<Long> missedIds;
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package org.nzbhydra.downloading.downloaders;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.google.common.collect.Iterables;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@ -49,8 +51,9 @@ public class DownloaderStatus {
|
||||
private int elementsInQueue;
|
||||
private String downloadingTitle;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private long downloadingTitleRemainingSizeKilobytes;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private long downloadingTitleRemainingTimeSeconds;
|
||||
|
||||
private int downloadingTitlePercentFinished;
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package org.nzbhydra.searching.dtoseventsenums;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import org.nzbhydra.springnative.ReflectionMarker;
|
||||
|
||||
@ -31,6 +33,7 @@ public class IndexerSearchMetaData {
|
||||
private int numberOfAvailableResults;
|
||||
private int numberOfFoundResults;
|
||||
private int offset;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private long responseTime;
|
||||
private boolean totalResultsKnown;
|
||||
private boolean wasSuccessful;
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package org.nzbhydra.searching.dtoseventsenums;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -53,7 +55,7 @@ public class SearchRequestParameters {
|
||||
|
||||
private Integer season;
|
||||
private String episode;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private long searchRequestId; //Sent by the GUI to identify this search when getting updates for it
|
||||
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package org.nzbhydra.searching.dtoseventsenums;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -27,7 +29,6 @@ import lombok.extern.jackson.Jacksonized;
|
||||
@Jacksonized
|
||||
public class SearchResultWebTO {
|
||||
|
||||
|
||||
private String age;
|
||||
private Boolean age_precise;
|
||||
private String category;
|
||||
@ -36,6 +37,7 @@ public class SearchResultWebTO {
|
||||
private Integer comments;
|
||||
private String details_link;
|
||||
private String downloadType;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long epoch;
|
||||
private Integer files;
|
||||
private Integer grabs;
|
||||
@ -49,8 +51,10 @@ public class SearchResultWebTO {
|
||||
private String link;
|
||||
private String originalCategory;
|
||||
private String poster;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long searchResultId;
|
||||
private String source;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long size;
|
||||
private String title;
|
||||
private String season;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user