mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Remove serverAddress from Feeds and FeedEpisodes URLs
This commit is contained in:
		
							parent
							
								
									3b4a5b8785
								
							
						
					
					
						commit
						9b8e059efe
					
				@ -10,9 +10,9 @@
 | 
				
			|||||||
        <p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
 | 
					        <p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="w-full relative">
 | 
					        <div class="w-full relative">
 | 
				
			||||||
          <ui-text-input v-model="currentFeed.feedUrl" readonly />
 | 
					          <ui-text-input :value="feedUrl" readonly />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(currentFeed.feedUrl)">content_copy</span>
 | 
					          <span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feedUrl)">content_copy</span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div v-if="currentFeed.meta" class="mt-5">
 | 
					        <div v-if="currentFeed.meta" class="mt-5">
 | 
				
			||||||
@ -111,8 +111,11 @@ export default {
 | 
				
			|||||||
    userIsAdminOrUp() {
 | 
					    userIsAdminOrUp() {
 | 
				
			||||||
      return this.$store.getters['user/getIsAdminOrUp']
 | 
					      return this.$store.getters['user/getIsAdminOrUp']
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    feedUrl() {
 | 
				
			||||||
 | 
					      return this.currentFeed ? `${window.origin}${this.$config.routerBasePath}${this.currentFeed.feedUrl}` : ''
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    demoFeedUrl() {
 | 
					    demoFeedUrl() {
 | 
				
			||||||
      return `${window.origin}/feed/${this.newFeedSlug}`
 | 
					      return `${window.origin}${this.$config.routerBasePath}/feed/${this.newFeedSlug}`
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    isHttp() {
 | 
					    isHttp() {
 | 
				
			||||||
      return window.origin.startsWith('http://')
 | 
					      return window.origin.startsWith('http://')
 | 
				
			||||||
 | 
				
			|||||||
@ -5,8 +5,8 @@
 | 
				
			|||||||
        <p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
 | 
					        <p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="w-full relative">
 | 
					        <div class="w-full relative">
 | 
				
			||||||
          <ui-text-input v-model="feed.feedUrl" readonly />
 | 
					          <ui-text-input :value="feedUrl" readonly />
 | 
				
			||||||
          <span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feed.feedUrl)">content_copy</span>
 | 
					          <span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feedUrl)">content_copy</span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div v-if="feed.meta" class="mt-5">
 | 
					        <div v-if="feed.meta" class="mt-5">
 | 
				
			||||||
@ -70,6 +70,9 @@ export default {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    _feed() {
 | 
					    _feed() {
 | 
				
			||||||
      return this.feed || {}
 | 
					      return this.feed || {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    feedUrl() {
 | 
				
			||||||
 | 
					      return this.feed ? `${window.origin}${this.$config.routerBasePath}${this.feed.feedUrl}` : ''
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
 | 
				
			|||||||
@ -126,7 +126,7 @@ export default {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    coverUrl(feed) {
 | 
					    coverUrl(feed) {
 | 
				
			||||||
      if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
 | 
					      if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
 | 
				
			||||||
      return `${feed.feedUrl}/cover`
 | 
					      return `${this.$config.routerBasePath}${feed.feedUrl}/cover`
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    async loadFeeds() {
 | 
					    async loadFeeds() {
 | 
				
			||||||
      const data = await this.$axios.$get(`/api/feeds`).catch((err) => {
 | 
					      const data = await this.$axios.$get(`/api/feeds`).catch((err) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -253,6 +253,10 @@ class Server {
 | 
				
			|||||||
    // if RouterBasePath is set, modify all requests to include the base path
 | 
					    // if RouterBasePath is set, modify all requests to include the base path
 | 
				
			||||||
    if (global.RouterBasePath) {
 | 
					    if (global.RouterBasePath) {
 | 
				
			||||||
      app.use((req, res, next) => {
 | 
					      app.use((req, res, next) => {
 | 
				
			||||||
 | 
					        const host = req.get('host')
 | 
				
			||||||
 | 
					        const protocol = req.secure || req.get('x-forwarded-proto') === 'https' ? 'https' : 'http'
 | 
				
			||||||
 | 
					        const prefix = req.url.startsWith(global.RouterBasePath) ? global.RouterBasePath : ''
 | 
				
			||||||
 | 
					        req.originalHostPrefix = `${protocol}://${host}${prefix}`
 | 
				
			||||||
        if (!req.url.startsWith(global.RouterBasePath)) {
 | 
					        if (!req.url.startsWith(global.RouterBasePath)) {
 | 
				
			||||||
          req.url = `${global.RouterBasePath}${req.url}`
 | 
					          req.url = `${global.RouterBasePath}${req.url}`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -162,7 +162,7 @@ class RssFeedManager {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const xml = feed.buildXml()
 | 
					    const xml = feed.buildXml(req.originalHostPrefix)
 | 
				
			||||||
    res.set('Content-Type', 'text/xml')
 | 
					    res.set('Content-Type', 'text/xml')
 | 
				
			||||||
    res.send(xml)
 | 
					    res.send(xml)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										74
									
								
								server/migrations/v2.17.5-remove-host-from-feed-urls.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								server/migrations/v2.17.5-remove-host-from-feed-urls.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @typedef MigrationContext
 | 
				
			||||||
 | 
					 * @property {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object.
 | 
				
			||||||
 | 
					 * @property {import('../Logger')} logger - a Logger object.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @typedef MigrationOptions
 | 
				
			||||||
 | 
					 * @property {MigrationContext} context - an object containing the migration context.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const migrationVersion = '2.17.5'
 | 
				
			||||||
 | 
					const migrationName = `${migrationVersion}-remove-host-from-feed-urls`
 | 
				
			||||||
 | 
					const loggerPrefix = `[${migrationVersion} migration]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This upward migration removes the host (serverAddress) from URL columns in the feeds and feedEpisodes tables.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {MigrationOptions} options - an object containing the migration context.
 | 
				
			||||||
 | 
					 * @returns {Promise<void>} - A promise that resolves when the migration is complete.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function up({ context: { queryInterface, logger } }) {
 | 
				
			||||||
 | 
					  // Upwards migration script
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} UPGRADE BEGIN: ${migrationName}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Removing serverAddress from Feeds table URLs`)
 | 
				
			||||||
 | 
					  await queryInterface.sequelize.query(`
 | 
				
			||||||
 | 
					    UPDATE Feeds
 | 
				
			||||||
 | 
					    SET feedUrl = REPLACE(feedUrl, COALESCE(serverAddress, ''), ''),
 | 
				
			||||||
 | 
					        imageUrl = REPLACE(imageUrl, COALESCE(serverAddress, ''), ''),
 | 
				
			||||||
 | 
					        siteUrl = REPLACE(siteUrl, COALESCE(serverAddress, ''), '');
 | 
				
			||||||
 | 
					  `)
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Removed serverAddress from Feeds table URLs`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Removing serverAddress from FeedEpisodes table URLs`)
 | 
				
			||||||
 | 
					  await queryInterface.sequelize.query(`
 | 
				
			||||||
 | 
					    UPDATE FeedEpisodes
 | 
				
			||||||
 | 
					      SET siteUrl = REPLACE(siteUrl, (SELECT COALESCE(serverAddress, '') FROM Feeds WHERE Feeds.id = FeedEpisodes.feedId), ''),
 | 
				
			||||||
 | 
					          enclosureUrl = REPLACE(enclosureUrl, (SELECT COALESCE(serverAddress, '') FROM Feeds WHERE Feeds.id = FeedEpisodes.feedId), '');
 | 
				
			||||||
 | 
					  `)
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Removed serverAddress from FeedEpisodes table URLs`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} UPGRADE END: ${migrationName}`)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This downward migration script adds the host (serverAddress) back to URL columns in the feeds and feedEpisodes tables.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {MigrationOptions} options - an object containing the migration context.
 | 
				
			||||||
 | 
					 * @returns {Promise<void>} - A promise that resolves when the migration is complete.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function down({ context: { queryInterface, logger } }) {
 | 
				
			||||||
 | 
					  // Downward migration script
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} DOWNGRADE BEGIN: ${migrationName}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Adding serverAddress back to Feeds table URLs`)
 | 
				
			||||||
 | 
					  await queryInterface.sequelize.query(`
 | 
				
			||||||
 | 
					    UPDATE Feeds
 | 
				
			||||||
 | 
					    SET feedUrl = COALESCE(serverAddress, '') || feedUrl,
 | 
				
			||||||
 | 
					        imageUrl = COALESCE(serverAddress, '') || imageUrl,
 | 
				
			||||||
 | 
					        siteUrl = COALESCE(serverAddress, '') || siteUrl;
 | 
				
			||||||
 | 
					  `)
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Added serverAddress back to Feeds table URLs`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Adding serverAddress back to FeedEpisodes table URLs`)
 | 
				
			||||||
 | 
					  await queryInterface.sequelize.query(`
 | 
				
			||||||
 | 
					    UPDATE FeedEpisodes
 | 
				
			||||||
 | 
					      SET siteUrl = (SELECT COALESCE(serverAddress, '') || FeedEpisodes.siteUrl FROM Feeds WHERE Feeds.id = FeedEpisodes.feedId),
 | 
				
			||||||
 | 
					          enclosureUrl = (SELECT COALESCE(serverAddress, '') || FeedEpisodes.enclosureUrl FROM Feeds WHERE Feeds.id = FeedEpisodes.feedId);
 | 
				
			||||||
 | 
					  `)
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} Added serverAddress back to FeedEpisodes table URLs`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logger.info(`${loggerPrefix} DOWNGRADE END: ${migrationName}`)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = { up, down }
 | 
				
			||||||
@ -109,7 +109,7 @@ class Feed {
 | 
				
			|||||||
    const mediaMetadata = media.metadata
 | 
					    const mediaMetadata = media.metadata
 | 
				
			||||||
    const isPodcast = libraryItem.mediaType === 'podcast'
 | 
					    const isPodcast = libraryItem.mediaType === 'podcast'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const feedUrl = `${serverAddress}/feed/${slug}`
 | 
					    const feedUrl = `/feed/${slug}`
 | 
				
			||||||
    const author = isPodcast ? mediaMetadata.author : mediaMetadata.authorName
 | 
					    const author = isPodcast ? mediaMetadata.author : mediaMetadata.authorName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.id = uuidv4()
 | 
					    this.id = uuidv4()
 | 
				
			||||||
@ -128,9 +128,9 @@ class Feed {
 | 
				
			|||||||
    this.meta.title = mediaMetadata.title
 | 
					    this.meta.title = mediaMetadata.title
 | 
				
			||||||
    this.meta.description = mediaMetadata.description
 | 
					    this.meta.description = mediaMetadata.description
 | 
				
			||||||
    this.meta.author = author
 | 
					    this.meta.author = author
 | 
				
			||||||
    this.meta.imageUrl = media.coverPath ? `${serverAddress}/feed/${slug}/cover${coverFileExtension}` : `${serverAddress}/Logo.png`
 | 
					    this.meta.imageUrl = media.coverPath ? `/feed/${slug}/cover${coverFileExtension}` : `/Logo.png`
 | 
				
			||||||
    this.meta.feedUrl = feedUrl
 | 
					    this.meta.feedUrl = feedUrl
 | 
				
			||||||
    this.meta.link = `${serverAddress}/item/${libraryItem.id}`
 | 
					    this.meta.link = `/item/${libraryItem.id}`
 | 
				
			||||||
    this.meta.explicit = !!mediaMetadata.explicit
 | 
					    this.meta.explicit = !!mediaMetadata.explicit
 | 
				
			||||||
    this.meta.type = mediaMetadata.type
 | 
					    this.meta.type = mediaMetadata.type
 | 
				
			||||||
    this.meta.language = mediaMetadata.language
 | 
					    this.meta.language = mediaMetadata.language
 | 
				
			||||||
@ -176,7 +176,7 @@ class Feed {
 | 
				
			|||||||
    this.meta.title = mediaMetadata.title
 | 
					    this.meta.title = mediaMetadata.title
 | 
				
			||||||
    this.meta.description = mediaMetadata.description
 | 
					    this.meta.description = mediaMetadata.description
 | 
				
			||||||
    this.meta.author = author
 | 
					    this.meta.author = author
 | 
				
			||||||
    this.meta.imageUrl = media.coverPath ? `${this.serverAddress}/feed/${this.slug}/cover${coverFileExtension}` : `${this.serverAddress}/Logo.png`
 | 
					    this.meta.imageUrl = media.coverPath ? `/feed/${this.slug}/cover${coverFileExtension}` : `/Logo.png`
 | 
				
			||||||
    this.meta.explicit = !!mediaMetadata.explicit
 | 
					    this.meta.explicit = !!mediaMetadata.explicit
 | 
				
			||||||
    this.meta.type = mediaMetadata.type
 | 
					    this.meta.type = mediaMetadata.type
 | 
				
			||||||
    this.meta.language = mediaMetadata.language
 | 
					    this.meta.language = mediaMetadata.language
 | 
				
			||||||
@ -206,7 +206,7 @@ class Feed {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setFromCollection(userId, slug, collectionExpanded, serverAddress, preventIndexing = true, ownerName = null, ownerEmail = null) {
 | 
					  setFromCollection(userId, slug, collectionExpanded, serverAddress, preventIndexing = true, ownerName = null, ownerEmail = null) {
 | 
				
			||||||
    const feedUrl = `${serverAddress}/feed/${slug}`
 | 
					    const feedUrl = `/feed/${slug}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const itemsWithTracks = collectionExpanded.books.filter((libraryItem) => libraryItem.media.tracks.length)
 | 
					    const itemsWithTracks = collectionExpanded.books.filter((libraryItem) => libraryItem.media.tracks.length)
 | 
				
			||||||
    const firstItemWithCover = itemsWithTracks.find((item) => item.media.coverPath)
 | 
					    const firstItemWithCover = itemsWithTracks.find((item) => item.media.coverPath)
 | 
				
			||||||
@ -227,9 +227,9 @@ class Feed {
 | 
				
			|||||||
    this.meta.title = collectionExpanded.name
 | 
					    this.meta.title = collectionExpanded.name
 | 
				
			||||||
    this.meta.description = collectionExpanded.description || ''
 | 
					    this.meta.description = collectionExpanded.description || ''
 | 
				
			||||||
    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
					    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
				
			||||||
    this.meta.imageUrl = this.coverPath ? `${serverAddress}/feed/${slug}/cover${coverFileExtension}` : `${serverAddress}/Logo.png`
 | 
					    this.meta.imageUrl = this.coverPath ? `/feed/${slug}/cover${coverFileExtension}` : `/Logo.png`
 | 
				
			||||||
    this.meta.feedUrl = feedUrl
 | 
					    this.meta.feedUrl = feedUrl
 | 
				
			||||||
    this.meta.link = `${serverAddress}/collection/${collectionExpanded.id}`
 | 
					    this.meta.link = `/collection/${collectionExpanded.id}`
 | 
				
			||||||
    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
					    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
				
			||||||
    this.meta.preventIndexing = preventIndexing
 | 
					    this.meta.preventIndexing = preventIndexing
 | 
				
			||||||
    this.meta.ownerName = ownerName
 | 
					    this.meta.ownerName = ownerName
 | 
				
			||||||
@ -272,7 +272,7 @@ class Feed {
 | 
				
			|||||||
    this.meta.title = collectionExpanded.name
 | 
					    this.meta.title = collectionExpanded.name
 | 
				
			||||||
    this.meta.description = collectionExpanded.description || ''
 | 
					    this.meta.description = collectionExpanded.description || ''
 | 
				
			||||||
    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
					    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
				
			||||||
    this.meta.imageUrl = this.coverPath ? `${this.serverAddress}/feed/${this.slug}/cover${coverFileExtension}` : `${this.serverAddress}/Logo.png`
 | 
					    this.meta.imageUrl = this.coverPath ? `/feed/${this.slug}/cover${coverFileExtension}` : `/Logo.png`
 | 
				
			||||||
    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
					    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.episodes = []
 | 
					    this.episodes = []
 | 
				
			||||||
@ -301,7 +301,7 @@ class Feed {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setFromSeries(userId, slug, seriesExpanded, serverAddress, preventIndexing = true, ownerName = null, ownerEmail = null) {
 | 
					  setFromSeries(userId, slug, seriesExpanded, serverAddress, preventIndexing = true, ownerName = null, ownerEmail = null) {
 | 
				
			||||||
    const feedUrl = `${serverAddress}/feed/${slug}`
 | 
					    const feedUrl = `/feed/${slug}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let itemsWithTracks = seriesExpanded.books.filter((libraryItem) => libraryItem.media.tracks.length)
 | 
					    let itemsWithTracks = seriesExpanded.books.filter((libraryItem) => libraryItem.media.tracks.length)
 | 
				
			||||||
    // Sort series items by series sequence
 | 
					    // Sort series items by series sequence
 | 
				
			||||||
@ -326,9 +326,9 @@ class Feed {
 | 
				
			|||||||
    this.meta.title = seriesExpanded.name
 | 
					    this.meta.title = seriesExpanded.name
 | 
				
			||||||
    this.meta.description = seriesExpanded.description || ''
 | 
					    this.meta.description = seriesExpanded.description || ''
 | 
				
			||||||
    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
					    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
				
			||||||
    this.meta.imageUrl = this.coverPath ? `${serverAddress}/feed/${slug}/cover${coverFileExtension}` : `${serverAddress}/Logo.png`
 | 
					    this.meta.imageUrl = this.coverPath ? `/feed/${slug}/cover${coverFileExtension}` : `/Logo.png`
 | 
				
			||||||
    this.meta.feedUrl = feedUrl
 | 
					    this.meta.feedUrl = feedUrl
 | 
				
			||||||
    this.meta.link = `${serverAddress}/library/${libraryId}/series/${seriesExpanded.id}`
 | 
					    this.meta.link = `/library/${libraryId}/series/${seriesExpanded.id}`
 | 
				
			||||||
    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
					    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
				
			||||||
    this.meta.preventIndexing = preventIndexing
 | 
					    this.meta.preventIndexing = preventIndexing
 | 
				
			||||||
    this.meta.ownerName = ownerName
 | 
					    this.meta.ownerName = ownerName
 | 
				
			||||||
@ -374,7 +374,7 @@ class Feed {
 | 
				
			|||||||
    this.meta.title = seriesExpanded.name
 | 
					    this.meta.title = seriesExpanded.name
 | 
				
			||||||
    this.meta.description = seriesExpanded.description || ''
 | 
					    this.meta.description = seriesExpanded.description || ''
 | 
				
			||||||
    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
					    this.meta.author = this.getAuthorsStringFromLibraryItems(itemsWithTracks)
 | 
				
			||||||
    this.meta.imageUrl = this.coverPath ? `${this.serverAddress}/feed/${this.slug}/cover${coverFileExtension}` : `${this.serverAddress}/Logo.png`
 | 
					    this.meta.imageUrl = this.coverPath ? `/feed/${this.slug}/cover${coverFileExtension}` : `/Logo.png`
 | 
				
			||||||
    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
					    this.meta.explicit = !!itemsWithTracks.some((li) => li.media.metadata.explicit) // explicit if any item is explicit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.episodes = []
 | 
					    this.episodes = []
 | 
				
			||||||
@ -402,12 +402,12 @@ class Feed {
 | 
				
			|||||||
    this.xml = null
 | 
					    this.xml = null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  buildXml() {
 | 
					  buildXml(originalHostPrefix) {
 | 
				
			||||||
    if (this.xml) return this.xml
 | 
					    if (this.xml) return this.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var rssfeed = new RSS(this.meta.getRSSData())
 | 
					    var rssfeed = new RSS(this.meta.getRSSData(originalHostPrefix))
 | 
				
			||||||
    this.episodes.forEach((ep) => {
 | 
					    this.episodes.forEach((ep) => {
 | 
				
			||||||
      rssfeed.item(ep.getRSSData())
 | 
					      rssfeed.item(ep.getRSSData(originalHostPrefix))
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    this.xml = rssfeed.xml()
 | 
					    this.xml = rssfeed.xml()
 | 
				
			||||||
    return this.xml
 | 
					    return this.xml
 | 
				
			||||||
 | 
				
			|||||||
@ -79,7 +79,7 @@ class FeedEpisode {
 | 
				
			|||||||
    this.title = episode.title
 | 
					    this.title = episode.title
 | 
				
			||||||
    this.description = episode.description || ''
 | 
					    this.description = episode.description || ''
 | 
				
			||||||
    this.enclosure = {
 | 
					    this.enclosure = {
 | 
				
			||||||
      url: `${serverAddress}${contentUrl}`,
 | 
					      url: `${contentUrl}`,
 | 
				
			||||||
      type: episode.audioTrack.mimeType,
 | 
					      type: episode.audioTrack.mimeType,
 | 
				
			||||||
      size: episode.size
 | 
					      size: episode.size
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -136,7 +136,7 @@ class FeedEpisode {
 | 
				
			|||||||
    this.title = title
 | 
					    this.title = title
 | 
				
			||||||
    this.description = mediaMetadata.description || ''
 | 
					    this.description = mediaMetadata.description || ''
 | 
				
			||||||
    this.enclosure = {
 | 
					    this.enclosure = {
 | 
				
			||||||
      url: `${serverAddress}${contentUrl}`,
 | 
					      url: `${contentUrl}`,
 | 
				
			||||||
      type: audioTrack.mimeType,
 | 
					      type: audioTrack.mimeType,
 | 
				
			||||||
      size: audioTrack.metadata.size
 | 
					      size: audioTrack.metadata.size
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -151,15 +151,19 @@ class FeedEpisode {
 | 
				
			|||||||
    this.fullPath = audioTrack.metadata.path
 | 
					    this.fullPath = audioTrack.metadata.path
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getRSSData() {
 | 
					  getRSSData(hostPrefix) {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      title: this.title,
 | 
					      title: this.title,
 | 
				
			||||||
      description: this.description || '',
 | 
					      description: this.description || '',
 | 
				
			||||||
      url: this.link,
 | 
					      url: `${hostPrefix}${this.link}`,
 | 
				
			||||||
      guid: this.enclosure.url,
 | 
					      guid: `${hostPrefix}${this.enclosure.url}`,
 | 
				
			||||||
      author: this.author,
 | 
					      author: this.author,
 | 
				
			||||||
      date: this.pubDate,
 | 
					      date: this.pubDate,
 | 
				
			||||||
      enclosure: this.enclosure,
 | 
					      enclosure: {
 | 
				
			||||||
 | 
					        url: `${hostPrefix}${this.enclosure.url}`,
 | 
				
			||||||
 | 
					        type: this.enclosure.type,
 | 
				
			||||||
 | 
					        size: this.enclosure.size
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      custom_elements: [
 | 
					      custom_elements: [
 | 
				
			||||||
        { 'itunes:author': this.author },
 | 
					        { 'itunes:author': this.author },
 | 
				
			||||||
        { 'itunes:duration': secondsToTimestamp(this.duration) },
 | 
					        { 'itunes:duration': secondsToTimestamp(this.duration) },
 | 
				
			||||||
 | 
				
			|||||||
@ -60,42 +60,36 @@ class FeedMeta {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getRSSData() {
 | 
					  getRSSData(hostPrefix) {
 | 
				
			||||||
    const blockTags = [
 | 
					    const blockTags = [{ 'itunes:block': 'yes' }, { 'googleplay:block': 'yes' }]
 | 
				
			||||||
      { 'itunes:block': 'yes' },
 | 
					 | 
				
			||||||
      { 'googleplay:block': 'yes' }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      title: this.title,
 | 
					      title: this.title,
 | 
				
			||||||
      description: this.description || '',
 | 
					      description: this.description || '',
 | 
				
			||||||
      generator: 'Audiobookshelf',
 | 
					      generator: 'Audiobookshelf',
 | 
				
			||||||
      feed_url: this.feedUrl,
 | 
					      feed_url: `${hostPrefix}${this.feedUrl}`,
 | 
				
			||||||
      site_url: this.link,
 | 
					      site_url: `${hostPrefix}${this.link}`,
 | 
				
			||||||
      image_url: 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',
 | 
					        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: [
 | 
				
			||||||
        { 'language': this.language || 'en' },
 | 
					        { language: this.language || 'en' },
 | 
				
			||||||
        { 'author': this.author || 'advplyr' },
 | 
					        { author: this.author || 'advplyr' },
 | 
				
			||||||
        { 'itunes:author': this.author || 'advplyr' },
 | 
					        { 'itunes:author': this.author || 'advplyr' },
 | 
				
			||||||
        { 'itunes:summary': this.description || '' },
 | 
					        { 'itunes:summary': this.description || '' },
 | 
				
			||||||
        { 'itunes:type': this.type },
 | 
					        { 'itunes:type': this.type },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          'itunes:image': {
 | 
					          'itunes:image': {
 | 
				
			||||||
            _attr: {
 | 
					            _attr: {
 | 
				
			||||||
              href: this.imageUrl
 | 
					              href: `${hostPrefix}${this.imageUrl}`
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          'itunes:owner': [
 | 
					          'itunes:owner': [{ 'itunes:name': this.ownerName || this.author || '' }, { 'itunes:email': this.ownerEmail || '' }]
 | 
				
			||||||
            { 'itunes:name': this.ownerName || this.author || '' },
 | 
					 | 
				
			||||||
            { 'itunes:email': this.ownerEmail || '' }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        { 'itunes:explicit': !!this.explicit },
 | 
					        { 'itunes:explicit': !!this.explicit },
 | 
				
			||||||
        ...(this.preventIndexing ? blockTags : [])
 | 
					        ...(this.preventIndexing ? blockTags : [])
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,202 @@
 | 
				
			|||||||
 | 
					const { expect } = require('chai')
 | 
				
			||||||
 | 
					const sinon = require('sinon')
 | 
				
			||||||
 | 
					const { up, down } = require('../../../server/migrations/v2.17.5-remove-host-from-feed-urls')
 | 
				
			||||||
 | 
					const { Sequelize, DataTypes } = require('sequelize')
 | 
				
			||||||
 | 
					const Logger = require('../../../server/Logger')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const defineModels = (sequelize) => {
 | 
				
			||||||
 | 
					  const Feeds = sequelize.define('Feeds', {
 | 
				
			||||||
 | 
					    id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4 },
 | 
				
			||||||
 | 
					    feedUrl: { type: DataTypes.STRING },
 | 
				
			||||||
 | 
					    imageUrl: { type: DataTypes.STRING },
 | 
				
			||||||
 | 
					    siteUrl: { type: DataTypes.STRING },
 | 
				
			||||||
 | 
					    serverAddress: { type: DataTypes.STRING }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const FeedEpisodes = sequelize.define('FeedEpisodes', {
 | 
				
			||||||
 | 
					    id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4 },
 | 
				
			||||||
 | 
					    feedId: { type: DataTypes.UUID },
 | 
				
			||||||
 | 
					    siteUrl: { type: DataTypes.STRING },
 | 
				
			||||||
 | 
					    enclosureUrl: { type: DataTypes.STRING }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { Feeds, FeedEpisodes }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('Migration v2.17.4-use-subfolder-for-oidc-redirect-uris', () => {
 | 
				
			||||||
 | 
					  let queryInterface, logger, context
 | 
				
			||||||
 | 
					  let sequelize
 | 
				
			||||||
 | 
					  let Feeds, FeedEpisodes
 | 
				
			||||||
 | 
					  const feed1Id = '00000000-0000-4000-a000-000000000001'
 | 
				
			||||||
 | 
					  const feed2Id = '00000000-0000-4000-a000-000000000002'
 | 
				
			||||||
 | 
					  const feedEpisode1Id = '00000000-4000-a000-0000-000000000011'
 | 
				
			||||||
 | 
					  const feedEpisode2Id = '00000000-4000-a000-0000-000000000012'
 | 
				
			||||||
 | 
					  const feedEpisode3Id = '00000000-4000-a000-0000-000000000021'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  before(async () => {
 | 
				
			||||||
 | 
					    sequelize = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
 | 
				
			||||||
 | 
					    queryInterface = sequelize.getQueryInterface()
 | 
				
			||||||
 | 
					    ;({ Feeds, FeedEpisodes } = defineModels(sequelize))
 | 
				
			||||||
 | 
					    await sequelize.sync()
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  after(async () => {
 | 
				
			||||||
 | 
					    await sequelize.close()
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    // Reset tables before each test
 | 
				
			||||||
 | 
					    await Feeds.destroy({ where: {}, truncate: true })
 | 
				
			||||||
 | 
					    await FeedEpisodes.destroy({ where: {}, truncate: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    logger = {
 | 
				
			||||||
 | 
					      info: sinon.stub(),
 | 
				
			||||||
 | 
					      error: sinon.stub()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    context = { queryInterface, logger }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('up', () => {
 | 
				
			||||||
 | 
					    it('should remove serverAddress from URLs in Feeds and FeedEpisodes tables', async () => {
 | 
				
			||||||
 | 
					      await Feeds.bulkCreate([
 | 
				
			||||||
 | 
					        { id: feed1Id, feedUrl: 'http://server1.com/feed1', imageUrl: 'http://server1.com/img1', siteUrl: 'http://server1.com/site1', serverAddress: 'http://server1.com' },
 | 
				
			||||||
 | 
					        { id: feed2Id, feedUrl: 'http://server2.com/feed2', imageUrl: 'http://server2.com/img2', siteUrl: 'http://server2.com/site2', serverAddress: 'http://server2.com' }
 | 
				
			||||||
 | 
					      ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await FeedEpisodes.bulkCreate([
 | 
				
			||||||
 | 
					        { id: feedEpisode1Id, feedId: feed1Id, siteUrl: 'http://server1.com/episode11', enclosureUrl: 'http://server1.com/enclosure11' },
 | 
				
			||||||
 | 
					        { id: feedEpisode2Id, feedId: feed1Id, siteUrl: 'http://server1.com/episode12', enclosureUrl: 'http://server1.com/enclosure12' },
 | 
				
			||||||
 | 
					        { id: feedEpisode3Id, feedId: feed2Id, siteUrl: 'http://server2.com/episode21', enclosureUrl: 'http://server2.com/enclosure21' }
 | 
				
			||||||
 | 
					      ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await up({ context })
 | 
				
			||||||
 | 
					      const feeds = await Feeds.findAll({ raw: true })
 | 
				
			||||||
 | 
					      const feedEpisodes = await FeedEpisodes.findAll({ raw: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] UPGRADE BEGIN: 2.17.5-remove-host-from-feed-urls')).to.be.true
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Removing serverAddress from Feeds table URLs')).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feeds[0].feedUrl).to.equal('/feed1')
 | 
				
			||||||
 | 
					      expect(feeds[0].imageUrl).to.equal('/img1')
 | 
				
			||||||
 | 
					      expect(feeds[0].siteUrl).to.equal('/site1')
 | 
				
			||||||
 | 
					      expect(feeds[1].feedUrl).to.equal('/feed2')
 | 
				
			||||||
 | 
					      expect(feeds[1].imageUrl).to.equal('/img2')
 | 
				
			||||||
 | 
					      expect(feeds[1].siteUrl).to.equal('/site2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Removed serverAddress from Feeds table URLs')).to.be.true
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Removing serverAddress from FeedEpisodes table URLs')).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].siteUrl).to.equal('/episode11')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].enclosureUrl).to.equal('/enclosure11')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[1].siteUrl).to.equal('/episode12')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[1].enclosureUrl).to.equal('/enclosure12')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[2].siteUrl).to.equal('/episode21')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[2].enclosureUrl).to.equal('/enclosure21')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Removed serverAddress from FeedEpisodes table URLs')).to.be.true
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] UPGRADE END: 2.17.5-remove-host-from-feed-urls')).to.be.true
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should handle null URLs in Feeds and FeedEpisodes tables', async () => {
 | 
				
			||||||
 | 
					      await Feeds.bulkCreate([{ id: feed1Id, feedUrl: 'http://server1.com/feed1', imageUrl: null, siteUrl: 'http://server1.com/site1', serverAddress: 'http://server1.com' }])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await FeedEpisodes.bulkCreate([{ id: feedEpisode1Id, feedId: feed1Id, siteUrl: null, enclosureUrl: 'http://server1.com/enclosure11' }])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await up({ context })
 | 
				
			||||||
 | 
					      const feeds = await Feeds.findAll({ raw: true })
 | 
				
			||||||
 | 
					      const feedEpisodes = await FeedEpisodes.findAll({ raw: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feeds[0].feedUrl).to.equal('/feed1')
 | 
				
			||||||
 | 
					      expect(feeds[0].imageUrl).to.be.null
 | 
				
			||||||
 | 
					      expect(feeds[0].siteUrl).to.equal('/site1')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].siteUrl).to.be.null
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].enclosureUrl).to.equal('/enclosure11')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should handle null serverAddress in Feeds table', async () => {
 | 
				
			||||||
 | 
					      await Feeds.bulkCreate([{ id: feed1Id, feedUrl: 'http://server1.com/feed1', imageUrl: 'http://server1.com/img1', siteUrl: 'http://server1.com/site1', serverAddress: null }])
 | 
				
			||||||
 | 
					      await FeedEpisodes.bulkCreate([{ id: feedEpisode1Id, feedId: feed1Id, siteUrl: 'http://server1.com/episode11', enclosureUrl: 'http://server1.com/enclosure11' }])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await up({ context })
 | 
				
			||||||
 | 
					      const feeds = await Feeds.findAll({ raw: true })
 | 
				
			||||||
 | 
					      const feedEpisodes = await FeedEpisodes.findAll({ raw: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feeds[0].feedUrl).to.equal('http://server1.com/feed1')
 | 
				
			||||||
 | 
					      expect(feeds[0].imageUrl).to.equal('http://server1.com/img1')
 | 
				
			||||||
 | 
					      expect(feeds[0].siteUrl).to.equal('http://server1.com/site1')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].siteUrl).to.equal('http://server1.com/episode11')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].enclosureUrl).to.equal('http://server1.com/enclosure11')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('down', () => {
 | 
				
			||||||
 | 
					    it('should add serverAddress back to URLs in Feeds and FeedEpisodes tables', async () => {
 | 
				
			||||||
 | 
					      await Feeds.bulkCreate([
 | 
				
			||||||
 | 
					        { id: feed1Id, feedUrl: '/feed1', imageUrl: '/img1', siteUrl: '/site1', serverAddress: 'http://server1.com' },
 | 
				
			||||||
 | 
					        { id: feed2Id, feedUrl: '/feed2', imageUrl: '/img2', siteUrl: '/site2', serverAddress: 'http://server2.com' }
 | 
				
			||||||
 | 
					      ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await FeedEpisodes.bulkCreate([
 | 
				
			||||||
 | 
					        { id: feedEpisode1Id, feedId: feed1Id, siteUrl: '/episode11', enclosureUrl: '/enclosure11' },
 | 
				
			||||||
 | 
					        { id: feedEpisode2Id, feedId: feed1Id, siteUrl: '/episode12', enclosureUrl: '/enclosure12' },
 | 
				
			||||||
 | 
					        { id: feedEpisode3Id, feedId: feed2Id, siteUrl: '/episode21', enclosureUrl: '/enclosure21' }
 | 
				
			||||||
 | 
					      ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await down({ context })
 | 
				
			||||||
 | 
					      const feeds = await Feeds.findAll({ raw: true })
 | 
				
			||||||
 | 
					      const feedEpisodes = await FeedEpisodes.findAll({ raw: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] DOWNGRADE BEGIN: 2.17.5-remove-host-from-feed-urls')).to.be.true
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Adding serverAddress back to Feeds table URLs')).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feeds[0].feedUrl).to.equal('http://server1.com/feed1')
 | 
				
			||||||
 | 
					      expect(feeds[0].imageUrl).to.equal('http://server1.com/img1')
 | 
				
			||||||
 | 
					      expect(feeds[0].siteUrl).to.equal('http://server1.com/site1')
 | 
				
			||||||
 | 
					      expect(feeds[1].feedUrl).to.equal('http://server2.com/feed2')
 | 
				
			||||||
 | 
					      expect(feeds[1].imageUrl).to.equal('http://server2.com/img2')
 | 
				
			||||||
 | 
					      expect(feeds[1].siteUrl).to.equal('http://server2.com/site2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Added serverAddress back to Feeds table URLs')).to.be.true
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] Adding serverAddress back to FeedEpisodes table URLs')).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].siteUrl).to.equal('http://server1.com/episode11')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].enclosureUrl).to.equal('http://server1.com/enclosure11')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[1].siteUrl).to.equal('http://server1.com/episode12')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[1].enclosureUrl).to.equal('http://server1.com/enclosure12')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[2].siteUrl).to.equal('http://server2.com/episode21')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[2].enclosureUrl).to.equal('http://server2.com/enclosure21')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(logger.info.calledWith('[2.17.5 migration] DOWNGRADE END: 2.17.5-remove-host-from-feed-urls')).to.be.true
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should handle null URLs in Feeds and FeedEpisodes tables', async () => {
 | 
				
			||||||
 | 
					      await Feeds.bulkCreate([{ id: feed1Id, feedUrl: '/feed1', imageUrl: null, siteUrl: '/site1', serverAddress: 'http://server1.com' }])
 | 
				
			||||||
 | 
					      await FeedEpisodes.bulkCreate([{ id: feedEpisode1Id, feedId: feed1Id, siteUrl: null, enclosureUrl: '/enclosure11' }])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await down({ context })
 | 
				
			||||||
 | 
					      const feeds = await Feeds.findAll({ raw: true })
 | 
				
			||||||
 | 
					      const feedEpisodes = await FeedEpisodes.findAll({ raw: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feeds[0].feedUrl).to.equal('http://server1.com/feed1')
 | 
				
			||||||
 | 
					      expect(feeds[0].imageUrl).to.be.null
 | 
				
			||||||
 | 
					      expect(feeds[0].siteUrl).to.equal('http://server1.com/site1')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].siteUrl).to.be.null
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].enclosureUrl).to.equal('http://server1.com/enclosure11')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should handle null serverAddress in Feeds table', async () => {
 | 
				
			||||||
 | 
					      await Feeds.bulkCreate([{ id: feed1Id, feedUrl: '/feed1', imageUrl: '/img1', siteUrl: '/site1', serverAddress: null }])
 | 
				
			||||||
 | 
					      await FeedEpisodes.bulkCreate([{ id: feedEpisode1Id, feedId: feed1Id, siteUrl: '/episode11', enclosureUrl: '/enclosure11' }])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await down({ context })
 | 
				
			||||||
 | 
					      const feeds = await Feeds.findAll({ raw: true })
 | 
				
			||||||
 | 
					      const feedEpisodes = await FeedEpisodes.findAll({ raw: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(feeds[0].feedUrl).to.equal('/feed1')
 | 
				
			||||||
 | 
					      expect(feeds[0].imageUrl).to.equal('/img1')
 | 
				
			||||||
 | 
					      expect(feeds[0].siteUrl).to.equal('/site1')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].siteUrl).to.equal('/episode11')
 | 
				
			||||||
 | 
					      expect(feedEpisodes[0].enclosureUrl).to.equal('/enclosure11')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user