Ensure we deconstruct volumes when they consist of multiple items

This commit is contained in:
Joseph Milazzo 2026-03-08 14:49:19 -05:00
parent e292c697a0
commit b4d004e402
4 changed files with 49 additions and 25 deletions

View File

@ -221,19 +221,6 @@ public class PersonController(
return Ok(await unitOfWork.PersonRepository.GetSeriesKnownFor(personId, UserId));
}
/// <summary>
/// Return external Series the person is an artist/author of. Requires Admin due to age rating restrictions.
/// </summary>
/// <param name="personId"></param>
/// <returns></returns>
[PersonAccess]
[KPlus]
[Authorize(PolicyGroups.AdminPolicy)]
[HttpGet("external-series")]
public async Task<ActionResult<IEnumerable<ExternalSeriesDto>>> GetExternalSeries(int personId)
{
return Ok(await unitOfWork.ExternalSeriesMetadataRepository.GetExternalSeriesForPerson(personId, UserId));
}
/// <summary>
/// Returns all individual chapters by role. Limited to 20 results.

View File

@ -272,15 +272,14 @@ export class AccountService {
this.stopRefreshTokenTimer();
if (user) {
if (!isSameUser) {
this.messageHub.stopHubConnection();
this.messageHub.createHubConnection(user);
this.licenseService.checkForValidLicense().subscribe();
}
if (user.token) {
this.startRefreshTokenTimer();
}
if (user && !isSameUser) {
this.messageHub.stopHubConnection();
this.messageHub.createHubConnection(user);
this.licenseService.checkForValidLicense().subscribe();
}
if (user?.token) {
this.startRefreshTokenTimer();
}
}
@ -447,7 +446,10 @@ export class AccountService {
refreshAccount(): Observable<null | User> {
if (!this._currentUser()) return of(null);
return this.httpClient.get<User>(this.baseUrl + 'account/refresh-account').pipe(map((user: User) => {
if (user) this.setCurrentUser({ ...user });
if (user) {
this.setCurrentUser({...user});
this.licenseService.checkForValidLicense().subscribe();
}
return user;
}));
}

View File

@ -134,7 +134,7 @@ export class DashboardComponent {
}
});
this.licenseService.checkForValidLicense()
this.licenseService.hasAnyLicense()
.pipe(
filter((hasLic: boolean) => hasLic),
switchMap(_ => this.scrobblingService.hasTokenExpired(ScrobbleProvider.AniList)),

View File

@ -249,7 +249,7 @@ export class DownloadService {
this.downloadSeries(entity as Series);
break;
case 'volume':
this.enqueueSingle(entity as Volume, 'volume', '', libraryId, seriesId);
this.downloadVolume(entity as Volume, libraryId, seriesId);
break;
case 'chapter':
this.enqueueSingle(entity as Chapter, 'chapter', '', libraryId, seriesId);
@ -489,6 +489,41 @@ export class DownloadService {
return this.httpClient.post<Record<number, number>>(this.baseUrl + 'download/bulk-series-size', seriesIds);
}
private downloadVolumeSize(volumeId: number) {
return this.httpClient.get<number>(this.baseUrl + 'download/volume-size?volumeId=' + volumeId);
}
private downloadChapterSize(chapterId: number) {
return this.httpClient.get<number>(this.baseUrl + 'download/chapter-size?chapterId=' + chapterId);
}
private downloadVolume(volume: Volume, libraryId: number, seriesId: number) {
this.debugLog('downloadVolume()', volume.minNumber);
// Volumes can be either a bunch of chapters or just 1
if (volume.chapters.length === 1) {
this.enqueueSingle(volume, 'volume', '', libraryId, seriesId);
return;
}
this.debugLog(`downloadVolume() decomposed into ${volume.chapters.length} items`);
const items = volume.chapters.map(c => ({ entity: c as Chapter, entityType: 'chapter' as const }));
const userPrefs = this.accountService.userPreferences();
if (userPrefs?.promptForDownloadSize && items.length > 0) {
// Single size call for the whole series, single confirm dialog
this.downloadVolumeSize(volume.id).pipe(
switchMap(async size => this.confirmSize(size, 'volume')),
filter(confirmed => confirmed),
takeUntilDestroyed(this.destroyRef)
).subscribe(() => this.enqueueItems(items, '', libraryId, seriesId));
} else {
this.enqueueItems(items, '', libraryId, seriesId);
}
}
private downloadSeries(series: Series) {
this.debugLog('downloadSeries()', series.name);
this.seriesService.getSeriesDetail(series.id).pipe(