Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions komga-webui/src/components/dialogs/EditBooksDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@
</template>

<script lang="ts">
import {groupAuthorsByRole} from '@/functions/authors'
import {buildManyAuthorsByRole, groupAuthorsByRole} from '@/functions/authors'
import {authorRoles} from '@/types/author-roles'
import Vue from 'vue'
import {helpers, requiredIf} from 'vuelidate/lib/validators'
Expand Down Expand Up @@ -482,6 +482,7 @@ export default Vue.extend({
authorSearch: [],
authorSearchResults: [] as string[],
tagsAvailable: [] as string[],
isMultiBookAuthorDirty: false, // workaround for author consistency in bulk mode
}
},
props: {
Expand Down Expand Up @@ -627,11 +628,27 @@ export default Vue.extend({
if (Array.isArray(books) && books.length === 0) return
else if (this.$_.isEmpty(books)) return
if (Array.isArray(books) && books.length > 0) {
this.form.authors = {}
this.form.authors = buildManyAuthorsByRole(books)
this.form.links = []
const currentRoles = this.$_.keys(this.form.authors)
// Use authorRoles from computed value, so we can extend if needed
const ignoreRoles = this.authorRoles.map(r => r.value)
.filter((r) => !this.customRoles.includes(r)) // remove old custom roles
.filter((r) => !authorRoles.includes(r)) // remove native roles
this.customRoles = currentRoles.filter((r) => !ignoreRoles.includes(r)) // add new custom roles

let forceAuthorLock = false
for (const book of books) {
const bookAuthor = groupAuthorsByRole(book.metadata.authors)
if (!this.$_.isEqual(bookAuthor, this.form.authors)) {
this.isMultiBookAuthorDirty = true
forceAuthorLock = true
break
}
}

const authorsLock = this.$_.uniq(books.map(x => x.metadata.authorsLock))
this.form.authorsLock = authorsLock.length > 1 ? false : authorsLock[0]
this.form.authorsLock = authorsLock.length > 1 ? false : authorsLock[0] || forceAuthorLock

this.form.tags = []

Expand Down Expand Up @@ -665,7 +682,7 @@ export default Vue.extend({
tagsLock: this.form.tagsLock,
}

if (this.$v.form?.authors?.$dirty) {
if (this.$v.form?.authors?.$dirty || this.isMultiBookAuthorDirty) {
this.$_.merge(metadata, {
authors: this.$_.keys(this.form.authors).flatMap((role: string) =>
this.$_.get(this.form.authors, role).map((name: string) => ({name: name, role: role})),
Expand Down
19 changes: 15 additions & 4 deletions komga-webui/src/components/dialogs/EditOneshotDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ import {isMatch} from 'date-fns'
import IsbnVerify from '@saekitominaga/isbn-verify'
import {debounce} from 'lodash'
import {authorRoles} from '@/types/author-roles'
import {groupAuthorsByRole} from '@/functions/authors'
import {buildManyAuthorsByRole, groupAuthorsByRole} from '@/functions/authors'

const tags = require('language-tags')

Expand Down Expand Up @@ -644,6 +644,7 @@ export default Vue.extend({
genresAvailable: [] as string[],
tagsAvailable: [] as string[],
sharingLabelsAvailable: [] as string[],
isMultiBookAuthorDirty: false, // workaround for author consistency in bulk mode
}
},
props: {
Expand Down Expand Up @@ -880,10 +881,20 @@ export default Vue.extend({
this.form.series.sharingLabelsLock = sharingLabelsLock.length > 1 ? false : sharingLabelsLock[0]

this.form.book.links = []
this.form.book.authors = {}
this.form.book.authors = buildManyAuthorsByRole(oneshots.map(x => x.book))

let forceAuthorLock = false
for (const oneshot of oneshots) {
const bookAuthor = groupAuthorsByRole(oneshot.book.metadata.authors)
if (!this.$_.isEqual(bookAuthor, this.form.book.authors)) {
this.isMultiBookAuthorDirty = true
forceAuthorLock = true
break
}
}

const authorsLock = this.$_.uniq(oneshots.map(x => x.book.metadata.authorsLock))
this.form.book.authorsLock = authorsLock.length > 1 ? false : authorsLock[0]
this.form.book.authorsLock = authorsLock.length > 1 ? false : authorsLock[0] || forceAuthorLock
} else {
this.form.series.genres = []
this.form.series.sharingLabels = []
Expand Down Expand Up @@ -925,7 +936,7 @@ export default Vue.extend({
tagsLock: this.form.book.tagsLock,
}

if (this.$v.form?.book?.authors?.$dirty) {
if (this.$v.form?.book?.authors?.$dirty || this.isMultiBookAuthorDirty) {
this.$_.merge(metadataBook, {
authors: this.$_.keys(this.form.book.authors).flatMap((role: string) =>
this.$_.get(this.form.book.authors, role).map((name: string) => ({name: name, role: role})),
Expand Down
24 changes: 21 additions & 3 deletions komga-webui/src/functions/authors.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import {groupBy, mapValues} from 'lodash'
import {AuthorDto} from '@/types/komga-books'
import {flatMap, groupBy, intersection, mapValues, reduce, uniq} from 'lodash'
import {AuthorDto, BookDto} from '@/types/komga-books'

type AuthorsByRole = {[role: string]: string[]}

// return an object where keys are roles, and values are string[]
export function groupAuthorsByRole (authors: AuthorDto[]): any {
export function groupAuthorsByRole (authors: AuthorDto[]): AuthorsByRole {
return mapValues(groupBy(authors, 'role'),
authors => authors.map((author: AuthorDto) => author.name))
}

// create an object where keys are roles and values are arrays of authors
// we're using intersection to only include authors that are present on all books of each roles
export function buildManyAuthorsByRole(books: BookDto[]): AuthorsByRole {
const allAuthorsByRoles = books.map(book => groupAuthorsByRole(book.metadata.authors))
const roleKeys = uniq(flatMap(allAuthorsByRoles, Object.keys))
return reduce(roleKeys, (acc: {[key: string]: string[]}, key) => {
const values = allAuthorsByRoles.map(authorsByRole => authorsByRole[key] || [])
const intersect = intersection(...values.filter(arr => arr.length > 0))

if (intersect.length > 0) {
acc[key] = intersect
}
return acc
}, {})
}
Loading