* Moved the calculation for time to read to the backend. Tweaked some logic around showing est time to complete. * Added debug logging to help pinpoint a duplicate issue in Kavita. * More combination logic is error checked in a special way for Robbie to reproduce an issue. * Migrated chapter detail card to use backend for time calculation. Ensure we take all chapters into account for volume time calcs * Tweaked messaging for some critical logs to include file * Ensure pages count uses comma separated number * Moved Hangfire annotations to interface level. Adjusted word count service to always recalculate when user requests via analyze series files.
299 lines
No EOL
14 KiB
HTML
299 lines
No EOL
14 KiB
HTML
<div class="row g-0 mt-2 mb-2">
|
|
<app-read-more [text]="seriesSummary" [maxLength]="250"></app-read-more>
|
|
</div>
|
|
|
|
<!-- This first row will have random information about the series-->
|
|
<div class="row g-0 mb-4 mt-3">
|
|
<ng-container *ngIf="seriesMetadata.ageRating">
|
|
<div class="col-lg-1 col-md-4 col-sm-4 col-4 mb-3">
|
|
<app-icon-and-title [clickable]="true" fontClasses="fas fa-eye" (click)="goTo(FilterQueryParam.AgeRating, seriesMetadata.ageRating)" title="Age Rating">
|
|
{{metadataService.getAgeRating(this.seriesMetadata.ageRating) | async}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
</ng-container>
|
|
<ng-container *ngIf="series">
|
|
<ng-container *ngIf="seriesMetadata.releaseYear > 0">
|
|
<div class="col-lg-1 col-md-4 col-sm-4 col-4 mb-3">
|
|
<app-icon-and-title [clickable]="false" fontClasses="fa-regular fa-calendar" title="Release Year">
|
|
{{seriesMetadata.releaseYear}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
</ng-container>
|
|
|
|
<ng-container *ngIf="seriesMetadata.language !== null">
|
|
<div class="col-lg-1 col-md-4 col-sm-4 col-4 mb-3">
|
|
<app-icon-and-title [clickable]="true" fontClasses="fas fa-language" (click)="goTo(FilterQueryParam.Languages, seriesMetadata.language)" title="Language">
|
|
{{seriesMetadata.language | defaultValue:'en' | languageName | async}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
</ng-container>
|
|
|
|
<ng-container>
|
|
<div class="d-none d-md-block col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="true" fontClasses="fa-solid fa-hourglass-empty" (click)="goTo(FilterQueryParam.PublicationStatus, seriesMetadata.publicationStatus)" title="Publication Status ({{seriesMetadata.maxCount}} / {{seriesMetadata.totalCount}})">
|
|
{{seriesMetadata.publicationStatus | publicationStatus}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
<div class="vr m-2 d-none d-lg-block"></div>
|
|
</ng-container>
|
|
|
|
<ng-container>
|
|
<div class="d-none d-md-block col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="true" [fontClasses]="'fa ' + utilityService.mangaFormatIcon(series.format)" (click)="goTo(FilterQueryParam.Format, series.format)" title="Format">
|
|
{{utilityService.mangaFormat(series.format)}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
</ng-container>
|
|
|
|
<ng-container *ngIf="series.latestReadDate && series.latestReadDate !== '' && (series.latestReadDate | date: 'shortDate') !== '1/1/01'">
|
|
<div class="d-none d-md-block col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="false" fontClasses="fa-regular fa-clock" title="Last Read">
|
|
{{series.latestReadDate | date:'shortDate'}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
</ng-container>
|
|
|
|
|
|
<ng-container *ngIf="series.format === MangaFormat.EPUB; else showPages">
|
|
<ng-container *ngIf="series.wordCount > 0">
|
|
<div class="col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="false" fontClasses="fa-solid fa-book-open">
|
|
{{series.wordCount | compactNumber}} Words
|
|
</app-icon-and-title>
|
|
</div>
|
|
</ng-container>
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
</ng-container>
|
|
<ng-template #showPages>
|
|
<div class="d-none d-md-block col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="false" fontClasses="fa-regular fa-file-lines">
|
|
{{series.pages | number:''}} Pages
|
|
</app-icon-and-title>
|
|
</div>
|
|
</ng-template>
|
|
|
|
|
|
|
|
<ng-container *ngIf="series.format === MangaFormat.EPUB && series.wordCount > 0 || series.format !== MangaFormat.EPUB">
|
|
<div class="col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="false" fontClasses="fa-regular fa-clock">
|
|
{{readingTime.minHours}}{{readingTime.maxHours !== readingTime.minHours ? ('-' + readingTime.maxHours) : ''}} Hour{{readingTime.minHours > 1 ? 's' : ''}}
|
|
</app-icon-and-title>
|
|
</div>
|
|
</ng-container>
|
|
|
|
|
|
<ng-container *ngIf="readingTimeLeft.hasProgress && readingTimeLeft.avgHours !== 0 ">
|
|
<div class="vr d-none d-lg-block m-2"></div>
|
|
<div class="col-lg-1 col-md-4 col-sm-4 col-4 mb-2">
|
|
<app-icon-and-title [clickable]="false" fontClasses="fa-solid fa-clock">
|
|
~{{readingTimeLeft.avgHours}} Hour{{readingTimeLeft.avgHours > 1 ? 's' : ''}} Left
|
|
</app-icon-and-title>
|
|
</div>
|
|
</ng-container>
|
|
|
|
|
|
</ng-container>
|
|
</div>
|
|
|
|
<div class="row g-0" *ngIf="seriesMetadata.genres && seriesMetadata.genres.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Genres</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.genres">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Genres, item.id)" [selectionMode]="TagBadgeCursor.Clickable">{{item.title}}</app-tag-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
<div class="row g-0" *ngIf="seriesMetadata.tags && seriesMetadata.tags.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Tags</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.tags">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Tags, item.id)" [selectionMode]="TagBadgeCursor.Clickable">{{item.title}}</app-tag-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.collectionTags && seriesMetadata.collectionTags.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Collections</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.collectionTags">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-tag-badge a11y-click="13,32" class="col-auto" routerLink="/collections/{{item.id}}" [selectionMode]="TagBadgeCursor.Clickable">
|
|
{{item.title}}
|
|
</app-tag-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
<div class="row g-0 mt-1" *ngIf="readingLists && readingLists.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Reading Lists</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="readingLists">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-tag-badge a11y-click="13,32" class="col-auto" routerLink="/lists/{{item.id}}" [selectionMode]="TagBadgeCursor.Clickable">
|
|
<!-- TODO: Build a promoted badge code -->
|
|
<span *ngIf="item.promoted">
|
|
<i class="fa fa-angle-double-up" aria-hidden="true"></i>
|
|
<span class="visually-hidden">(promoted)</span>
|
|
</span>
|
|
{{item.title}}
|
|
</app-tag-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.writers && seriesMetadata.writers.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Writers/Authors</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.writers">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Writers, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" id="extended-series-metadata">
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.coverArtists && seriesMetadata.coverArtists.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Cover Artists</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.coverArtists">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.CoverArtists, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.characters && seriesMetadata.characters.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Characters</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.characters">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Character, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.colorists && seriesMetadata.colorists.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Colorists</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.colorists">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Colorist, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.editors && seriesMetadata.editors.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Editors</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.editors">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Editor, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.inkers && seriesMetadata.inkers.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Inkers</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.inkers">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Inker, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.letterers && seriesMetadata.letterers.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Letterers</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.letterers">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Letterer, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.translators && seriesMetadata.translators.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Translators</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.translators">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Translator, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.pencillers && seriesMetadata.pencillers.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Pencillers</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.pencillers">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Penciller, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0 mt-1" *ngIf="seriesMetadata.publishers && seriesMetadata.publishers.length > 0">
|
|
<div class="col-md-4">
|
|
<h5>Publishers</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<app-badge-expander [items]="seriesMetadata.publishers">
|
|
<ng-template #badgeExpanderItem let-item let-position="idx">
|
|
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Publisher, item.id)" [person]="item"></app-person-badge>
|
|
</ng-template>
|
|
</app-badge-expander>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-0">
|
|
<hr class="col mt-3" *ngIf="hasExtendedProperites" >
|
|
<a [class.hidden]="hasExtendedProperites" *ngIf="hasExtendedProperites"
|
|
class="col col-md-auto align-self-end read-more-link" (click)="toggleView()">
|
|
<i aria-hidden="true" class="fa fa-caret-{{isCollapsed ? 'down' : 'up'}} me-1" aria-controls="extended-series-metadata"></i>
|
|
See {{isCollapsed ? 'More' : 'Less'}}
|
|
</a>
|
|
</div> |