Compare commits

..

7 Commits

Author SHA1 Message Date
advplyr b816c0e7c4 Fix opening feed for series and collections 2025-01-20 14:18:22 -06:00
advplyr a8b92819d1 Update feed episode description to use CDATA 2025-01-20 14:04:18 -06:00
advplyr 54a4b09592 Update RSS feed to exclude empty tags, format duration, use CDATA 2025-01-20 13:57:56 -06:00
advplyr f13283b950 Merge pull request #3864 from mikiher/subdir-support-fix-missing-img
Fix missing texture image & epub ebook url for subdirectory support
2025-01-20 09:09:39 -06:00
advplyr 78994b3589 Update epub ebook url to include routerBasePath 2025-01-20 09:06:45 -06:00
advplyr 6745efc4d6 Revert case-insensitive cache manager update in #3780 2025-01-20 08:59:45 -06:00
mikiher 6c540ad789 Fix missing texture image for subdirectory support 2025-01-20 08:38:58 +02:00
7 changed files with 63 additions and 41 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
@import './absicons.css'; @import './absicons.css';
:root { :root {
--bookshelf-texture-img: url(/textures/wood_default.jpg); --bookshelf-texture-img: url(~static/textures/wood_default.jpg);
--bookshelf-divider-bg: linear-gradient(180deg, rgba(149, 119, 90, 1) 0%, rgba(103, 70, 37, 1) 17%, rgba(103, 70, 37, 1) 88%, rgba(71, 48, 25, 1) 100%); --bookshelf-divider-bg: linear-gradient(180deg, rgba(149, 119, 90, 1) 0%, rgba(103, 70, 37, 1) 17%, rgba(103, 70, 37, 1) 88%, rgba(71, 48, 25, 1) 100%);
} }
+2 -2
View File
@@ -97,9 +97,9 @@ export default {
}, },
ebookUrl() { ebookUrl() {
if (this.fileId) { if (this.fileId) {
return `/api/items/${this.libraryItemId}/ebook/${this.fileId}` return `${this.$config.routerBasePath}/api/items/${this.libraryItemId}/ebook/${this.fileId}`
} }
return `/api/items/${this.libraryItemId}/ebook` return `${this.$config.routerBasePath}/api/items/${this.libraryItemId}/ebook`
}, },
themeRules() { themeRules() {
const isDark = this.ereaderSettings.theme === 'dark' const isDark = this.ereaderSettings.theme === 'dark'
+1 -2
View File
@@ -42,8 +42,7 @@ class ApiCacheManager {
Logger.debug(`[ApiCacheManager] Skipping cache for random sort`) Logger.debug(`[ApiCacheManager] Skipping cache for random sort`)
return next() return next()
} }
// Force URL to be lower case for matching against routes
req.url = req.url.toLowerCase()
const key = { user: req.user.username, url: req.url } const key = { user: req.user.username, url: req.url }
const stringifiedKey = JSON.stringify(key) const stringifiedKey = JSON.stringify(key)
Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`) Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`)
+37 -21
View File
@@ -561,7 +561,42 @@ class Feed extends Model {
* @param {string} hostPrefix * @param {string} hostPrefix
*/ */
buildXml(hostPrefix) { buildXml(hostPrefix) {
const blockTags = [{ 'itunes:block': 'yes' }, { 'googleplay:block': 'yes' }] const customElements = [
{ language: this.language || 'en' },
{ author: this.author || 'advplyr' },
{ 'itunes:author': this.author || 'advplyr' },
{ 'itunes:type': this.podcastType || 'serial' },
{
'itunes:image': {
_attr: {
href: `${hostPrefix}${this.imageURL}`
}
}
},
{ 'itunes:explicit': !!this.explicit }
]
if (this.description) {
customElements.push({ 'itunes:summary': { _cdata: this.description } })
}
const itunesOwnersData = []
if (this.ownerName || this.author) {
itunesOwnersData.push({ 'itunes:name': this.ownerName || this.author })
}
if (this.ownerEmail) {
itunesOwnersData.push({ 'itunes:email': this.ownerEmail })
}
if (itunesOwnersData.length) {
customElements.push({
'itunes:owner': itunesOwnersData
})
}
if (this.preventIndexing) {
customElements.push({ 'itunes:block': 'yes' }, { 'googleplay:block': 'yes' })
}
const rssData = { const rssData = {
title: this.title, title: this.title,
description: this.description || '', description: this.description || '',
@@ -571,29 +606,10 @@ class Feed extends Model {
image_url: `${hostPrefix}${this.imageURL}`, image_url: `${hostPrefix}${this.imageURL}`,
custom_namespaces: { custom_namespaces: {
itunes: 'http://www.itunes.com/dtds/podcast-1.0.dtd', itunes: 'http://www.itunes.com/dtds/podcast-1.0.dtd',
psc: 'http://podlove.org/simple-chapters',
podcast: 'https://podcastindex.org/namespace/1.0', podcast: 'https://podcastindex.org/namespace/1.0',
googleplay: 'http://www.google.com/schemas/play-podcasts/1.0' googleplay: 'http://www.google.com/schemas/play-podcasts/1.0'
}, },
custom_elements: [ custom_elements: customElements
{ language: this.language || 'en' },
{ author: this.author || 'advplyr' },
{ 'itunes:author': this.author || 'advplyr' },
{ 'itunes:summary': this.description || '' },
{ 'itunes:type': this.podcastType },
{
'itunes:image': {
_attr: {
href: `${hostPrefix}${this.imageURL}`
}
}
},
{
'itunes:owner': [{ 'itunes:name': this.ownerName || this.author || '' }, { 'itunes:email': this.ownerEmail || '' }]
},
{ 'itunes:explicit': !!this.explicit },
...(this.preventIndexing ? blockTags : [])
]
} }
const rssfeed = new RSS(rssData) const rssfeed = new RSS(rssData)
+19 -12
View File
@@ -220,7 +220,7 @@ class FeedEpisode extends Model {
const feedEpisodeObjs = [] const feedEpisodeObjs = []
let numExisting = 0 let numExisting = 0
for (const book of books) { for (const book of books) {
const trackList = book.libraryItem.getTrackList() const trackList = book.getTracklist(book.libraryItem.id)
const useChapterTitles = this.checkUseChapterTitlesForEpisodes(trackList, book) const useChapterTitles = this.checkUseChapterTitlesForEpisodes(trackList, book)
for (const track of trackList) { for (const track of trackList) {
// Check for existing episode by filepath // Check for existing episode by filepath
@@ -305,6 +305,23 @@ class FeedEpisode extends Model {
* @param {string} hostPrefix * @param {string} hostPrefix
*/ */
getRSSData(hostPrefix) { getRSSData(hostPrefix) {
const customElements = [
{ 'itunes:author': this.author || null },
{ 'itunes:duration': Math.round(Number(this.duration)) },
{
'itunes:explicit': !!this.explicit
},
{ 'itunes:episodeType': this.episodeType || null },
{ 'itunes:season': this.season || null },
{ 'itunes:episode': this.episode || null }
].filter((element) => {
// Remove empty custom elements
return Object.values(element)[0] !== null
})
if (this.description) {
customElements.push({ 'itunes:summary': { _cdata: this.description } })
}
return { return {
title: this.title, title: this.title,
description: this.description || '', description: this.description || '',
@@ -317,17 +334,7 @@ class FeedEpisode extends Model {
type: this.enclosureType, type: this.enclosureType,
size: this.enclosureSize size: this.enclosureSize
}, },
custom_elements: [ custom_elements: customElements
{ 'itunes:author': this.author },
{ 'itunes:duration': secondsToTimestamp(this.duration) },
{ 'itunes:summary': this.description || '' },
{
'itunes:explicit': !!this.explicit
},
{ 'itunes:episodeType': this.episodeType },
{ 'itunes:season': this.season },
{ 'itunes:episode': this.episode }
]
} }
} }
} }
+1 -1
View File
@@ -65,7 +65,7 @@ class ApiRouter {
// //
// Library Routes // Library Routes
// //
this.router.get(/^\/libraries/i, this.apiCacheManager.middleware) this.router.get(/^\/libraries/, this.apiCacheManager.middleware)
this.router.post('/libraries', LibraryController.create.bind(this)) this.router.post('/libraries', LibraryController.create.bind(this))
this.router.get('/libraries', LibraryController.findAll.bind(this)) this.router.get('/libraries', LibraryController.findAll.bind(this))
this.router.get('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.findOne.bind(this)) this.router.get('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.findOne.bind(this))
+1 -1
View File
@@ -112,7 +112,7 @@ function secondsToTimestamp(seconds, includeMs = false, alwaysIncludeHours = fal
var ms = _seconds - Math.floor(seconds) var ms = _seconds - Math.floor(seconds)
_seconds = Math.floor(_seconds) _seconds = Math.floor(_seconds)
var msString = '.' + (includeMs ? ms.toFixed(3) : '0.0').split('.')[1] const msString = includeMs ? '.' + ms.toFixed(3).split('.')[1] : ''
if (alwaysIncludeHours) { if (alwaysIncludeHours) {
return `${_hours.toString().padStart(2, '0')}:${_minutes.toString().padStart(2, '0')}:${_seconds.toString().padStart(2, '0')}${msString}` return `${_hours.toString().padStart(2, '0')}:${_minutes.toString().padStart(2, '0')}:${_seconds.toString().padStart(2, '0')}${msString}`
} }