Compare commits

...

6 Commits

Author SHA1 Message Date
advplyr 2cc9d1b7f8 Update watcher to re-scan library items when non-media files are added/updated #4245 2025-05-01 17:17:40 -05:00
advplyr 2b7268c952 Merge pull request #4240 from josh-vin/feat/defaultYearInReview
Improves Year in Review display logic
2025-04-30 17:26:00 -05:00
advplyr e097fe1e88 Merge pull request #4241 from advplyr/player_track_tooltip
Fix player track tooltip overflowing on share player
2025-04-29 18:01:25 -05:00
advplyr 6819c0b108 Fix player track tooltip overflowing on share player 2025-04-29 17:46:54 -05:00
Josh Vincent 58cd751b43 Improves Year in Review display logic 2025-04-28 21:00:22 -06:00
advplyr 9f834a5345 Merge pull request #4234 from advplyr/fix_exclude_prefixes_crash
Fix server crash when updating excluded prefixes #4221
2025-04-28 16:57:38 -05:00
6 changed files with 35 additions and 15 deletions
@@ -74,6 +74,9 @@ export default {
currentChapterStart() { currentChapterStart() {
if (!this.currentChapter) return 0 if (!this.currentChapter) return 0
return this.currentChapter.start return this.currentChapter.start
},
isMobile() {
return this.$store.state.globals.isMobile
} }
}, },
methods: { methods: {
@@ -145,6 +148,9 @@ export default {
}) })
}, },
mousemoveTrack(e) { mousemoveTrack(e) {
if (this.isMobile) {
return
}
const offsetX = e.offsetX const offsetX = e.offsetX
const baseTime = this.useChapterTrack ? this.currentChapterStart : 0 const baseTime = this.useChapterTrack ? this.currentChapterStart : 0
@@ -198,6 +204,7 @@ export default {
setTrackWidth() { setTrackWidth() {
if (this.$refs.track) { if (this.$refs.track) {
this.trackWidth = this.$refs.track.clientWidth this.trackWidth = this.$refs.track.clientWidth
this.trackOffsetLeft = this.$refs.track.getBoundingClientRect().left
} else { } else {
console.error('Track not loaded', this.$refs) console.error('Track not loaded', this.$refs)
} }
@@ -164,14 +164,15 @@ export default {
beforeMount() { beforeMount() {
this.yearInReviewYear = new Date().getFullYear() this.yearInReviewYear = new Date().getFullYear()
// When not December show previous year this.availableYears = this.getAvailableYears()
if (new Date().getMonth() < 11) { const availableYearValues = this.availableYears.map((y) => y.value)
// When not December show previous year if data is available
if (new Date().getMonth() < 11 && availableYearValues.includes(this.yearInReviewYear - 1)) {
this.yearInReviewYear-- this.yearInReviewYear--
} }
}, },
mounted() { mounted() {
this.availableYears = this.getAvailableYears()
if (typeof navigator.share !== 'undefined' && navigator.share) { if (typeof navigator.share !== 'undefined' && navigator.share) {
this.showShareButton = true this.showShareButton = true
} else { } else {
+6 -3
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="w-full h-dvh max-h-dvh overflow-hidden" :style="{ backgroundColor: coverRgb }"> <div class="w-full max-w-full h-dvh max-h-dvh overflow-hidden" :style="{ backgroundColor: coverRgb }">
<div class="w-screen h-screen absolute inset-0 pointer-events-none" style="background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(38, 38, 38, 1) 80%)"></div> <div class="w-screen h-screen absolute inset-0 pointer-events-none" style="background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(38, 38, 38, 1) 80%)"></div>
<div class="absolute inset-0 w-screen h-dvh flex items-center justify-center z-10"> <div class="absolute inset-0 w-screen h-dvh flex items-center justify-center z-10">
<div class="w-full p-2 sm:p-4 md:p-8"> <div class="w-full p-2 sm:p-4 md:p-8">
@@ -335,8 +335,11 @@ export default {
} }
}, },
resize() { resize() {
this.windowWidth = window.innerWidth setTimeout(() => {
this.windowHeight = window.innerHeight this.windowWidth = window.innerWidth
this.windowHeight = window.innerHeight
this.$store.commit('globals/updateWindowSize', { width: window.innerWidth, height: window.innerHeight })
}, 100)
}, },
playerError(error) { playerError(error) {
console.error('Player error', error) console.error('Player error', error)
-1
View File
@@ -246,7 +246,6 @@ class LibraryItem extends Model {
include include
}) })
if (!libraryItem) { if (!libraryItem) {
Logger.error(`[LibraryItem] Library item not found`)
return null return null
} }
+1 -1
View File
@@ -407,7 +407,7 @@ class LibraryScanner {
const folder = library.libraryFolders[0] const folder = library.libraryFolders[0]
const filePathItems = folderGroups[folderId].fileUpdates.map((fileUpdate) => fileUtils.getFilePathItemFromFileUpdate(fileUpdate)) const filePathItems = folderGroups[folderId].fileUpdates.map((fileUpdate) => fileUtils.getFilePathItemFromFileUpdate(fileUpdate))
const fileUpdateGroup = scanUtils.groupFileItemsIntoLibraryItemDirs(library.mediaType, filePathItems, !!library.settings?.audiobooksOnly) const fileUpdateGroup = scanUtils.groupFileItemsIntoLibraryItemDirs(library.mediaType, filePathItems, !!library.settings?.audiobooksOnly, true)
if (!Object.keys(fileUpdateGroup).length) { if (!Object.keys(fileUpdateGroup).length) {
Logger.info(`[LibraryScanner] No important changes to scan for in folder "${folderId}"`) Logger.info(`[LibraryScanner] No important changes to scan for in folder "${folderId}"`)
+16 -6
View File
@@ -24,6 +24,12 @@ function isMediaFile(mediaType, ext, audiobooksOnly = false) {
return globals.SupportedAudioTypes.includes(extclean) || globals.SupportedEbookTypes.includes(extclean) return globals.SupportedAudioTypes.includes(extclean) || globals.SupportedEbookTypes.includes(extclean)
} }
function isScannableNonMediaFile(ext) {
if (!ext) return false
const extclean = ext.slice(1).toLowerCase()
return globals.TextFileTypes.includes(extclean) || globals.MetadataFileTypes.includes(extclean) || globals.SupportedImageTypes.includes(extclean)
}
function checkFilepathIsAudioFile(filepath) { function checkFilepathIsAudioFile(filepath) {
const ext = Path.extname(filepath) const ext = Path.extname(filepath)
if (!ext) return false if (!ext) return false
@@ -35,27 +41,31 @@ module.exports.checkFilepathIsAudioFile = checkFilepathIsAudioFile
/** /**
* @param {string} mediaType * @param {string} mediaType
* @param {import('./fileUtils').FilePathItem[]} fileItems * @param {import('./fileUtils').FilePathItem[]} fileItems
* @param {boolean} [audiobooksOnly=false] * @param {boolean} audiobooksOnly
* @param {boolean} [includeNonMediaFiles=false] - Used by the watcher to re-scan when covers/metadata files are added/removed
* @returns {Record<string,string[]>} map of files grouped into potential libarary item dirs * @returns {Record<string,string[]>} map of files grouped into potential libarary item dirs
*/ */
function groupFileItemsIntoLibraryItemDirs(mediaType, fileItems, audiobooksOnly = false) { function groupFileItemsIntoLibraryItemDirs(mediaType, fileItems, audiobooksOnly, includeNonMediaFiles = false) {
// Step 1: Filter out non-book-media files in root dir (with depth of 0) // Step 1: Filter out non-book-media files in root dir (with depth of 0)
const itemsFiltered = fileItems.filter((i) => { const itemsFiltered = fileItems.filter((i) => {
return i.deep > 0 || (mediaType === 'book' && isMediaFile(mediaType, i.extension, audiobooksOnly)) return i.deep > 0 || (mediaType === 'book' && isMediaFile(mediaType, i.extension, audiobooksOnly))
}) })
// Step 2: Separate media files and other files // Step 2: Separate media files and other files
// - Directories without a media file will not be included // - Directories without a media file will not be included (unless includeNonMediaFiles is true)
/** @type {import('./fileUtils').FilePathItem[]} */ /** @type {import('./fileUtils').FilePathItem[]} */
const mediaFileItems = [] const mediaFileItems = []
/** @type {import('./fileUtils').FilePathItem[]} */ /** @type {import('./fileUtils').FilePathItem[]} */
const otherFileItems = [] const otherFileItems = []
itemsFiltered.forEach((item) => { itemsFiltered.forEach((item) => {
if (isMediaFile(mediaType, item.extension, audiobooksOnly)) mediaFileItems.push(item) if (isMediaFile(mediaType, item.extension, audiobooksOnly) || (includeNonMediaFiles && isScannableNonMediaFile(item.extension))) {
else otherFileItems.push(item) mediaFileItems.push(item)
} else {
otherFileItems.push(item)
}
}) })
// Step 3: Group audio files in library items // Step 3: Group media files (or non-media files if includeNonMediaFiles is true) in library items
const libraryItemGroup = {} const libraryItemGroup = {}
mediaFileItems.forEach((item) => { mediaFileItems.forEach((item) => {
const dirparts = item.reldirpath.split('/').filter((p) => !!p) const dirparts = item.reldirpath.split('/').filter((p) => !!p)