Hooked up the ability to get average rating on Comic series.

This commit is contained in:
Joseph Milazzo 2025-03-17 12:35:54 -05:00
parent 579cd847af
commit 585df0b5d3
15 changed files with 47 additions and 71 deletions

View file

@ -65,7 +65,7 @@ public class ExternalMetadataService : IExternalMetadataService
private readonly ICoverDbService _coverDbService;
private readonly TimeSpan _externalSeriesMetadataCache = TimeSpan.FromDays(30);
public static readonly HashSet<LibraryType> NonEligibleLibraryTypes =
[LibraryType.Comic, LibraryType.Book, LibraryType.Image, LibraryType.ComicVine];
[LibraryType.Comic, LibraryType.Book, LibraryType.Image];
private readonly SeriesDetailPlusDto _defaultReturn = new()
{
Series = null,
@ -487,6 +487,7 @@ public class ExternalMetadataService : IExternalMetadataService
if (result.MalId.HasValue) externalSeriesMetadata.MalId = result.MalId.Value;
if (result.AniListId.HasValue) externalSeriesMetadata.AniListId = result.AniListId.Value;
//TODO: if (result.CbrId.HasValue) externalSeriesMetadata.CbrId = result.CbrId.Value;
// If there is metadata and the user has metadata download turned on
var madeMetadataModification = false;
@ -609,7 +610,7 @@ public class ExternalMetadataService : IExternalMetadataService
madeModification = await UpdateRelationships(series, settings, externalMetadata.Relations, defaultAdmin) || madeModification;
madeModification = await UpdateCoverImage(series, settings, externalMetadata) || madeModification;
// TODO: Hook in individual issue metadata
madeModification = await UpdateChapters(series, settings, externalMetadata) || madeModification;
return madeModification;
}
@ -1031,6 +1032,16 @@ public class ExternalMetadataService : IExternalMetadataService
return false;
}
private async Task<bool> UpdateChapters(Series series, MetadataSettingsDto settings,
ExternalSeriesDetailDto externalMetadata)
{
if (externalMetadata.PlusMediaFormat != PlusMediaFormat.Comic) return false;
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(1);
return false;
}
private async Task<bool> UpdateCoverImage(Series series, MetadataSettingsDto settings, ExternalSeriesDetailDto externalMetadata)
{
if (!settings.EnableCoverImage) return false;

View file

@ -37,7 +37,9 @@ public enum ScrobbleProvider
Kavita = 0,
AniList = 1,
Mal = 2,
Cbr = 3
[Obsolete]
GoogleBooks = 3,
Cbr = 4
}
public interface IScrobblingService

View file

@ -17,6 +17,8 @@ export class ProviderImagePipe implements PipeTransform {
return `assets/images/ExternalServices/GoogleBooks${large ? '-lg' : ''}.png`;
case ScrobbleProvider.Kavita:
return `assets/images/logo-${large ? '64' : '32'}.png`;
case ScrobbleProvider.Cbr:
return `assets/images/ExternalServices/ComicBookRoundup.png`;
}
}

View file

@ -1,23 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import {ScrobbleProvider} from "../_services/scrobbling.service";
@Pipe({
name: 'providerName',
standalone: true
})
export class ProviderNamePipe implements PipeTransform {
transform(value: ScrobbleProvider): string {
switch (value) {
case ScrobbleProvider.AniList:
return 'AniList';
case ScrobbleProvider.Mal:
return 'MAL';
case ScrobbleProvider.Kavita:
return 'Kavita';
case ScrobbleProvider.GoogleBooks:
return 'Google Books';
}
}
}

View file

@ -12,6 +12,7 @@ export class ScrobbleProviderNamePipe implements PipeTransform {
case ScrobbleProvider.AniList: return 'AniList';
case ScrobbleProvider.Mal: return 'MAL';
case ScrobbleProvider.Kavita: return 'Kavita';
case ScrobbleProvider.Cbr: return 'Comicbook Roundup';
case ScrobbleProvider.GoogleBooks: return 'Google Books';
}
}

View file

