mirror of
https://github.com/gotson/komga.git
synced 2025-12-21 07:56:57 +01:00
feat(api): revamp search authors
return authors with their role can be refined by library or collection or series
This commit is contained in:
parent
0c5a7447f8
commit
f549067a8a
7 changed files with 141 additions and 28 deletions
|
|
@ -333,7 +333,7 @@ export default Vue.extend({
|
|||
deep: true,
|
||||
async handler(val: []) {
|
||||
const index = val.findIndex(x => x !== null)
|
||||
this.authorSearchResults = await this.$komgaReferential.getAuthors(val[index])
|
||||
this.authorSearchResults = await this.$komgaReferential.getAuthorsNames(val[index])
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {AxiosInstance} from 'axios'
|
||||
import {AuthorDto} from "@/types/komga-books";
|
||||
|
||||
const qs = require('qs')
|
||||
const tags = require('language-tags')
|
||||
|
|
@ -6,19 +7,21 @@ const tags = require('language-tags')
|
|||
export default class KomgaReferentialService {
|
||||
private http: AxiosInstance
|
||||
|
||||
constructor (http: AxiosInstance) {
|
||||
constructor(http: AxiosInstance) {
|
||||
this.http = http
|
||||
}
|
||||
|
||||
async getAuthors (search?: string): Promise<string[]> {
|
||||
async getAuthors(search?: string, libraryId?: string, collectionId?: string, seriesId?: string): Promise<AuthorDto[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (search) {
|
||||
params.search = search
|
||||
}
|
||||
if (search) params.search = search
|
||||
if (libraryId) params.library_id = libraryId
|
||||
if (collectionId) params.collection_id = collectionId
|
||||
if (seriesId) params.series_id = seriesId
|
||||
|
||||
return (await this.http.get('/api/v1/authors', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve authors'
|
||||
|
|
@ -29,7 +32,26 @@ export default class KomgaReferentialService {
|
|||
}
|
||||
}
|
||||
|
||||
async getGenres (libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
async getAuthorsNames(search?: string): Promise<string[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (search) {
|
||||
params.search = search
|
||||
}
|
||||
return (await this.http.get('/api/v1/authors/names', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve authors names'
|
||||
if (e.response.data.message) {
|
||||
msg += `: ${e.response.data.message}`
|
||||
}
|
||||
throw new Error(msg)
|
||||
}
|
||||
}
|
||||
|
||||
async getGenres(libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (libraryId) params.library_id = libraryId
|
||||
|
|
@ -37,7 +59,7 @@ export default class KomgaReferentialService {
|
|||
|
||||
return (await this.http.get('/api/v1/genres', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve genres'
|
||||
|
|
@ -48,7 +70,7 @@ export default class KomgaReferentialService {
|
|||
}
|
||||
}
|
||||
|
||||
async getTags (libraryId?: string, seriesId?: string, collectionId?: string): Promise<string[]> {
|
||||
async getTags(libraryId?: string, seriesId?: string, collectionId?: string): Promise<string[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (libraryId) params.library_id = libraryId
|
||||
|
|
@ -57,7 +79,7 @@ export default class KomgaReferentialService {
|
|||
|
||||
return (await this.http.get('/api/v1/tags', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve tags'
|
||||
|
|
@ -68,7 +90,7 @@ export default class KomgaReferentialService {
|
|||
}
|
||||
}
|
||||
|
||||
async getPublishers (libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
async getPublishers(libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (libraryId) params.library_id = libraryId
|
||||
|
|
@ -76,7 +98,7 @@ export default class KomgaReferentialService {
|
|||
|
||||
return (await this.http.get('/api/v1/publishers', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve publishers'
|
||||
|
|
@ -87,7 +109,7 @@ export default class KomgaReferentialService {
|
|||
}
|
||||
}
|
||||
|
||||
async getAgeRatings (libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
async getAgeRatings(libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (libraryId) params.library_id = libraryId
|
||||
|
|
@ -95,7 +117,7 @@ export default class KomgaReferentialService {
|
|||
|
||||
return (await this.http.get('/api/v1/age-ratings', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve age ratings'
|
||||
|
|
@ -106,7 +128,7 @@ export default class KomgaReferentialService {
|
|||
}
|
||||
}
|
||||
|
||||
async getSeriesReleaseDates (libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
async getSeriesReleaseDates(libraryId?: string, collectionId?: string): Promise<string[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (libraryId) params.library_id = libraryId
|
||||
|
|
@ -114,7 +136,7 @@ export default class KomgaReferentialService {
|
|||
|
||||
return (await this.http.get('/api/v1/series/release-dates', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to retrieve series release dates'
|
||||
|
|
@ -125,7 +147,7 @@ export default class KomgaReferentialService {
|
|||
}
|
||||
}
|
||||
|
||||
async getLanguages (libraryId?: string, collectionId?: string): Promise<NameValue[]> {
|
||||
async getLanguages(libraryId?: string, collectionId?: string): Promise<NameValue[]> {
|
||||
try {
|
||||
const params = {} as any
|
||||
if (libraryId) params.library_id = libraryId
|
||||
|
|
@ -133,14 +155,14 @@ export default class KomgaReferentialService {
|
|||
|
||||
const data = (await this.http.get('/api/v1/languages', {
|
||||
params: params,
|
||||
paramsSerializer: params => qs.stringify(params, { indices: false }),
|
||||
paramsSerializer: params => qs.stringify(params, {indices: false}),
|
||||
})).data
|
||||
const ret = [] as NameValue[]
|
||||
for (const code of data) {
|
||||
const tag = tags(code)
|
||||
if (tag.valid()) {
|
||||
const name = tag.language().descriptions()[0] + ` (${code})`
|
||||
ret.push({ name: name, value: code })
|
||||
ret.push({name: name, value: code})
|
||||
}
|
||||
}
|
||||
return ret
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
package org.gotson.komga.domain.persistence
|
||||
|
||||
import org.gotson.komga.domain.model.Author
|
||||
import java.time.LocalDate
|
||||
|
||||
interface ReferentialRepository {
|
||||
fun findAuthorsByName(search: String): List<String>
|
||||
fun findAuthorsByName(search: String): List<Author>
|
||||
fun findAuthorsByNameAndLibrary(search: String, libraryId: String): List<Author>
|
||||
fun findAuthorsByNameAndCollection(search: String, collectionId: String): List<Author>
|
||||
fun findAuthorsByNameAndSeries(search: String, seriesId: String): List<Author>
|
||||
fun findAuthorsNamesByName(search: String): List<String>
|
||||
fun findAuthorsRoles(): List<String>
|
||||
|
||||
fun findAllGenres(): Set<String>
|
||||
fun findAllGenresByLibrary(libraryId: String): Set<String>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package org.gotson.komga.infrastructure.jooq
|
||||
|
||||
import org.gotson.komga.domain.model.Author
|
||||
import org.gotson.komga.domain.persistence.ReferentialRepository
|
||||
import org.gotson.komga.jooq.Tables
|
||||
import org.gotson.komga.jooq.tables.records.BookMetadataAggregationAuthorRecord
|
||||
import org.gotson.komga.jooq.tables.records.BookMetadataAuthorRecord
|
||||
import org.jooq.DSLContext
|
||||
import org.jooq.impl.DSL.lower
|
||||
import org.jooq.impl.DSL.select
|
||||
|
|
@ -16,6 +19,7 @@ class ReferentialDao(
|
|||
private val a = Tables.BOOK_METADATA_AUTHOR
|
||||
private val sd = Tables.SERIES_METADATA
|
||||
private val bma = Tables.BOOK_METADATA_AGGREGATION
|
||||
private val bmaa = Tables.BOOK_METADATA_AGGREGATION_AUTHOR
|
||||
private val s = Tables.SERIES
|
||||
private val b = Tables.BOOK
|
||||
private val g = Tables.SERIES_METADATA_GENRE
|
||||
|
|
@ -23,13 +27,56 @@ class ReferentialDao(
|
|||
private val st = Tables.SERIES_METADATA_TAG
|
||||
private val cs = Tables.COLLECTION_SERIES
|
||||
|
||||
override fun findAuthorsByName(search: String): List<String> =
|
||||
override fun findAuthorsByName(search: String): List<Author> =
|
||||
dsl.selectDistinct(a.NAME, a.ROLE)
|
||||
.from(a)
|
||||
.where(a.NAME.containsIgnoreCase(search))
|
||||
.orderBy(a.NAME, a.ROLE)
|
||||
.fetchInto(a)
|
||||
.map { it.toDomain() }
|
||||
|
||||
override fun findAuthorsByNameAndLibrary(search: String, libraryId: String): List<Author> =
|
||||
dsl.selectDistinct(bmaa.NAME, bmaa.ROLE)
|
||||
.from(bmaa)
|
||||
.leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID))
|
||||
.where(bmaa.NAME.containsIgnoreCase(search))
|
||||
.and(s.LIBRARY_ID.eq(libraryId))
|
||||
.orderBy(bmaa.NAME, bmaa.ROLE)
|
||||
.fetchInto(bmaa)
|
||||
.map { it.toDomain() }
|
||||
|
||||
override fun findAuthorsByNameAndCollection(search: String, collectionId: String): List<Author> =
|
||||
dsl.selectDistinct(bmaa.NAME, bmaa.ROLE)
|
||||
.from(bmaa)
|
||||
.leftJoin(cs).on(bmaa.SERIES_ID.eq(cs.SERIES_ID))
|
||||
.where(bmaa.NAME.containsIgnoreCase(search))
|
||||
.and(cs.COLLECTION_ID.eq(collectionId))
|
||||
.orderBy(bmaa.NAME, bmaa.ROLE)
|
||||
.fetchInto(bmaa)
|
||||
.map { it.toDomain() }
|
||||
|
||||
override fun findAuthorsByNameAndSeries(search: String, seriesId: String): List<Author> =
|
||||
dsl.selectDistinct(bmaa.NAME, bmaa.ROLE)
|
||||
.from(bmaa)
|
||||
.where(bmaa.NAME.containsIgnoreCase(search))
|
||||
.and(bmaa.SERIES_ID.eq(seriesId))
|
||||
.orderBy(bmaa.NAME, bmaa.ROLE)
|
||||
.fetchInto(bmaa)
|
||||
.map { it.toDomain() }
|
||||
|
||||
override fun findAuthorsNamesByName(search: String): List<String> =
|
||||
dsl.selectDistinct(a.NAME)
|
||||
.from(a)
|
||||
.where(a.NAME.containsIgnoreCase(search))
|
||||
.orderBy(a.NAME)
|
||||
.fetch(a.NAME)
|
||||
|
||||
override fun findAuthorsRoles(): List<String> =
|
||||
dsl.selectDistinct(a.ROLE)
|
||||
.from(a)
|
||||
.orderBy(a.ROLE)
|
||||
.fetch(a.ROLE)
|
||||
|
||||
override fun findAllGenres(): Set<String> =
|
||||
dsl.selectDistinct(g.GENRE)
|
||||
.from(g)
|
||||
|
|
@ -191,4 +238,16 @@ class ReferentialDao(
|
|||
.and(bma.RELEASE_DATE.isNotNull)
|
||||
.orderBy(bma.RELEASE_DATE.desc())
|
||||
.fetchSet(bma.RELEASE_DATE)
|
||||
|
||||
private fun BookMetadataAuthorRecord.toDomain(): Author =
|
||||
Author(
|
||||
name = name,
|
||||
role = role
|
||||
)
|
||||
|
||||
private fun BookMetadataAggregationAuthorRecord.toDomain(): Author =
|
||||
Author(
|
||||
name = name,
|
||||
role = role
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package org.gotson.komga.interfaces.rest
|
||||
|
||||
import org.gotson.komga.domain.persistence.ReferentialRepository
|
||||
import org.gotson.komga.interfaces.rest.dto.AuthorDto
|
||||
import org.gotson.komga.interfaces.rest.dto.toDto
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
|
|
@ -15,9 +17,28 @@ class ReferentialController(
|
|||
|
||||
@GetMapping("/authors")
|
||||
fun getAuthors(
|
||||
@RequestParam(name = "search", defaultValue = "") search: String,
|
||||
@RequestParam(name = "library_id", required = false) libraryId: String?,
|
||||
@RequestParam(name = "collection_id", required = false) collectionId: String?,
|
||||
@RequestParam(name = "series_id", required = false) seriesId: String?,
|
||||
): List<AuthorDto> =
|
||||
|
||||
when {
|
||||
libraryId != null -> referentialRepository.findAuthorsByNameAndLibrary(search, libraryId)
|
||||
collectionId != null -> referentialRepository.findAuthorsByNameAndCollection(search, collectionId)
|
||||
seriesId != null -> referentialRepository.findAuthorsByNameAndSeries(search, seriesId)
|
||||
else -> referentialRepository.findAuthorsByName(search)
|
||||
}.map { it.toDto() }
|
||||
|
||||
@GetMapping("/authors/names")
|
||||
fun getAuthorsNames(
|
||||
@RequestParam(name = "search", defaultValue = "") search: String
|
||||
): List<String> =
|
||||
referentialRepository.findAuthorsByName(search)
|
||||
referentialRepository.findAuthorsNamesByName(search)
|
||||
|
||||
@GetMapping("/authors/roles")
|
||||
fun getAuthorsRoles(): List<String> =
|
||||
referentialRepository.findAuthorsRoles()
|
||||
|
||||
@GetMapping("/genres")
|
||||
fun getGenres(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package org.gotson.komga.interfaces.rest.dto
|
||||
|
||||
import org.gotson.komga.domain.model.Author
|
||||
|
||||
data class AuthorDto(
|
||||
val name: String,
|
||||
val role: String
|
||||
)
|
||||
|
||||
fun Author.toDto() = AuthorDto(name, role)
|
||||
|
|
@ -59,11 +59,6 @@ data class BookMetadataDto(
|
|||
val lastModified: LocalDateTime
|
||||
)
|
||||
|
||||
data class AuthorDto(
|
||||
val name: String,
|
||||
val role: String
|
||||
)
|
||||
|
||||
data class ReadProgressDto(
|
||||
val page: Int,
|
||||
val completed: Boolean,
|
||||
|
|
|
|||
Loading…
Reference in a new issue