mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-01 19:07:02 -04:00 
			
		
		
		
	Merge pull request #4263 from advplyr/new_session_track_endpoint
Add new api endpoint for direct playing audio files using session id
This commit is contained in:
		
						commit
						1afb8840db
					
				| @ -1,5 +1,5 @@ | ||||
| export default class AudioTrack { | ||||
|   constructor(track, userToken, routerBasePath) { | ||||
|   constructor(track, sessionId, userToken, routerBasePath) { | ||||
|     this.index = track.index || 0 | ||||
|     this.startOffset = track.startOffset || 0 // Total time of all previous tracks
 | ||||
|     this.duration = track.duration || 0 | ||||
| @ -8,28 +8,29 @@ export default class AudioTrack { | ||||
|     this.mimeType = track.mimeType | ||||
|     this.metadata = track.metadata || {} | ||||
| 
 | ||||
|     this.userToken = userToken | ||||
|     this.sessionId = sessionId | ||||
|     this.routerBasePath = routerBasePath || '' | ||||
|     if (this.contentUrl?.startsWith('/hls')) { | ||||
|       this.sessionTrackUrl = `${this.contentUrl}?token=${userToken}` | ||||
|     } else { | ||||
|       this.sessionTrackUrl = `/public/session/${sessionId}/track/${this.index}` | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Used for CastPlayer | ||||
|    */ | ||||
|   get fullContentUrl() { | ||||
|     if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl | ||||
| 
 | ||||
|     if (process.env.NODE_ENV === 'development') { | ||||
|       return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}` | ||||
|       return `${process.env.serverUrl}${this.sessionTrackUrl}` | ||||
|     } | ||||
|     return `${window.location.origin}${this.routerBasePath}${this.contentUrl}?token=${this.userToken}` | ||||
|     return `${window.location.origin}${this.routerBasePath}${this.sessionTrackUrl}` | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Used for LocalPlayer | ||||
|    */ | ||||
|   get relativeContentUrl() { | ||||
|     if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl | ||||
| 
 | ||||
|     return `${this.routerBasePath}${this.contentUrl}?token=${this.userToken}` | ||||
|     return `${this.routerBasePath}${this.sessionTrackUrl}` | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -226,7 +226,7 @@ export default class PlayerHandler { | ||||
| 
 | ||||
|     console.log('[PlayerHandler] Preparing Session', session) | ||||
| 
 | ||||
|     var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken, this.ctx.$config.routerBasePath)) | ||||
|     var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, session.id, this.userToken, this.ctx.$config.routerBasePath)) | ||||
| 
 | ||||
|     this.ctx.playerLoading = true | ||||
|     this.isHlsTranscode = true | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| const Path = require('path') | ||||
| const { Request, Response, NextFunction } = require('express') | ||||
| const Logger = require('../Logger') | ||||
| const Database = require('../Database') | ||||
| const { toNumber, isUUID } = require('../utils/index') | ||||
| const { getAudioMimeTypeFromExtname, encodeUriPath } = require('../utils/fileUtils') | ||||
| 
 | ||||
| const ShareManager = require('../managers/ShareManager') | ||||
| 
 | ||||
| @ -266,6 +268,51 @@ class SessionController { | ||||
|     this.playbackSessionManager.syncLocalSessionsRequest(req, res) | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * GET: /public/session/:id/track/:index | ||||
|    * While a session is open, this endpoint can be used to stream the audio track | ||||
|    * | ||||
|    * @this {import('../routers/PublicRouter')} | ||||
|    * | ||||
|    * @param {Request} req | ||||
|    * @param {Response} res | ||||
|    */ | ||||
|   async getTrack(req, res) { | ||||
|     const audioTrackIndex = toNumber(req.params.index, null) | ||||
|     if (audioTrackIndex === null) { | ||||
|       Logger.error(`[SessionController] Invalid audio track index "${req.params.index}"`) | ||||
|       return res.sendStatus(400) | ||||
|     } | ||||
| 
 | ||||
|     const playbackSession = this.playbackSessionManager.getSession(req.params.id) | ||||
|     if (!playbackSession) { | ||||
|       Logger.error(`[SessionController] Unable to find playback session with id=${req.params.id}`) | ||||
|       return res.sendStatus(404) | ||||
|     } | ||||
| 
 | ||||
|     const audioTrack = playbackSession.audioTracks.find((t) => t.index === audioTrackIndex) | ||||
|     if (!audioTrack) { | ||||
|       Logger.error(`[SessionController] Unable to find audio track with index=${audioTrackIndex}`) | ||||
|       return res.sendStatus(404) | ||||
|     } | ||||
| 
 | ||||
|     const user = await Database.userModel.getUserById(playbackSession.userId) | ||||
|     Logger.debug(`[SessionController] Serving audio track ${audioTrack.index} for session "${req.params.id}" belonging to user "${user.username}"`) | ||||
| 
 | ||||
|     if (global.XAccel) { | ||||
|       const encodedURI = encodeUriPath(global.XAccel + audioTrack.metadata.path) | ||||
|       Logger.debug(`Use X-Accel to serve static file ${encodedURI}`) | ||||
|       return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send() | ||||
|     } | ||||
| 
 | ||||
|     // Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
 | ||||
|     const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(audioTrack.metadata.path)) | ||||
|     if (audioMimeType) { | ||||
|       res.setHeader('Content-Type', audioMimeType) | ||||
|     } | ||||
|     res.sendFile(audioTrack.metadata.path) | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * | ||||
|    * @param {RequestWithUser} req | ||||
|  | ||||
| @ -26,6 +26,12 @@ class PlaybackSessionManager { | ||||
|     this.sessions = [] | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Get open session by id | ||||
|    * | ||||
|    * @param {string} sessionId | ||||
|    * @returns {PlaybackSession} | ||||
|    */ | ||||
|   getSession(sessionId) { | ||||
|     return this.sessions.find((s) => s.id === sessionId) | ||||
|   } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| const express = require('express') | ||||
| const ShareController = require('../controllers/ShareController') | ||||
| const SessionController = require('../controllers/SessionController') | ||||
| 
 | ||||
| class PublicRouter { | ||||
|   constructor(playbackSessionManager) { | ||||
| @ -17,6 +18,7 @@ class PublicRouter { | ||||
|     this.router.get('/share/:slug/cover', ShareController.getMediaItemShareCoverImage.bind(this)) | ||||
|     this.router.get('/share/:slug/download', ShareController.downloadMediaItemShare.bind(this)) | ||||
|     this.router.patch('/share/:slug/progress', ShareController.updateMediaItemShareProgress.bind(this)) | ||||
|     this.router.get('/session/:id/track/:index', SessionController.getTrack.bind(this)) | ||||
|   } | ||||
| } | ||||
| module.exports = PublicRouter | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user