@ -12,9 +12,10 @@ import {UtilityService} from "../shared/_services/utility.service";
export enum ScrobbleProvider {
Kavita = 0,
AniList= 1,
AniList = 1,
Mal = 2,
GoogleBooks = 3
GoogleBooks = 3,
Cbr = 4
}
@Injectable({

View file

@ -4,15 +4,12 @@ import {
Component,
DestroyRef,
EventEmitter,
HostListener,
inject,
OnInit
} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {Router} from '@angular/router';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {map, of} from 'rxjs';
import {Observable} from 'rxjs/internal/Observable';
import {EditCollectionTagsComponent} from 'src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component';
import {UserCollection} from 'src/app/_models/collection-tag';
import {JumpKey} from 'src/app/_models/jumpbar/jump-key';
@ -32,15 +29,11 @@ import {
import {translate, TranslocoDirective, TranslocoService} from "@jsverse/transloco";
import {ToastrService} from "ngx-toastr";
import {ScrobbleProvider} from "../../../_services/scrobbling.service";
import {ProviderImagePipe} from "../../../_pipes/provider-image.pipe";
import {ProviderNamePipe} from "../../../_pipes/provider-name.pipe";
import {CollectionOwnerComponent} from "../collection-owner/collection-owner.component";
import {User} from "../../../_models/user";
import {BulkOperationsComponent} from "../../../cards/bulk-operations/bulk-operations.component";
import {BulkSelectionService} from "../../../cards/bulk-selection.service";
import {SeriesCardComponent} from "../../../cards/series-card/series-card.component";
import {ActionService} from "../../../_services/action.service";
import {KEY_CODES} from "../../../shared/_services/utility.service";
import {WikiLink} from "../../../_models/wiki";
import {DefaultModalOptions} from "../../../_models/default-modal-options";
@ -51,7 +44,8 @@ import {DefaultModalOptions} from "../../../_models/default-modal-options";
styleUrls: ['./all-collections.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [SideNavCompanionBarComponent, CardDetailLayoutComponent, CardItemComponent, AsyncPipe, DecimalPipe, TranslocoDirective, ProviderImagePipe, ProviderNamePipe, CollectionOwnerComponent, BulkOperationsComponent, SeriesCardComponent]
imports: [SideNavCompanionBarComponent, CardDetailLayoutComponent, CardItemComponent, AsyncPipe, DecimalPipe,
TranslocoDirective, CollectionOwnerComponent, BulkOperationsComponent]
})
export class AllCollectionsComponent implements OnInit {

View file

@ -32,7 +32,7 @@
<div class="under-image">
<app-image [imageUrl]="collectionTag.source | providerImage"
width="16px" height="16px"
[ngbTooltip]="collectionTag.source | providerName" tabindex="0"></app-image>
[ngbTooltip]="collectionTag.source | scrobbleProviderName" tabindex="0"></app-image>
<span class="ms-2 me-2">{{t('sync-progress', {title: series.length + ' / ' + collectionTag.totalSourceCount})}}</span>
<i class="fa-solid fa-question-circle" aria-hidden="true" [ngbTooltip]="t('last-sync', {date: collectionTag.lastSyncUtc | date: 'short' | defaultDate })"></i>
</div>

View file

@ -1,4 +1,4 @@
import {AsyncPipe, DatePipe, DOCUMENT, NgStyle} from '@angular/common';
import {AsyncPipe, DatePipe, DOCUMENT} from '@angular/common';
import {
AfterContentChecked,
ChangeDetectionStrategy,
@ -7,7 +7,6 @@ import {
DestroyRef,
ElementRef,
EventEmitter,
HostListener,
inject,
Inject,
OnInit,
@ -22,7 +21,7 @@ import {BulkSelectionService} from 'src/app/cards/bulk-selection.service';
import {EditCollectionTagsComponent} from 'src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component';
import {FilterSettings} from 'src/app/metadata-filter/filter-settings';
import {FilterUtilitiesService} from 'src/app/shared/_services/filter-utilities.service';
import {Breakpoint, KEY_CODES, UtilityService} from 'src/app/shared/_services/utility.service';
import {Breakpoint, UtilityService} from 'src/app/shared/_services/utility.service';
import {UserCollection} from 'src/app/_models/collection-tag';
import {SeriesAddedToCollectionEvent} from 'src/app/_models/events/series-added-to-collection-event';
import {JumpKey} from 'src/app/_models/jumpbar/jump-key';
@ -55,16 +54,13 @@ import {SeriesFilterV2} from "../../../_models/metadata/v2/series-filter-v2";
import {AccountService} from "../../../_services/account.service";
import {User} from "../../../_models/user";
import {ScrobbleProvider} from "../../../_services/scrobbling.service";
import {SafeHtmlPipe} from "../../../_pipes/safe-html.pipe";
import {TranslocoDatePipe} from "@jsverse/transloco-locale";
import {DefaultDatePipe} from "../../../_pipes/default-date.pipe";
import {ProviderImagePipe} from "../../../_pipes/provider-image.pipe";
import {ProviderNamePipe} from "../../../_pipes/provider-name.pipe";
import {PromotedIconComponent} from "../../../shared/_components/promoted-icon/promoted-icon.component";
import {
SmartCollectionDrawerComponent
} from "../../../_single-module/smart-collection-drawer/smart-collection-drawer.component";
import {DefaultModalOptions} from "../../../_models/default-modal-options";
import {ScrobbleProviderNamePipe} from "../../../_pipes/scrobble-provider-name.pipe";
@Component({
selector: 'app-collection-detail',
@ -72,10 +68,9 @@ import {DefaultModalOptions} from "../../../_models/default-modal-options";
styleUrls: ['./collection-detail.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [SideNavCompanionBarComponent, CardActionablesComponent, NgStyle, ImageComponent, ReadMoreComponent,
imports: [SideNavCompanionBarComponent, CardActionablesComponent, ImageComponent, ReadMoreComponent,
BulkOperationsComponent, CardDetailLayoutComponent, SeriesCardComponent, TranslocoDirective, NgbTooltip,
SafeHtmlPipe, TranslocoDatePipe, DatePipe, DefaultDatePipe, ProviderImagePipe, ProviderNamePipe, AsyncPipe,
PromotedIconComponent]
DatePipe, DefaultDatePipe, ProviderImagePipe, AsyncPipe, ScrobbleProviderNamePipe]
})
export class CollectionDetailComponent implements OnInit, AfterContentChecked {

View file

@ -6,8 +6,8 @@
{{t('collection-via-label')}}
<app-image [imageUrl]="collection.source | providerImage"
width="16px" height="16px"
[ngbTooltip]="collection.source | providerName"
[attr.aria-label]="collection.source | providerName"></app-image>
[ngbTooltip]="collection.source | scrobbleProviderName"
[attr.aria-label]="collection.source | scrobbleProviderName"></app-image>
}
</div>
}

View file

@ -1,25 +1,24 @@
import {ChangeDetectionStrategy, Component, inject, Input} from '@angular/core';
import {ScrobbleProvider} from "../../../_services/scrobbling.service";
import {ProviderImagePipe} from "../../../_pipes/provider-image.pipe";
import {ProviderNamePipe} from "../../../_pipes/provider-name.pipe";
import {UserCollection} from "../../../_models/collection-tag";
import {TranslocoDirective} from "@jsverse/transloco";
import {AsyncPipe, JsonPipe} from "@angular/common";
import {AsyncPipe} from "@angular/common";
import {AccountService} from "../../../_services/account.service";
import {ImageComponent} from "../../../shared/image/image.component";
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
import {ScrobbleProviderNamePipe} from "../../../_pipes/scrobble-provider-name.pipe";
@Component({
selector: 'app-collection-owner',
standalone: true,
imports: [
ProviderImagePipe,
ProviderNamePipe,
TranslocoDirective,
AsyncPipe,
JsonPipe,
ImageComponent,
NgbTooltip
NgbTooltip,
ScrobbleProviderNamePipe
],
templateUrl: './collection-owner.component.html',
styleUrl: './collection-owner.component.scss',

View file

@ -1,4 +1,4 @@
import {AsyncPipe, DOCUMENT, NgOptimizedImage, NgTemplateOutlet} from '@angular/common';
import {AsyncPipe, DOCUMENT} from '@angular/common';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
@ -17,7 +17,7 @@ import {Chapter} from 'src/app/_models/chapter';
import {UserCollection} from 'src/app/_models/collection-tag';
import {Library} from 'src/app/_models/library/library';
import {MangaFile} from 'src/app/_models/manga-file';
import {Person, PersonRole} from 'src/app/_models/metadata/person';
import {Person} from 'src/app/_models/metadata/person';
import {ReadingList} from 'src/app/_models/reading-list';
import {SearchResult} from 'src/app/_models/search/search-result';
import {SearchResultGroup} from 'src/app/_models/search/search-result-group';
@ -28,40 +28,34 @@ import {ScrollService} from 'src/app/_services/scroll.service';
import {SearchService} from 'src/app/_services/search.service';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {SentenceCasePipe} from '../../../_pipes/sentence-case.pipe';
import {PersonRolePipe} from '../../../_pipes/person-role.pipe';
import {NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle, NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {EventsWidgetComponent} from '../events-widget/events-widget.component';
import {SeriesFormatComponent} from '../../../shared/series-format/series-format.component';
import {ImageComponent} from '../../../shared/image/image.component';
import {GroupedTypeaheadComponent, SearchEvent} from '../grouped-typeahead/grouped-typeahead.component';
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {TranslocoDirective} from "@jsverse/transloco";
import {FilterUtilitiesService} from "../../../shared/_services/filter-utilities.service";
import {FilterStatement} from "../../../_models/metadata/v2/filter-statement";
import {FilterField} from "../../../_models/metadata/v2/filter-field";
import {FilterComparison} from "../../../_models/metadata/v2/filter-comparison";
import {BookmarkSearchResult} from "../../../_models/search/bookmark-search-result";
import {ScrobbleProvider} from "../../../_services/scrobbling.service";
import {ProviderImagePipe} from "../../../_pipes/provider-image.pipe";
import {ProviderNamePipe} from "../../../_pipes/provider-name.pipe";
import {CollectionOwnerComponent} from "../../../collections/_components/collection-owner/collection-owner.component";
import {PromotedIconComponent} from "../../../shared/_components/promoted-icon/promoted-icon.component";
import {SettingsTabId} from "../../../sidenav/preference-nav/preference-nav.component";
import {Breakpoint, UtilityService} from "../../../shared/_services/utility.service";
import {WikiLink} from "../../../_models/wiki";
import {
GenericListModalComponent
} from "../../../statistics/_components/_modals/generic-list-modal/generic-list-modal.component";
import {NavLinkModalComponent} from "../nav-link-modal/nav-link-modal.component";
@Component({
selector: 'app-nav-header',
templateUrl: './nav-header.component.html',
styleUrls: ['./nav-header.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [RouterLink, RouterLinkActive, NgOptimizedImage, GroupedTypeaheadComponent, ImageComponent,
imports: [RouterLink, RouterLinkActive, GroupedTypeaheadComponent, ImageComponent,
SeriesFormatComponent, EventsWidgetComponent, NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgbDropdownItem,
AsyncPipe, PersonRolePipe, SentenceCasePipe, TranslocoDirective, ProviderImagePipe, ProviderNamePipe, CollectionOwnerComponent, PromotedIconComponent, NgTemplateOutlet]
AsyncPipe, SentenceCasePipe, TranslocoDirective, CollectionOwnerComponent, PromotedIconComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NavHeaderComponent implements OnInit {

View file

@ -17,7 +17,7 @@
@for (rating of ratings; track rating.provider + rating.averageScore) {
<div class="col-auto custom-col clickable" [ngbPopover]="externalPopContent" [popoverContext]="{rating: rating}"
[popoverTitle]="rating.provider | providerName" popoverClass="sm-popover">
[popoverTitle]="rating.provider | scrobbleProviderName" popoverClass="sm-popover">
<span class="badge rounded-pill me-1">
<img class="me-1" [ngSrc]="rating.provider | providerImage:true" width="24" height="24" alt="" aria-hidden="true">
{{rating.averageScore}}%

View file

@ -13,7 +13,6 @@ import {ProviderImagePipe} from "../../../_pipes/provider-image.pipe";
import {NgbModal, NgbPopover} from "@ng-bootstrap/ng-bootstrap";
import {LoadingComponent} from "../../../shared/loading/loading.component";
import {LibraryType} from "../../../_models/library/library";
import {ProviderNamePipe} from "../../../_pipes/provider-name.pipe";
import {NgxStarsModule} from "ngx-stars";
import {ThemeService} from "../../../_services/theme.service";
import {Breakpoint, UtilityService} from "../../../shared/_services/utility.service";
@ -23,12 +22,13 @@ import {SafeHtmlPipe} from "../../../_pipes/safe-html.pipe";
import {ImageService} from "../../../_services/image.service";
import {AsyncPipe, NgOptimizedImage, NgTemplateOutlet} from "@angular/common";
import {RatingModalComponent} from "../rating-modal/rating-modal.component";
import {ScrobbleProviderNamePipe} from "../../../_pipes/scrobble-provider-name.pipe";
@Component({
selector: 'app-external-rating',
standalone: true,
imports: [ProviderImagePipe, NgbPopover, LoadingComponent, ProviderNamePipe, NgxStarsModule, ImageComponent,
TranslocoDirective, SafeHtmlPipe, NgOptimizedImage, AsyncPipe, NgTemplateOutlet],
imports: [ScrobbleProviderNamePipe, NgbPopover, LoadingComponent, NgxStarsModule, ImageComponent,
TranslocoDirective, SafeHtmlPipe, NgOptimizedImage, AsyncPipe, NgTemplateOutlet, ProviderImagePipe],
templateUrl: './external-rating.component.html',
styleUrls: ['./external-rating.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB