Compare commits

...

10 Commits

Author SHA1 Message Date
advplyr 52a3bc224a Version bump v2.12.3 2024-08-09 16:59:19 -05:00
advplyr 54d67e5216 Merge pull request #3245 from ic1415/LibraryItemController
Update LibraryItemController.js
2024-08-09 16:48:30 -05:00
advplyr b55d8250cc Download log update 2024-08-09 16:48:21 -05:00
advplyr 3a1e9abd68 Revert unicode sqlite extension to fix db corruption #3241 2024-08-09 16:41:52 -05:00
advplyr c5ba40a178 Merge pull request #3262 from Vito0912/lang/add-year-in-review
lang/localization of "year in review"
2024-08-09 16:26:12 -05:00
Vito0912 f0c6dccadb Added max width 2024-08-09 19:24:43 +02:00
Vito0912 e701d1ab6a now? please 2024-08-09 18:59:20 +02:00
Vito0912 e10c8093c9 localization of year in review 2024-08-09 18:48:29 +02:00
ic1415 ef2d736b20 Update LibraryItemController.js
standardizing log messages for all download cases
2024-08-05 16:33:56 -04:00
ic1415 f3a453be20 Update LibraryItemController.js
Additional logging for single file downloads coming from download function
2024-08-05 16:19:28 -04:00
13 changed files with 75 additions and 50 deletions
+15 -13
View File
@@ -132,6 +132,8 @@ export default {
ctx.restore() ctx.restore()
} }
const twoColumnWidth = 210
ctx.globalAlpha = 1 ctx.globalAlpha = 1
ctx.textBaseline = 'middle' ctx.textBaseline = 'middle'
@@ -150,12 +152,12 @@ export default {
// Top text // Top text
addText('audiobookshelf', '28px', 'normal', tanColor, '0px', 65, 28) addText('audiobookshelf', '28px', 'normal', tanColor, '0px', 65, 28)
addText(`${this.year} YEAR IN REVIEW`, '18px', 'bold', 'white', '1px', 65, 51) addText(`${this.year} ${this.$strings.StatsYearInReview}`, '18px', 'bold', 'white', '1px', 65, 51,)
// Top left box // Top left box
createRoundedRect(50, 100, 340, 160) createRoundedRect(50, 100, 340, 160)
addText(this.yearStats.numBooksFinished, '64px', 'bold', 'white', '0px', 160, 165) addText(this.yearStats.numBooksFinished, '64px', 'bold', 'white', '0px', 160, 165)
addText('books finished', '28px', 'normal', tanColor, '0px', 160, 210) addText(this.$strings.StatsBooksFinished, '28px', 'normal', tanColor, '0px', 160, 210, twoColumnWidth)
const readIconPath = new Path2D() const readIconPath = new Path2D()
readIconPath.addPath(new Path2D('M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z'), { a: 2, d: 2, e: 100, f: 160 }) readIconPath.addPath(new Path2D('M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z'), { a: 2, d: 2, e: 100, f: 160 })
ctx.fillStyle = '#ffffff' ctx.fillStyle = '#ffffff'
@@ -164,40 +166,40 @@ export default {
// Box top right // Box top right
createRoundedRect(410, 100, 340, 160) createRoundedRect(410, 100, 340, 160)
addText(this.$elapsedPrettyExtended(this.yearStats.totalListeningTime, true, false), '40px', 'bold', 'white', '0px', 500, 165) addText(this.$elapsedPrettyExtended(this.yearStats.totalListeningTime, true, false), '40px', 'bold', 'white', '0px', 500, 165)
addText('spent listening', '28px', 'normal', tanColor, '0px', 500, 205) addText(this.$strings.StatsSpentListening, '28px', 'normal', tanColor, '0px', 500, 205, twoColumnWidth)
addIcon('watch_later', 'white', '52px', 440, 180) addIcon('watch_later', 'white', '52px', 440, 180)
// Box bottom left // Box bottom left
createRoundedRect(50, 280, 340, 160) createRoundedRect(50, 280, 340, 160)
addText(this.yearStats.totalListeningSessions, '64px', 'bold', 'white', '0px', 160, 345) addText(this.yearStats.totalListeningSessions, '64px', 'bold', 'white', '0px', 160, 345)
addText('sessions', '28px', 'normal', tanColor, '1px', 160, 390) addText(this.$strings.StatsSessions, '28px', 'normal', tanColor, '1px', 160, 390, twoColumnWidth)
addIcon('headphones', 'white', '52px', 95, 360) addIcon('headphones', 'white', '52px', 95, 360)
// Box bottom right // Box bottom right
createRoundedRect(410, 280, 340, 160) createRoundedRect(410, 280, 340, 160)
addText(this.yearStats.numBooksListened, '64px', 'bold', 'white', '0px', 500, 345) addText(this.yearStats.numBooksListened, '64px', 'bold', 'white', '0px', 500, 345)
addText('books listened to', '28px', 'normal', tanColor, '0px', 500, 390) addText(this.$strings.StatsBooksListenedTo, '28px', 'normal', tanColor, '0px', 500, 390, twoColumnWidth)
addIcon('local_library', 'white', '52px', 440, 360) addIcon('local_library', 'white', '52px', 440, 360)
if (!this.variant) { if (!this.variant) {
// Text stats // Text stats
const topNarrator = this.yearStats.mostListenedNarrator const topNarrator = this.yearStats.mostListenedNarrator
if (topNarrator) { if (topNarrator) {
addText('TOP NARRATOR', '24px', 'normal', tanColor, '1px', 70, 520) addText(this.$strings.StatsTopNarrator, '24px', 'normal', tanColor, '1px', 70, 520, 330)
addText(topNarrator.name, '36px', 'bolder', 'white', '0px', 70, 564, 330) addText(topNarrator.name, '36px', 'bolder', 'white', '0px', 70, 564, 330)
addText(this.$elapsedPrettyExtended(topNarrator.time, true, false), '24px', 'lighter', 'white', '1px', 70, 599) addText(this.$elapsedPrettyExtended(topNarrator.time, true, false), '24px', 'lighter', 'white', '1px', 70, 599)
} }
const topGenre = this.yearStats.topGenres[0] const topGenre = this.yearStats.topGenres[0]
if (topGenre) { if (topGenre) {
addText('TOP GENRE', '24px', 'normal', tanColor, '1px', 430, 520) addText(this.$strings.StatsTopGenre, '24px', 'normal', tanColor, '1px', 430, 520, 330)
addText(topGenre.genre, '36px', 'bolder', 'white', '0px', 430, 564, 330) addText(topGenre.genre, '36px', 'bolder', 'white', '0px', 430, 564, 330)
addText(this.$elapsedPrettyExtended(topGenre.time, true, false), '24px', 'lighter', 'white', '1px', 430, 599) addText(this.$elapsedPrettyExtended(topGenre.time, true, false), '24px', 'lighter', 'white', '1px', 430, 599)
} }
const topAuthor = this.yearStats.topAuthors[0] const topAuthor = this.yearStats.topAuthors[0]
if (topAuthor) { if (topAuthor) {
addText('TOP AUTHOR', '24px', 'normal', tanColor, '1px', 70, 670) addText(this.$strings.StatsTopAuthor, '24px', 'normal', tanColor, '1px', 70, 670, 330)
addText(topAuthor.name, '36px', 'bolder', 'white', '0px', 70, 714, 330) addText(topAuthor.name, '36px', 'bolder', 'white', '0px', 70, 714, 330)
addText(this.$elapsedPrettyExtended(topAuthor.time, true, false), '24px', 'lighter', 'white', '1px', 70, 749) addText(this.$elapsedPrettyExtended(topAuthor.time, true, false), '24px', 'lighter', 'white', '1px', 70, 749)
} }
@@ -205,7 +207,7 @@ export default {
if (this.yearStats.mostListenedMonth?.time) { if (this.yearStats.mostListenedMonth?.time) {
const jsdate = new Date(this.year, this.yearStats.mostListenedMonth.month, 1) const jsdate = new Date(this.year, this.yearStats.mostListenedMonth.month, 1)
const monthName = this.$formatJsDate(jsdate, 'LLLL') const monthName = this.$formatJsDate(jsdate, 'LLLL')
addText('TOP MONTH', '24px', 'normal', tanColor, '1px', 430, 670) addText(this.$strings.StatsTopMonth, '24px', 'normal', tanColor, '1px', 430, 670, 330)
addText(monthName, '36px', 'bolder', 'white', '0px', 430, 714, 330) addText(monthName, '36px', 'bolder', 'white', '0px', 430, 714, 330)
addText(this.$elapsedPrettyExtended(this.yearStats.mostListenedMonth.time, true, false), '24px', 'lighter', 'white', '1px', 430, 749) addText(this.$elapsedPrettyExtended(this.yearStats.mostListenedMonth.time, true, false), '24px', 'lighter', 'white', '1px', 430, 749)
} }
@@ -214,7 +216,7 @@ export default {
finishedBookCoverImgs = Object.values(finishedBookCoverImgs) finishedBookCoverImgs = Object.values(finishedBookCoverImgs)
if (finishedBookCoverImgs.length > 0) { if (finishedBookCoverImgs.length > 0) {
ctx.textAlign = 'center' ctx.textAlign = 'center'
addText('Some books finished this year...', '28px', 'normal', tanColor, '0px', canvas.width / 2, 530) addText(this.$strings.StatsBooksFinishedThisYear, '28px', 'normal', tanColor, '0px', canvas.width / 2, 530)
for (let i = 0; i < Math.min(5, finishedBookCoverImgs.length); i++) { for (let i = 0; i < Math.min(5, finishedBookCoverImgs.length); i++) {
let imgToAdd = finishedBookCoverImgs[i] let imgToAdd = finishedBookCoverImgs[i]
@@ -224,14 +226,14 @@ export default {
} else if (this.variant === 2) { } else if (this.variant === 2) {
// Text stats // Text stats
if (this.yearStats.topAuthors.length) { if (this.yearStats.topAuthors.length) {
addText('TOP AUTHORS', '24px', 'normal', tanColor, '1px', 70, 524) addText(this.$strings.StatsTopAuthors, '24px', 'normal', tanColor, '1px', 70, 524)
for (let i = 0; i < this.yearStats.topAuthors.length; i++) { for (let i = 0; i < this.yearStats.topAuthors.length; i++) {
addText(this.yearStats.topAuthors[i].name, '36px', 'bolder', 'white', '0px', 70, 584 + i * 60, 330) addText(this.yearStats.topAuthors[i].name, '36px', 'bolder', 'white', '0px', 70, 584 + i * 60, 330)
} }
} }
if (this.yearStats.topGenres.length) { if (this.yearStats.topGenres.length) {
addText('TOP GENRES', '24px', 'normal', tanColor, '1px', 430, 524) addText(this.$strings.StatsTopGenres, '24px', 'normal', tanColor, '1px', 430, 524)
for (let i = 0; i < this.yearStats.topGenres.length; i++) { for (let i = 0; i < this.yearStats.topGenres.length; i++) {
addText(this.yearStats.topGenres[i].genre, '36px', 'bolder', 'white', '0px', 430, 584 + i * 60, 330) addText(this.yearStats.topGenres[i].genre, '36px', 'bolder', 'white', '0px', 430, 584 + i * 60, 330)
} }
@@ -263,7 +265,7 @@ export default {
} }
}) })
} else { } else {
this.$toast.error('Cannot share natively on this device') this.$toast.error(this.$strings.ToastErrorCannotShare)
} }
}) })
}, },
+14 -12
View File
@@ -123,6 +123,8 @@ export default {
ctx.restore() ctx.restore()
} }
const threeColumnTextWidth = 200
ctx.globalAlpha = 1 ctx.globalAlpha = 1
ctx.textBaseline = 'middle' ctx.textBaseline = 'middle'
@@ -141,33 +143,33 @@ export default {
// Top text // Top text
addText('audiobookshelf', '28px', 'normal', tanColor, '0px', 65, 28) addText('audiobookshelf', '28px', 'normal', tanColor, '0px', 65, 28)
addText(`${this.year} YEAR IN REVIEW`, '18px', 'bold', 'white', '1px', 65, 51) addText(`${this.year} ${this.$strings.StatsYearInReview}`, '18px', 'bold', 'white', '1px', 65, 51)
// Top left box // Top left box
createRoundedRect(40, 100, 230, 100) createRoundedRect(40, 100, 230, 100)
ctx.textAlign = 'center' ctx.textAlign = 'center'
addText(this.yearStats.numBooksAdded, '48px', 'bold', 'white', '0px', 155, 140) addText(this.yearStats.numBooksAdded, '48px', 'bold', 'white', '0px', 155, 140)
addText('books added', '18px', 'normal', tanColor, '0px', 155, 170) addText(this.$strings.StatsBooksAdded, '18px', 'normal', tanColor, '0px', 155, 170, threeColumnTextWidth)
// Box top right // Box top right
createRoundedRect(285, 100, 230, 100) createRoundedRect(285, 100, 230, 100)
addText(this.yearStats.numAuthorsAdded, '48px', 'bold', 'white', '0px', 400, 140) addText(this.yearStats.numAuthorsAdded, '48px', 'bold', 'white', '0px', 400, 140)
addText('authors added', '18px', 'normal', tanColor, '0px', 400, 170) addText(this.$strings.StatsAuthorsAdded, '18px', 'normal', tanColor, '0px', 400, 170, threeColumnTextWidth)
// Box bottom left // Box bottom left
createRoundedRect(530, 100, 230, 100) createRoundedRect(530, 100, 230, 100)
addText(this.yearStats.numListeningSessions, '48px', 'bold', 'white', '0px', 645, 140) addText(this.yearStats.numListeningSessions, '48px', 'bold', 'white', '0px', 645, 140)
addText('sessions', '18px', 'normal', tanColor, '1px', 645, 170) addText(this.$strings.StatsSessions, '18px', 'normal', tanColor, '1px', 645, 170, threeColumnTextWidth)
// Text stats // Text stats
if (this.yearStats.totalBooksAddedSize) { if (this.yearStats.totalBooksAddedSize) {
addText('Your book collection grew to...', '24px', 'normal', tanColor, '0px', canvas.width / 2, 260) addText(this.$strings.StatsCollectionGrewTo, '24px', 'normal', tanColor, '0px', canvas.width / 2, 260)
addText(this.$bytesPretty(this.yearStats.totalBooksSize), '36px', 'bolder', 'white', '0px', canvas.width / 2, 300) addText(this.$bytesPretty(this.yearStats.totalBooksSize), '36px', 'bolder', 'white', '0px', canvas.width / 2, 300)
addText('+' + this.$bytesPretty(this.yearStats.totalBooksAddedSize), '20px', 'lighter', 'white', '0px', canvas.width / 2, 330) addText('+' + this.$bytesPretty(this.yearStats.totalBooksAddedSize), '20px', 'lighter', 'white', '0px', canvas.width / 2, 330)
} }
if (this.yearStats.totalBooksAddedDuration) { if (this.yearStats.totalBooksAddedDuration) {
addText('With a total duration of...', '24px', 'normal', tanColor, '0px', canvas.width / 2, 400) addText(this.$strings.StatsTotalDuration, '24px', 'normal', tanColor, '0px', canvas.width / 2, 400)
addText(this.$elapsedPrettyExtended(this.yearStats.totalBooksDuration, true, false), '36px', 'bolder', 'white', '0px', canvas.width / 2, 440) addText(this.$elapsedPrettyExtended(this.yearStats.totalBooksDuration, true, false), '36px', 'bolder', 'white', '0px', canvas.width / 2, 440)
addText('+' + this.$elapsedPrettyExtended(this.yearStats.totalBooksAddedDuration, true, false), '20px', 'lighter', 'white', '0px', canvas.width / 2, 470) addText('+' + this.$elapsedPrettyExtended(this.yearStats.totalBooksAddedDuration, true, false), '20px', 'lighter', 'white', '0px', canvas.width / 2, 470)
} }
@@ -176,7 +178,7 @@ export default {
// Bottom images // Bottom images
imgsToAdd = Object.values(imgsToAdd) imgsToAdd = Object.values(imgsToAdd)
if (imgsToAdd.length > 0) { if (imgsToAdd.length > 0) {
addText('Some additions include...', '24px', 'normal', tanColor, '0px', canvas.width / 2, 540) addText(this.$strings.StatsBooksAdditional, '24px', 'normal', tanColor, '0px', canvas.width / 2, 540)
for (let i = 0; i < Math.min(5, imgsToAdd.length); i++) { for (let i = 0; i < Math.min(5, imgsToAdd.length); i++) {
let imgToAdd = imgsToAdd[i] let imgToAdd = imgsToAdd[i]
@@ -187,14 +189,14 @@ export default {
// Text stats // Text stats
ctx.textAlign = 'left' ctx.textAlign = 'left'
if (this.yearStats.topAuthors.length) { if (this.yearStats.topAuthors.length) {
addText('TOP AUTHORS', '24px', 'normal', tanColor, '1px', 70, 549) addText(this.$strings.StatsTopAuthors, '24px', 'normal', tanColor, '1px', 70, 549, 330)
for (let i = 0; i < this.yearStats.topAuthors.length; i++) { for (let i = 0; i < this.yearStats.topAuthors.length; i++) {
addText(this.yearStats.topAuthors[i].name, '36px', 'bolder', 'white', '0px', 70, 609 + i * 60, 330) addText(this.yearStats.topAuthors[i].name, '36px', 'bolder', 'white', '0px', 70, 609 + i * 60, 330)
} }
} }
if (this.yearStats.topNarrators.length) { if (this.yearStats.topNarrators.length) {
addText('TOP NARRATORS', '24px', 'normal', tanColor, '1px', 430, 549) addText(this.$strings.StatsTopNarrators, '24px', 'normal', tanColor, '1px', 430, 549)
for (let i = 0; i < this.yearStats.topNarrators.length; i++) { for (let i = 0; i < this.yearStats.topNarrators.length; i++) {
addText(this.yearStats.topNarrators[i].name, '36px', 'bolder', 'white', '0px', 430, 609 + i * 60, 330) addText(this.yearStats.topNarrators[i].name, '36px', 'bolder', 'white', '0px', 430, 609 + i * 60, 330)
} }
@@ -203,14 +205,14 @@ export default {
// Text stats // Text stats
ctx.textAlign = 'left' ctx.textAlign = 'left'
if (this.yearStats.topAuthors.length) { if (this.yearStats.topAuthors.length) {
addText('TOP AUTHORS', '24px', 'normal', tanColor, '1px', 70, 549) addText(this.$strings.StatsTopAuthors, '24px', 'normal', tanColor, '1px', 70, 549, 330)
for (let i = 0; i < this.yearStats.topAuthors.length; i++) { for (let i = 0; i < this.yearStats.topAuthors.length; i++) {
addText(this.yearStats.topAuthors[i].name, '36px', 'bolder', 'white', '0px', 70, 609 + i * 60, 330) addText(this.yearStats.topAuthors[i].name, '36px', 'bolder', 'white', '0px', 70, 609 + i * 60, 330)
} }
} }
if (this.yearStats.topGenres.length) { if (this.yearStats.topGenres.length) {
addText('TOP GENRES', '24px', 'normal', tanColor, '1px', 430, 549) addText(this.$strings.StatsTopGenres, '24px', 'normal', tanColor, '1px', 430, 549)
for (let i = 0; i < this.yearStats.topGenres.length; i++) { for (let i = 0; i < this.yearStats.topGenres.length; i++) {
addText(this.yearStats.topGenres[i].genre, '36px', 'bolder', 'white', '0px', 430, 609 + i * 60, 330) addText(this.yearStats.topGenres[i].genre, '36px', 'bolder', 'white', '0px', 430, 609 + i * 60, 330)
} }
@@ -239,7 +241,7 @@ export default {
} }
}) })
} else { } else {
this.$toast.error('Cannot share natively on this device') this.$toast.error(this.$strings.ToastErrorCannotShare)
} }
}) })
}, },
@@ -113,6 +113,8 @@ export default {
ctx.restore() ctx.restore()
} }
const twoColumnWidth = 180
ctx.globalAlpha = 1 ctx.globalAlpha = 1
ctx.textBaseline = 'middle' ctx.textBaseline = 'middle'
@@ -131,12 +133,12 @@ export default {
// Top text // Top text
addText('audiobookshelf', '28px', 'normal', tanColor, '0px', 65, 28) addText('audiobookshelf', '28px', 'normal', tanColor, '0px', 65, 28)
addText(`${this.year} YEAR IN REVIEW`, '18px', 'bold', 'white', '1px', 65, 51) addText(`${this.year} ${this.$strings.StatsYearInReview}`, '18px', 'bold', 'white', '1px', 65, 51)
// Top left box // Top left box
createRoundedRect(15, 75, 280, 110) createRoundedRect(15, 75, 280, 110)
addText(this.yearStats.numBooksFinished, '48px', 'bold', 'white', '0px', 105, 120) addText(this.yearStats.numBooksFinished, '48px', 'bold', 'white', '0px', 105, 120)
addText('books finished', '20px', 'normal', tanColor, '0px', 105, 155) addText(this.$strings.StatsBooksFinished, '20px', 'normal', tanColor, '0px', 105, 155, twoColumnWidth)
const readIconPath = new Path2D() const readIconPath = new Path2D()
readIconPath.addPath(new Path2D('M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z'), { a: 1.5, d: 1.5, e: 55, f: 115 }) readIconPath.addPath(new Path2D('M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z'), { a: 1.5, d: 1.5, e: 55, f: 115 })
ctx.fillStyle = '#ffffff' ctx.fillStyle = '#ffffff'
@@ -144,7 +146,7 @@ export default {
createRoundedRect(305, 75, 280, 110) createRoundedRect(305, 75, 280, 110)
addText(this.yearStats.numBooksListened, '48px', 'bold', 'white', '0px', 400, 120) addText(this.yearStats.numBooksListened, '48px', 'bold', 'white', '0px', 400, 120)
addText('books listened to', '20px', 'normal', tanColor, '0px', 400, 155) addText(this.$strings.StatsBooksListenedTo, '20px', 'normal', tanColor, '0px', 400, 155, twoColumnWidth)
addIcon('local_library', 'white', '42px', 345, 130) addIcon('local_library', 'white', '42px', 345, 130)
this.canvas = canvas this.canvas = canvas
@@ -169,7 +171,7 @@ export default {
} }
}) })
} else { } else {
this.$toast.error('Cannot share natively on this device') this.$toast.error(this.$strings.ToastErrorCannotShare)
} }
}) })
}, },
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.12.2", "version": "2.12.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.12.2", "version": "2.12.3",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.13.6", "@nuxtjs/axios": "^5.13.6",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.12.2", "version": "2.12.3",
"buildNumber": 1, "buildNumber": 1,
"description": "Self-hosted audiobook and podcast client", "description": "Self-hosted audiobook and podcast client",
"main": "index.js", "main": "index.js",
+19
View File
@@ -771,6 +771,24 @@
"PlaceholderNewPlaylist": "New playlist name", "PlaceholderNewPlaylist": "New playlist name",
"PlaceholderSearch": "Search..", "PlaceholderSearch": "Search..",
"PlaceholderSearchEpisode": "Search episode..", "PlaceholderSearchEpisode": "Search episode..",
"StatsAuthorsAdded": "authors added",
"StatsBooksAdded": "books added",
"StatsBooksAdditional": "Some additions include…",
"StatsBooksFinished": "books finished",
"StatsBooksFinishedThisYear": "Some books finished this year…",
"StatsBooksListenedTo": "books listened to",
"StatsCollectionGrewTo": "Your book collection grew to…",
"StatsSessions": "sessions",
"StatsSpentListening": "spent listening",
"StatsTopAuthor": "TOP AUTHOR",
"StatsTopAuthors": "TOP AUTHORS",
"StatsTopGenre": "TOP GENRE",
"StatsTopGenres": "TOP GENRES",
"StatsTopMonth": "TOP MONTH",
"StatsTopNarrator": "TOP NARRATOR",
"StatsTopNarrators": "TOP NARRATORS",
"StatsTotalDuration": "With a total duration of…",
"StatsYearInReview": "YEAR IN REVIEW",
"ToastAccountUpdateFailed": "Failed to update account", "ToastAccountUpdateFailed": "Failed to update account",
"ToastAccountUpdateSuccess": "Account updated", "ToastAccountUpdateSuccess": "Account updated",
"ToastAuthorImageRemoveFailed": "Failed to remove image", "ToastAuthorImageRemoveFailed": "Failed to remove image",
@@ -806,6 +824,7 @@
"ToastCollectionUpdateSuccess": "Collection updated", "ToastCollectionUpdateSuccess": "Collection updated",
"ToastDeleteFileFailed": "Failed to delete file", "ToastDeleteFileFailed": "Failed to delete file",
"ToastDeleteFileSuccess": "File deleted", "ToastDeleteFileSuccess": "File deleted",
"ToastErrorCannotShare": "Cannot share natively on this device",
"ToastFailedToLoadData": "Failed to load data", "ToastFailedToLoadData": "Failed to load data",
"ToastItemCoverUpdateFailed": "Failed to update item cover", "ToastItemCoverUpdateFailed": "Failed to update item cover",
"ToastItemCoverUpdateSuccess": "Item cover updated", "ToastItemCoverUpdateSuccess": "Item cover updated",
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.12.2", "version": "2.12.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.12.2", "version": "2.12.3",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"axios": "^0.27.2", "axios": "^0.27.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.12.2", "version": "2.12.3",
"buildNumber": 1, "buildNumber": 1,
"description": "Self-hosted audiobook and podcast server", "description": "Self-hosted audiobook and podcast server",
"main": "index.js", "main": "index.js",
+4 -5
View File
@@ -207,7 +207,6 @@ class Database {
try { try {
await this.sequelize.authenticate() await this.sequelize.authenticate()
await this.loadExtensions([process.env.SQLEAN_UNICODE_PATH])
Logger.info(`[Database] Db connection was successful`) Logger.info(`[Database] Db connection was successful`)
return true return true
} catch (error) { } catch (error) {
@@ -217,7 +216,7 @@ class Database {
} }
/** /**
* * TODO: Temporarily disabled
* @param {string[]} extensions paths to extension binaries * @param {string[]} extensions paths to extension binaries
*/ */
async loadExtensions(extensions) { async loadExtensions(extensions) {
@@ -827,7 +826,7 @@ class Database {
} }
/** /**
* * TODO: Temporarily unused
* @param {string} value * @param {string} value
* @returns {string} * @returns {string}
*/ */
@@ -836,7 +835,7 @@ class Database {
} }
/** /**
* * TODO: Temporarily unused
* @param {string} query * @param {string} query
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
@@ -855,7 +854,7 @@ class Database {
*/ */
matchExpression(column, normalizedQuery) { matchExpression(column, normalizedQuery) {
const normalizedPattern = this.sequelize.escape(`%${normalizedQuery}%`) const normalizedPattern = this.sequelize.escape(`%${normalizedQuery}%`)
const normalizedColumn = this.normalize(column) const normalizedColumn = column
return `${normalizedColumn} LIKE ${normalizedPattern}` return `${normalizedColumn} LIKE ${normalizedPattern}`
} }
} }
+6 -6
View File
@@ -113,21 +113,21 @@ class LibraryItemController {
Logger.warn('User attempted to download without permission', req.user) Logger.warn('User attempted to download without permission', req.user)
return res.sendStatus(403) return res.sendStatus(403)
} }
const libraryItemPath = req.libraryItem.path
const itemTitle = req.libraryItem.media.metadata.title
// If library item is a single file in root dir then no need to zip // If library item is a single file in root dir then no need to zip
if (req.libraryItem.isFile) { if (req.libraryItem.isFile) {
// Express does not set the correct mimetype for m4b files so use our defined mimetypes if available // Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(req.libraryItem.path)) const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(libraryItemPath))
if (audioMimeType) { if (audioMimeType) {
res.setHeader('Content-Type', audioMimeType) res.setHeader('Content-Type', audioMimeType)
} }
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
res.download(req.libraryItem.path, req.libraryItem.relPath) res.download(libraryItemPath, req.libraryItem.relPath)
return return
} }
const libraryItemPath = req.libraryItem.path
const itemTitle = req.libraryItem.media.metadata.title
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`) Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
const filename = `${itemTitle}.zip` const filename = `${itemTitle}.zip`
zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res) zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
@@ -715,7 +715,7 @@ class LibraryItemController {
return res.sendStatus(403) return res.sendStatus(403)
} }
Logger.info(`[LibraryItemController] User "${req.user.username}" requested file download at "${libraryFile.metadata.path}"`) Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${req.libraryItem.media.metadata.title}" file at "${libraryFile.metadata.path}"`)
if (global.XAccel) { if (global.XAccel) {
const encodedURI = encodeUriPath(global.XAccel + libraryFile.metadata.path) const encodedURI = encodeUriPath(global.XAccel + libraryFile.metadata.path)
+3 -2
View File
@@ -263,8 +263,9 @@ module.exports.sqlean = sqlean // for testing
class BinaryManager { class BinaryManager {
defaultRequiredBinaries = [ defaultRequiredBinaries = [
new Binary('ffmpeg', 'executable', 'FFMPEG_PATH', ['5.1'], ffbinaries), // ffmpeg executable new Binary('ffmpeg', 'executable', 'FFMPEG_PATH', ['5.1'], ffbinaries), // ffmpeg executable
new Binary('ffprobe', 'executable', 'FFPROBE_PATH', ['5.1'], ffbinaries), // ffprobe executable new Binary('ffprobe', 'executable', 'FFPROBE_PATH', ['5.1'], ffbinaries) // ffprobe executable
new Binary('unicode', 'library', 'SQLEAN_UNICODE_PATH', ['0.24.2'], sqlean) // sqlean unicode extension // TODO: Temporarily disabled due to db corruption issues
// new Binary('unicode', 'library', 'SQLEAN_UNICODE_PATH', ['0.24.2'], sqlean) // sqlean unicode extension
] ]
constructor(requiredBinaries = this.defaultRequiredBinaries) { constructor(requiredBinaries = this.defaultRequiredBinaries) {
@@ -975,7 +975,7 @@ module.exports = {
async search(oldUser, oldLibrary, query, limit, offset) { async search(oldUser, oldLibrary, query, limit, offset) {
const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(oldUser) const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(oldUser)
const normalizedQuery = await Database.getNormalizedQuery(query) const normalizedQuery = query
const matchTitle = Database.matchExpression('title', normalizedQuery) const matchTitle = Database.matchExpression('title', normalizedQuery)
const matchSubtitle = Database.matchExpression('subtitle', normalizedQuery) const matchSubtitle = Database.matchExpression('subtitle', normalizedQuery)
@@ -314,7 +314,7 @@ module.exports = {
async search(oldUser, oldLibrary, query, limit, offset) { async search(oldUser, oldLibrary, query, limit, offset) {
const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(oldUser) const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(oldUser)
const normalizedQuery = await Database.getNormalizedQuery(query) const normalizedQuery = query
const matchTitle = Database.matchExpression('title', normalizedQuery) const matchTitle = Database.matchExpression('title', normalizedQuery)
const matchAuthor = Database.matchExpression('author', normalizedQuery) const matchAuthor = Database.matchExpression('author', normalizedQuery)