Misc Bugfixes (#2216)
* Folder watching will now appropriately ignore changes that occur in blacklisted folders. * Fixed up recently updated from dashboard not opening a pre-sorted page. There were issues with how encoding and decoding was done plus missing code. * Fixed up all streams from Dashboard opening to correctly filtered pages. * All search linking now works. * Rating tooltip and stars are bigger on mobile. * A bit of cleanup * Added day breakdown to user stats page. * Removed Token checks before we write events to the history table for scrobbling. Refactored so series holds will prevent writing events for reviews, ratings, etc. * Fixed a potential bug where series name could be taken from a chapter that isn't the first ordered (very unlikely) for epubs. Fixed a bug where Volume 1.5 could be selected for series-level metadata over Volume 1. * Optimized the license check code so that users without any license entered would still take advantage of the cache layer. * Sped up an API that checks if the library allows scrobbling * Cleaned up the mobile CSS a bit for filters.
This commit is contained in:
parent
ef3e76e3e5
commit
c84a3294e9
30 changed files with 324 additions and 246 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, Router} from '@angular/router';
|
||||
import {ActivatedRouteSnapshot, Params, Router} from '@angular/router';
|
||||
import {Pagination} from 'src/app/_models/pagination';
|
||||
import {SortField, SortOptions} from 'src/app/_models/metadata/series-filter';
|
||||
import {MetadataService} from "../../_services/metadata.service";
|
||||
|
|
@ -9,50 +9,17 @@ import {FilterCombination} from "../../_models/metadata/v2/filter-combination";
|
|||
import {FilterField} from "../../_models/metadata/v2/filter-field";
|
||||
import {FilterComparison} from "../../_models/metadata/v2/filter-comparison";
|
||||
|
||||
/**
|
||||
* Used to pass state between the filter and the url
|
||||
*/
|
||||
export enum FilterQueryParam {
|
||||
Format = 'format',
|
||||
Genres = 'genres',
|
||||
AgeRating = 'ageRating',
|
||||
PublicationStatus = 'publicationStatus',
|
||||
Tags = 'tags',
|
||||
Languages = 'languages',
|
||||
CollectionTags = 'collectionTags',
|
||||
Libraries = 'libraries',
|
||||
Writers = 'writers',
|
||||
Artists = 'artists',
|
||||
Character = 'character',
|
||||
Colorist = 'colorist',
|
||||
CoverArtists = 'coverArtists',
|
||||
Editor = 'editor',
|
||||
Inker = 'inker',
|
||||
Letterer = 'letterer',
|
||||
Penciller = 'penciller',
|
||||
Publisher = 'publisher',
|
||||
Translator = 'translators',
|
||||
ReadStatus = 'readStatus',
|
||||
SortBy = 'sortBy',
|
||||
Rating = 'rating',
|
||||
Name = 'name',
|
||||
/**
|
||||
* This is a pagination control
|
||||
*/
|
||||
Page = 'page',
|
||||
/**
|
||||
* Special case for the UI. Does not trigger filtering
|
||||
*/
|
||||
None = 'none'
|
||||
}
|
||||
const sortOptionsKey = 'sortOptions=';
|
||||
const statementsKey = 'stmts=';
|
||||
const limitToKey = 'limitTo=';
|
||||
const combinationKey = 'combination=';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FilterUtilitiesService {
|
||||
|
||||
constructor(private metadataService: MetadataService, private router: Router) {
|
||||
}
|
||||
constructor(private metadataService: MetadataService, private router: Router) {}
|
||||
|
||||
applyFilter(page: Array<any>, filter: FilterField, comparison: FilterComparison, value: string) {
|
||||
const dto: SeriesFilterV2 = {
|
||||
|
|
@ -61,8 +28,14 @@ export class FilterUtilitiesService {
|
|||
limitTo: 0
|
||||
};
|
||||
|
||||
console.log('applying filter: ', this.urlFromFilterV2(page.join('/') + '?', dto))
|
||||
this.router.navigateByUrl(this.urlFromFilterV2(page.join('/') + '?', dto));
|
||||
const url = this.urlFromFilterV2(page.join('/') + '?', dto);
|
||||
return this.router.navigateByUrl(url);
|
||||
}
|
||||
|
||||
applyFilterWithParams(page: Array<any>, filter: SeriesFilterV2, extraParams: Params) {
|
||||
let url = this.urlFromFilterV2(page.join('/') + '?', filter);
|
||||
url += Object.keys(extraParams).map(k => `&${k}=${extraParams[k]}`).join('');
|
||||
return this.router.navigateByUrl(url, extraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,7 +57,7 @@ export class FilterUtilitiesService {
|
|||
|
||||
/**
|
||||
* Will fetch current page from route if present
|
||||
* @param ActivatedRouteSnapshot to fetch page from. Must be from component else may get stale data
|
||||
* @param snapshot to fetch page from. Must be from component else may get stale data
|
||||
* @param itemsPerPage If you want pagination, pass non-zero number
|
||||
* @returns A default pagination object
|
||||
*/
|
||||
|
|
@ -107,10 +80,10 @@ export class FilterUtilitiesService {
|
|||
|
||||
encodeSeriesFilter(filter: SeriesFilterV2) {
|
||||
const encodedStatements = this.encodeFilterStatements(filter.statements);
|
||||
const encodedSortOptions = filter.sortOptions ? `sortOptions=${this.encodeSortOptions(filter.sortOptions)}` : '';
|
||||
const encodedLimitTo = `limitTo=${filter.limitTo}`;
|
||||
const encodedSortOptions = filter.sortOptions ? `${sortOptionsKey}${this.encodeSortOptions(filter.sortOptions)}` : '';
|
||||
const encodedLimitTo = `${limitToKey}${filter.limitTo}`;
|
||||
|
||||
return `${this.encodeName(filter.name)}stmts=${encodedStatements}&${encodedSortOptions}&${encodedLimitTo}&combination=${filter.combination}`;
|
||||
return `${this.encodeName(filter.name)}${encodedStatements}&${encodedSortOptions}&${encodedLimitTo}&${combinationKey}${filter.combination}`;
|
||||
}
|
||||
|
||||
encodeName(name: string | undefined) {
|
||||
|
|
@ -124,7 +97,8 @@ export class FilterUtilitiesService {
|
|||
}
|
||||
|
||||
encodeFilterStatements(statements: Array<FilterStatement>) {
|
||||
return encodeURIComponent(statements.map(statement => {
|
||||
if (statements.length === 0) return '';
|
||||
return statementsKey + encodeURIComponent(statements.map(statement => {
|
||||
const encodedComparison = `comparison=${statement.comparison}`;
|
||||
const encodedField = `field=${statement.field}`;
|
||||
const encodedValue = `value=${encodeURIComponent(statement.value)}`;
|
||||
|
|
@ -144,19 +118,23 @@ export class FilterUtilitiesService {
|
|||
}
|
||||
|
||||
const fullUrl = window.location.href.split('?')[1];
|
||||
const stmtsStartIndex = fullUrl.indexOf('stmts=');
|
||||
let endIndex = fullUrl.indexOf('&sortOptions=');
|
||||
const stmtsStartIndex = fullUrl.indexOf(statementsKey);
|
||||
let endIndex = fullUrl.indexOf('&' + sortOptionsKey);
|
||||
if (endIndex < 0) {
|
||||
endIndex = fullUrl.indexOf('&limitTo=');
|
||||
endIndex = fullUrl.indexOf('&' + limitToKey);
|
||||
}
|
||||
|
||||
if (stmtsStartIndex !== -1 && endIndex !== -1) {
|
||||
const stmtsEncoded = fullUrl.substring(stmtsStartIndex + 6, endIndex);
|
||||
if (stmtsStartIndex !== -1 || endIndex !== -1) {
|
||||
// +1 is for the =
|
||||
const stmtsEncoded = fullUrl.substring(stmtsStartIndex + statementsKey.length, endIndex);
|
||||
filter.statements = this.decodeFilterStatements(stmtsEncoded);
|
||||
}
|
||||
|
||||
if (queryParams.sortOptions) {
|
||||
const sortOptions = this.decodeSortOptions(queryParams.sortOptions);
|
||||
const optionsStartIndex = fullUrl.indexOf('&' + sortOptionsKey);
|
||||
const endIndex = fullUrl.indexOf('&' + limitToKey);
|
||||
const sortOptionsEncoded = fullUrl.substring(optionsStartIndex + sortOptionsKey.length + 1, endIndex);
|
||||
const sortOptions = this.decodeSortOptions(sortOptionsEncoded);
|
||||
if (sortOptions) {
|
||||
filter.sortOptions = sortOptions;
|
||||
}
|
||||
|
|
@ -174,7 +152,7 @@ export class FilterUtilitiesService {
|
|||
}
|
||||
|
||||
decodeSortOptions(encodedSortOptions: string): SortOptions | null {
|
||||
const parts = encodedSortOptions.split('&');
|
||||
const parts = decodeURIComponent(encodedSortOptions).split('&');
|
||||
const sortFieldPart = parts.find(part => part.startsWith('sortField='));
|
||||
const isAscendingPart = parts.find(part => part.startsWith('isAscending='));
|
||||
|
||||
|
|
@ -188,7 +166,7 @@ export class FilterUtilitiesService {
|
|||
}
|
||||
|
||||
decodeFilterStatements(encodedStatements: string): FilterStatement[] {
|
||||
const statementStrings = decodeURIComponent(encodedStatements).split(','); // I don't think this will wrk
|
||||
const statementStrings = decodeURIComponent(encodedStatements).split(',');
|
||||
return statementStrings.map(statementString => {
|
||||
const parts = statementString.split('&');
|
||||
if (parts === null || parts.length < 3) return null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue