mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-04 03:17:00 -05:00 
			
		
		
		
	Add:experimental generate podcast feed for testing
This commit is contained in:
		
							parent
							
								
									7373c7159b
								
							
						
					
					
						commit
						8b38dda229
					
				@ -156,6 +156,11 @@
 | 
			
		||||
            <ui-tooltip v-if="isPodcast && userIsAdminOrUp" text="Find Episodes" direction="top">
 | 
			
		||||
              <ui-icon-btn icon="search" class="mx-0.5" :loading="fetchingRSSFeed" outlined @click="findEpisodesClick" />
 | 
			
		||||
            </ui-tooltip>
 | 
			
		||||
 | 
			
		||||
            <!-- Experimental RSS feed open -->
 | 
			
		||||
            <ui-tooltip v-if="isPodcast && showExperimentalFeatures" text="Open RSS Feed" direction="top">
 | 
			
		||||
              <ui-icon-btn icon="rss_feed" class="mx-0.5" outlined @click="openRSSFeed" />
 | 
			
		||||
            </ui-tooltip>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="my-4 max-w-2xl">
 | 
			
		||||
@ -478,6 +483,22 @@ export default {
 | 
			
		||||
      this.$store.commit('setSelectedLibraryItem', this.libraryItem)
 | 
			
		||||
      this.$store.commit('globals/setShowUserCollectionsModal', true)
 | 
			
		||||
    },
 | 
			
		||||
    openRSSFeed() {
 | 
			
		||||
      const payload = {
 | 
			
		||||
        serverAddress: window.origin
 | 
			
		||||
      }
 | 
			
		||||
      if (this.$isDev) payload.serverAddress = 'http://localhost:3333'
 | 
			
		||||
 | 
			
		||||
      console.log('Payload', payload)
 | 
			
		||||
      this.$axios
 | 
			
		||||
        .$post(`/api/podcasts/${this.libraryItemId}/open-feed`, payload)
 | 
			
		||||
        .then((data) => {
 | 
			
		||||
          console.log('Opened RSS Feed', data)
 | 
			
		||||
        })
 | 
			
		||||
        .catch((error) => {
 | 
			
		||||
          console.error('Failed to open RSS Feed', error)
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
    episodeDownloadQueued(episodeDownload) {
 | 
			
		||||
      if (episodeDownload.libraryItemId === this.libraryItemId) {
 | 
			
		||||
        this.episodeDownloadsQueued.push(episodeDownload)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										84
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										84
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -1,12 +1,11 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "audiobookshelf",
 | 
			
		||||
  "version": "1.7.3",
 | 
			
		||||
  "version": "2.0.8",
 | 
			
		||||
  "lockfileVersion": 2,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "packages": {
 | 
			
		||||
    "": {
 | 
			
		||||
      "name": "audiobookshelf",
 | 
			
		||||
      "version": "1.7.3",
 | 
			
		||||
      "version": "2.0.8",
 | 
			
		||||
      "license": "GPL-3.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "archiver": "^5.3.0",
 | 
			
		||||
@ -26,6 +25,7 @@
 | 
			
		||||
        "node-cron": "^3.0.0",
 | 
			
		||||
        "node-ffprobe": "^3.0.0",
 | 
			
		||||
        "node-stream-zip": "^1.15.0",
 | 
			
		||||
        "podcast": "^2.0.0",
 | 
			
		||||
        "proper-lockfile": "^4.1.2",
 | 
			
		||||
        "read-chunk": "^3.1.0",
 | 
			
		||||
        "recursive-readdir-async": "^1.1.8",
 | 
			
		||||
@ -1477,6 +1477,14 @@
 | 
			
		||||
        "node": ">=6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/podcast": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/podcast/-/podcast-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-1NZe7cVabfkcMe39yOOhBMJrXC6OROLOIBkfEPayiJL59ncyJmOeO5bxolSCSGroho8jQ0zURMczyICI1U/xbw==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "rss": "^1.2.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/process-nextick-args": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 | 
			
		||||
@ -1675,6 +1683,34 @@
 | 
			
		||||
        "atomically": "^1.7.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/rss": {
 | 
			
		||||
      "version": "1.2.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz",
 | 
			
		||||
      "integrity": "sha1-UKFpiHYTgTOnT5oF0r3I240nqSE=",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-types": "2.1.13",
 | 
			
		||||
        "xml": "1.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/rss/node_modules/mime-db": {
 | 
			
		||||
      "version": "1.25.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
 | 
			
		||||
      "integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I=",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/rss/node_modules/mime-types": {
 | 
			
		||||
      "version": "2.1.13",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
 | 
			
		||||
      "integrity": "sha1-4HqqnGxrmnyjASxpADrSWjnpKog=",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": "~1.25.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/safe-buffer": {
 | 
			
		||||
      "version": "5.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
 | 
			
		||||
@ -2071,6 +2107,11 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/xml": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/xml2js": {
 | 
			
		||||
      "version": "0.4.23",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
 | 
			
		||||
@ -3222,6 +3263,14 @@
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
 | 
			
		||||
    },
 | 
			
		||||
    "podcast": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/podcast/-/podcast-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-1NZe7cVabfkcMe39yOOhBMJrXC6OROLOIBkfEPayiJL59ncyJmOeO5bxolSCSGroho8jQ0zURMczyICI1U/xbw==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "rss": "^1.2.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "process-nextick-args": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 | 
			
		||||
@ -3387,6 +3436,30 @@
 | 
			
		||||
        "atomically": "^1.7.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "rss": {
 | 
			
		||||
      "version": "1.2.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz",
 | 
			
		||||
      "integrity": "sha1-UKFpiHYTgTOnT5oF0r3I240nqSE=",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "mime-types": "2.1.13",
 | 
			
		||||
        "xml": "1.0.1"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": {
 | 
			
		||||
          "version": "1.25.0",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
 | 
			
		||||
          "integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I="
 | 
			
		||||
        },
 | 
			
		||||
        "mime-types": {
 | 
			
		||||
          "version": "2.1.13",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
 | 
			
		||||
          "integrity": "sha1-4HqqnGxrmnyjASxpADrSWjnpKog=",
 | 
			
		||||
          "requires": {
 | 
			
		||||
            "mime-db": "~1.25.0"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "safe-buffer": {
 | 
			
		||||
      "version": "5.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
 | 
			
		||||
@ -3690,6 +3763,11 @@
 | 
			
		||||
      "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
 | 
			
		||||
      "requires": {}
 | 
			
		||||
    },
 | 
			
		||||
    "xml": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
 | 
			
		||||
    },
 | 
			
		||||
    "xml2js": {
 | 
			
		||||
      "version": "0.4.23",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,7 @@
 | 
			
		||||
    "node-cron": "^3.0.0",
 | 
			
		||||
    "node-ffprobe": "^3.0.0",
 | 
			
		||||
    "node-stream-zip": "^1.15.0",
 | 
			
		||||
    "podcast": "^2.0.0",
 | 
			
		||||
    "proper-lockfile": "^4.1.2",
 | 
			
		||||
    "read-chunk": "^3.1.0",
 | 
			
		||||
    "recursive-readdir-async": "^1.1.8",
 | 
			
		||||
 | 
			
		||||
@ -1,59 +0,0 @@
 | 
			
		||||
// const Podcast = require('podcast')
 | 
			
		||||
const express = require('express')
 | 
			
		||||
// const ip = require('ip')
 | 
			
		||||
const Logger = require('./Logger')
 | 
			
		||||
 | 
			
		||||
// Not functional at the moment - just an idea
 | 
			
		||||
class RssFeeds {
 | 
			
		||||
  constructor(Port, db) {
 | 
			
		||||
    this.Port = Port
 | 
			
		||||
    this.db = db
 | 
			
		||||
    this.feeds = {}
 | 
			
		||||
 | 
			
		||||
    this.router = express()
 | 
			
		||||
    this.init()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init() {
 | 
			
		||||
    this.router.get('/:id', this.getFeed.bind(this))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFeed(req, res) {
 | 
			
		||||
    Logger.info('Get Feed', req.params.id, this.feeds[req.params.id])
 | 
			
		||||
 | 
			
		||||
    var feed = this.feeds[req.params.id]
 | 
			
		||||
    if (!feed) return null
 | 
			
		||||
    var xml = feed.buildXml()
 | 
			
		||||
    res.set('Content-Type', 'text/xml')
 | 
			
		||||
    res.send(xml)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  openFeed(audiobook) {
 | 
			
		||||
    // Removed Podcast npm package and ip package
 | 
			
		||||
    return null
 | 
			
		||||
    // var ipAddress = ip.address('public', 'ipv4')
 | 
			
		||||
    // var serverAddress = 'http://' + ipAddress + ':' + this.Port
 | 
			
		||||
    // Logger.info('Open RSS Feed', 'Server address', serverAddress)
 | 
			
		||||
 | 
			
		||||
    // var feedId = (Date.now() + Math.floor(Math.random() * 1000)).toString(36)
 | 
			
		||||
    // const feed = new Podcast({
 | 
			
		||||
    //   title: audiobook.title,
 | 
			
		||||
    //   description: 'AudioBookshelf RSS Feed',
 | 
			
		||||
    //   feed_url: `${serverAddress}/feeds/${feedId}`,
 | 
			
		||||
    //   image_url: `${serverAddress}/Logo.png`,
 | 
			
		||||
    //   author: 'advplyr',
 | 
			
		||||
    //   language: 'en'
 | 
			
		||||
    // })
 | 
			
		||||
    // audiobook.tracks.forEach((track) => {
 | 
			
		||||
    //   feed.addItem({
 | 
			
		||||
    //     title: `Track ${track.index}`,
 | 
			
		||||
    //     description: `AudioBookshelf Audiobook Track #${track.index}`,
 | 
			
		||||
    //     url: `${serverAddress}/feeds/${feedId}?track=${track.index}`,
 | 
			
		||||
    //     author: 'advplyr'
 | 
			
		||||
    //   })
 | 
			
		||||
    // })
 | 
			
		||||
    // this.feeds[feedId] = feed
 | 
			
		||||
    // return feed
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
module.exports = RssFeeds
 | 
			
		||||
@ -31,6 +31,7 @@ const BackupManager = require('./managers/BackupManager')
 | 
			
		||||
const PlaybackSessionManager = require('./managers/PlaybackSessionManager')
 | 
			
		||||
const PodcastManager = require('./managers/PodcastManager')
 | 
			
		||||
const AudioMetadataMangaer = require('./managers/AudioMetadataManager')
 | 
			
		||||
const RssFeedManager = require('./managers/RssFeedManager')
 | 
			
		||||
 | 
			
		||||
class Server {
 | 
			
		||||
  constructor(PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH) {
 | 
			
		||||
@ -74,11 +75,12 @@ class Server {
 | 
			
		||||
    this.coverManager = new CoverManager(this.db, this.cacheManager)
 | 
			
		||||
    this.podcastManager = new PodcastManager(this.db, this.watcher, this.emitter.bind(this))
 | 
			
		||||
    this.audioMetadataManager = new AudioMetadataMangaer(this.db, this.emitter.bind(this), this.clientEmitter.bind(this))
 | 
			
		||||
    this.rssFeedManager = new RssFeedManager(this.db)
 | 
			
		||||
 | 
			
		||||
    this.scanner = new Scanner(this.db, this.coverManager, this.emitter.bind(this))
 | 
			
		||||
 | 
			
		||||
    // Routers
 | 
			
		||||
    this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.abMergeManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.audioMetadataManager, this.emitter.bind(this), this.clientEmitter.bind(this))
 | 
			
		||||
    this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.abMergeManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.audioMetadataManager, this.rssFeedManager, this.emitter.bind(this), this.clientEmitter.bind(this))
 | 
			
		||||
    this.hlsRouter = new HlsRouter(this.db, this.auth, this.playbackSessionManager, this.emitter.bind(this))
 | 
			
		||||
    this.staticRouter = new StaticRouter(this.db)
 | 
			
		||||
 | 
			
		||||
@ -198,6 +200,16 @@ class Server {
 | 
			
		||||
      res.sendFile(fullPath)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    // RSS Feed temp route
 | 
			
		||||
    app.get('/feed/:id', (req, res) => {
 | 
			
		||||
      Logger.info(`[Server] requesting rss feed ${req.params.id}`)
 | 
			
		||||
      this.rssFeedManager.getFeed(req, res)
 | 
			
		||||
    })
 | 
			
		||||
    app.get('/feed/:id/item/*', (req, res) => {
 | 
			
		||||
      Logger.info(`[Server] requesting rss feed ${req.params.id}`)
 | 
			
		||||
      this.rssFeedManager.getFeedItem(req, res)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    // Client dynamic routes
 | 
			
		||||
    app.get('/item/:id', (req, res) => res.sendFile(Path.join(distPath, 'index.html')))
 | 
			
		||||
    app.get('/audiobook/:id/edit', (req, res) => res.sendFile(Path.join(distPath, 'index.html')))
 | 
			
		||||
 | 
			
		||||
@ -120,14 +120,7 @@ class PodcastController {
 | 
			
		||||
      return res.sendStatus(500)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var libraryItem = this.db.getLibraryItem(req.params.id)
 | 
			
		||||
    if (!libraryItem || libraryItem.mediaType !== 'podcast') {
 | 
			
		||||
      return res.sendStatus(404)
 | 
			
		||||
    }
 | 
			
		||||
    if (!req.user.checkCanAccessLibrary(libraryItem.libraryId)) {
 | 
			
		||||
      Logger.error(`[PodcastController] User attempted to check/download episodes for a library without permission`, req.user)
 | 
			
		||||
      return res.sendStatus(500)
 | 
			
		||||
    }
 | 
			
		||||
    var libraryItem = req.libraryItem
 | 
			
		||||
    if (!libraryItem.media.metadata.feedUrl) {
 | 
			
		||||
      Logger.error(`[PodcastController] checkNewEpisodes no feed url for item ${libraryItem.id}`)
 | 
			
		||||
      return res.status(500).send('Podcast has no rss feed url')
 | 
			
		||||
@ -149,10 +142,8 @@ class PodcastController {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getEpisodeDownloads(req, res) {
 | 
			
		||||
    var libraryItem = this.db.getLibraryItem(req.params.id)
 | 
			
		||||
    if (!libraryItem || libraryItem.mediaType !== 'podcast') {
 | 
			
		||||
      return res.sendStatus(404)
 | 
			
		||||
    }
 | 
			
		||||
    var libraryItem = req.libraryItem
 | 
			
		||||
 | 
			
		||||
    var downloadsInQueue = this.podcastManager.getEpisodeDownloadsInQueue(libraryItem.id)
 | 
			
		||||
    res.json({
 | 
			
		||||
      downloads: downloadsInQueue.map(d => d.toJSONForClient())
 | 
			
		||||
@ -164,15 +155,7 @@ class PodcastController {
 | 
			
		||||
      Logger.error(`[PodcastController] Non-admin user attempted to download episodes`, req.user)
 | 
			
		||||
      return res.sendStatus(500)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var libraryItem = this.db.getLibraryItem(req.params.id)
 | 
			
		||||
    if (!libraryItem || libraryItem.mediaType !== 'podcast') {
 | 
			
		||||
      return res.sendStatus(404)
 | 
			
		||||
    }
 | 
			
		||||
    if (!req.user.checkCanAccessLibrary(libraryItem.libraryId)) {
 | 
			
		||||
      Logger.error(`[PodcastController] User attempted to download episodes for library without permission`, req.user)
 | 
			
		||||
      return res.sendStatus(404)
 | 
			
		||||
    }
 | 
			
		||||
    var libraryItem = req.libraryItem
 | 
			
		||||
 | 
			
		||||
    var episodes = req.body
 | 
			
		||||
    if (!episodes || !episodes.length) {
 | 
			
		||||
@ -183,14 +166,22 @@ class PodcastController {
 | 
			
		||||
    res.sendStatus(200)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async openPodcastFeed(req, res) {
 | 
			
		||||
    if (!req.user.isAdminOrUp) {
 | 
			
		||||
      Logger.error(`[PodcastController] Non-admin user attempted to open podcast feed`, req.user)
 | 
			
		||||
      return res.sendStatus(500)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const feedData = this.rssFeedManager.openPodcastFeed(req.user, req.libraryItem, req.body)
 | 
			
		||||
 | 
			
		||||
    res.json({
 | 
			
		||||
      success: true,
 | 
			
		||||
      feedUrl: feedData.feedUrl
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updateEpisode(req, res) {
 | 
			
		||||
    var libraryItem = this.db.getLibraryItem(req.params.id)
 | 
			
		||||
    if (!libraryItem || libraryItem.mediaType !== 'podcast') {
 | 
			
		||||
      return res.sendStatus(404)
 | 
			
		||||
    }
 | 
			
		||||
    if (!req.user.canUpload || !req.user.checkCanAccessLibrary(libraryItem.libraryId)) {
 | 
			
		||||
      return res.sendStatus(404)
 | 
			
		||||
    }
 | 
			
		||||
    var libraryItem = req.libraryItem
 | 
			
		||||
 | 
			
		||||
    var episodeId = req.params.episodeId
 | 
			
		||||
    if (!libraryItem.media.checkHasEpisode(episodeId)) {
 | 
			
		||||
@ -205,5 +196,35 @@ class PodcastController {
 | 
			
		||||
 | 
			
		||||
    res.json(libraryItem.toJSONExpanded())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  middleware(req, res, next) {
 | 
			
		||||
    var item = this.db.libraryItems.find(li => li.id === req.params.id)
 | 
			
		||||
    if (!item || !item.media) return res.sendStatus(404)
 | 
			
		||||
 | 
			
		||||
    if (!item.isPodcast) {
 | 
			
		||||
      return res.sendStatus(500)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check user can access this library
 | 
			
		||||
    if (!req.user.checkCanAccessLibrary(item.libraryId)) {
 | 
			
		||||
      return res.sendStatus(403)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check user can access this library item
 | 
			
		||||
    if (!req.user.checkCanAccessLibraryItemWithTags(item.media.tags)) {
 | 
			
		||||
      return res.sendStatus(403)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (req.method == 'DELETE' && !req.user.canDelete) {
 | 
			
		||||
      Logger.warn(`[PodcastController] User attempted to delete without permission`, req.user.username)
 | 
			
		||||
      return res.sendStatus(403)
 | 
			
		||||
    } else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
 | 
			
		||||
      Logger.warn('[PodcastController] User attempted to update without permission', req.user.username)
 | 
			
		||||
      return res.sendStatus(403)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    req.libraryItem = item
 | 
			
		||||
    next()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
module.exports = new PodcastController()
 | 
			
		||||
							
								
								
									
										87
									
								
								server/managers/RssFeedManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								server/managers/RssFeedManager.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
			
		||||
const Path = require('path')
 | 
			
		||||
const { Podcast } = require('podcast')
 | 
			
		||||
const { getId } = require('../utils/index')
 | 
			
		||||
const Logger = require('../Logger')
 | 
			
		||||
 | 
			
		||||
// Not functional at the moment
 | 
			
		||||
class RssFeedManager {
 | 
			
		||||
  constructor(db) {
 | 
			
		||||
    this.db = db
 | 
			
		||||
    this.feeds = {}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFeed(req, res) {
 | 
			
		||||
    var feedData = this.feeds[req.params.id]
 | 
			
		||||
    if (!feedData) {
 | 
			
		||||
      Logger.error(`[RssFeedManager] Feed not found ${req.params.id}`)
 | 
			
		||||
      res.sendStatus(404)
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    var xml = feedData.feed.buildXml()
 | 
			
		||||
    res.set('Content-Type', 'text/xml')
 | 
			
		||||
    res.send(xml)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFeedItem(req, res) {
 | 
			
		||||
    var feedData = this.feeds[req.params.id]
 | 
			
		||||
    if (!feedData) {
 | 
			
		||||
      Logger.error(`[RssFeedManager] Feed not found ${req.params.id}`)
 | 
			
		||||
      res.sendStatus(404)
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    var remainingPath = req.params['0']
 | 
			
		||||
    var fullPath = Path.join(feedData.libraryItemPath, remainingPath)
 | 
			
		||||
    res.sendFile(fullPath)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  openFeed(feedId, libraryItem, serverAddress) {
 | 
			
		||||
    const podcast = libraryItem.media
 | 
			
		||||
 | 
			
		||||
    const feedUrl = `${serverAddress}/feed/${feedId}`
 | 
			
		||||
    // Removed Podcast npm package and ip package
 | 
			
		||||
    const feed = new Podcast({
 | 
			
		||||
      title: podcast.metadata.title,
 | 
			
		||||
      description: podcast.metadata.description,
 | 
			
		||||
      feedUrl,
 | 
			
		||||
      imageUrl: `${serverAddress}/Logo.png`,
 | 
			
		||||
      author: podcast.metadata.author || 'advplyr',
 | 
			
		||||
      language: 'en'
 | 
			
		||||
    })
 | 
			
		||||
    podcast.episodes.forEach((episode) => {
 | 
			
		||||
      var contentUrl = episode.audioTrack.contentUrl.replace(/\\/g, '/')
 | 
			
		||||
      contentUrl = contentUrl.replace(`/s/item/${libraryItem.id}`, `/feed/${feedId}/item`)
 | 
			
		||||
 | 
			
		||||
      feed.addItem({
 | 
			
		||||
        title: episode.title,
 | 
			
		||||
        description: episode.description || '',
 | 
			
		||||
        enclosure: {
 | 
			
		||||
          url: `${serverAddress}${contentUrl}`,
 | 
			
		||||
          type: episode.audioTrack.mimeType,
 | 
			
		||||
          size: episode.size
 | 
			
		||||
        },
 | 
			
		||||
        url: `${serverAddress}${contentUrl}`,
 | 
			
		||||
        author: podcast.metadata.author || 'advplyr'
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    const feedData = {
 | 
			
		||||
      id: feedId,
 | 
			
		||||
      libraryItemId: libraryItem.id,
 | 
			
		||||
      libraryItemPath: libraryItem.path,
 | 
			
		||||
      serverAddress: serverAddress,
 | 
			
		||||
      feedUrl,
 | 
			
		||||
      feed
 | 
			
		||||
    }
 | 
			
		||||
    this.feeds[feedId] = feedData
 | 
			
		||||
    return feedData
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  openPodcastFeed(user, libraryItem, options) {
 | 
			
		||||
    const serverAddress = options.serverAddress
 | 
			
		||||
    const feedId = getId('feed')
 | 
			
		||||
    const feedData = this.openFeed(feedId, libraryItem, serverAddress)
 | 
			
		||||
    Logger.debug(`[RssFeedManager] Opened podcast feed ${feedData.feedUrl}`)
 | 
			
		||||
    return feedData
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
module.exports = RssFeedManager
 | 
			
		||||
@ -25,7 +25,7 @@ const Series = require('../objects/entities/Series')
 | 
			
		||||
const FileSystemController = require('../controllers/FileSystemController')
 | 
			
		||||
 | 
			
		||||
class ApiRouter {
 | 
			
		||||
  constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, emitter, clientEmitter) {
 | 
			
		||||
  constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, rssFeedManager, emitter, clientEmitter) {
 | 
			
		||||
    this.db = db
 | 
			
		||||
    this.auth = auth
 | 
			
		||||
    this.scanner = scanner
 | 
			
		||||
@ -37,6 +37,7 @@ class ApiRouter {
 | 
			
		||||
    this.cacheManager = cacheManager
 | 
			
		||||
    this.podcastManager = podcastManager
 | 
			
		||||
    this.audioMetadataManager = audioMetadataManager
 | 
			
		||||
    this.rssFeedManager = rssFeedManager
 | 
			
		||||
    this.emitter = emitter
 | 
			
		||||
    this.clientEmitter = clientEmitter
 | 
			
		||||
 | 
			
		||||
@ -180,11 +181,12 @@ class ApiRouter {
 | 
			
		||||
    //
 | 
			
		||||
    this.router.post('/podcasts', PodcastController.create.bind(this))
 | 
			
		||||
    this.router.post('/podcasts/feed', PodcastController.getPodcastFeed.bind(this))
 | 
			
		||||
    this.router.get('/podcasts/:id/checknew', PodcastController.checkNewEpisodes.bind(this))
 | 
			
		||||
    this.router.get('/podcasts/:id/downloads', PodcastController.getEpisodeDownloads.bind(this))
 | 
			
		||||
    this.router.get('/podcasts/:id/clear-queue', PodcastController.clearEpisodeDownloadQueue.bind(this))
 | 
			
		||||
    this.router.post('/podcasts/:id/download-episodes', PodcastController.downloadEpisodes.bind(this))
 | 
			
		||||
    this.router.patch('/podcasts/:id/episode/:episodeId', PodcastController.updateEpisode.bind(this))
 | 
			
		||||
    this.router.get('/podcasts/:id/checknew', PodcastController.middleware.bind(this), PodcastController.checkNewEpisodes.bind(this))
 | 
			
		||||
    this.router.get('/podcasts/:id/downloads', PodcastController.middleware.bind(this), PodcastController.getEpisodeDownloads.bind(this))
 | 
			
		||||
    this.router.get('/podcasts/:id/clear-queue', PodcastController.middleware.bind(this), PodcastController.clearEpisodeDownloadQueue.bind(this))
 | 
			
		||||
    this.router.post('/podcasts/:id/download-episodes', PodcastController.middleware.bind(this), PodcastController.downloadEpisodes.bind(this))
 | 
			
		||||
    this.router.post('/podcasts/:id/open-feed', PodcastController.middleware.bind(this), PodcastController.openPodcastFeed.bind(this))
 | 
			
		||||
    this.router.patch('/podcasts/:id/episode/:episodeId', PodcastController.middleware.bind(this), PodcastController.updateEpisode.bind(this))
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Misc Routes
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user