mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-12-25 21:29:37 +00:00
New model update audio player, stream, collections
This commit is contained in:
parent
2d19208340
commit
65df377a49
20 changed files with 145 additions and 145 deletions
|
|
@ -81,6 +81,7 @@ class ApiController {
|
|||
this.router.post('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.uploadCover.bind(this))
|
||||
this.router.patch('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.updateCover.bind(this))
|
||||
this.router.delete('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.removeCover.bind(this))
|
||||
this.router.get('/items/:id/stream', LibraryItemController.middleware.bind(this), LibraryItemController.openStream.bind(this))
|
||||
|
||||
//
|
||||
// Book Routes
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ class StreamManager {
|
|||
this.StreamsPath = Path.join(global.MetadataPath, 'streams')
|
||||
}
|
||||
|
||||
get audiobooks() {
|
||||
return this.db.audiobooks
|
||||
}
|
||||
|
||||
getStream(streamId) {
|
||||
return this.streams.find(s => s.id === streamId)
|
||||
}
|
||||
|
|
@ -27,12 +23,12 @@ class StreamManager {
|
|||
this.streams = this.streams.filter(s => s.id !== stream.id)
|
||||
}
|
||||
|
||||
async openStream(client, audiobook, transcodeOptions = {}) {
|
||||
async openStream(client, libraryItem, transcodeOptions = {}) {
|
||||
if (!client || !client.user) {
|
||||
Logger.error('[StreamManager] Cannot open stream invalid client', client)
|
||||
return
|
||||
}
|
||||
var stream = new Stream(this.StreamsPath, client, audiobook, transcodeOptions)
|
||||
var stream = new Stream(this.StreamsPath, client, libraryItem, transcodeOptions)
|
||||
|
||||
stream.on('closed', () => {
|
||||
this.removeStream(stream)
|
||||
|
|
@ -43,7 +39,7 @@ class StreamManager {
|
|||
await stream.generatePlaylist()
|
||||
stream.start()
|
||||
|
||||
Logger.info('Stream Opened for client', client.user.username, 'for audiobook', audiobook.title, 'with streamId', stream.id)
|
||||
Logger.info('Stream Opened for client', client.user.username, 'for item', stream.itemTitle, 'with streamId', stream.id)
|
||||
|
||||
client.stream = stream
|
||||
client.user.stream = stream.id
|
||||
|
|
@ -103,25 +99,25 @@ class StreamManager {
|
|||
}
|
||||
}
|
||||
|
||||
async openStreamApiRequest(res, user, audiobook) {
|
||||
Logger.info(`[StreamManager] User "${user.username}" open stream request for "${audiobook.title}"`)
|
||||
async openStreamApiRequest(res, user, libraryItem) {
|
||||
Logger.info(`[StreamManager] User "${user.username}" open stream request for "${libraryItem.media.metadata.title}"`)
|
||||
var client = {
|
||||
user
|
||||
}
|
||||
var stream = await this.openStream(client, audiobook)
|
||||
var stream = await this.openStream(client, libraryItem)
|
||||
this.db.updateUserStream(client.user.id, stream.id)
|
||||
|
||||
res.json({
|
||||
audiobookId: audiobook.id,
|
||||
libraryItemId: libraryItem.id,
|
||||
startTime: stream.startTime,
|
||||
streamId: stream.id,
|
||||
streamUrl: stream.clientPlaylistUri
|
||||
})
|
||||
}
|
||||
|
||||
async openStreamSocketRequest(socket, audiobookId) {
|
||||
Logger.info('[StreamManager] Open Stream Request', socket.id, audiobookId)
|
||||
var audiobook = this.audiobooks.find(ab => ab.id === audiobookId)
|
||||
async openStreamSocketRequest(socket, libraryItemId) {
|
||||
Logger.info('[StreamManager] Open Stream Request', socket.id, libraryItemId)
|
||||
var libraryItem = this.db.libraryItems.find(li => li.id === libraryItemId)
|
||||
var client = socket.sheepClient
|
||||
|
||||
if (client.stream) {
|
||||
|
|
@ -131,7 +127,7 @@ class StreamManager {
|
|||
client.stream = null
|
||||
}
|
||||
|
||||
var stream = await this.openStream(client, audiobook)
|
||||
var stream = await this.openStream(client, libraryItem)
|
||||
this.db.updateUserStream(client.user.id, stream.id)
|
||||
|
||||
this.emitter('user_stream_update', client.user.toJSONForPublic(this.streams))
|
||||
|
|
|
|||
|
|
@ -177,6 +177,11 @@ class LibraryItemController {
|
|||
return this.cacheManager.handleCoverCache(res, libraryItem, options)
|
||||
}
|
||||
|
||||
// GET: api/items/:id/stream
|
||||
openStream(req, res) {
|
||||
this.streamManager.openStreamApiRequest(res, req.user, req.libraryItem)
|
||||
}
|
||||
|
||||
middleware(req, res, next) {
|
||||
var item = this.db.libraryItems.find(li => li.id === req.params.id)
|
||||
if (!item || !item.media) return res.sendStatus(404)
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ const hlsPlaylistGenerator = require('../utils/hlsPlaylistGenerator')
|
|||
const UserListeningSession = require('./UserListeningSession')
|
||||
|
||||
class Stream extends EventEmitter {
|
||||
constructor(streamPath, client, audiobook, transcodeOptions = {}) {
|
||||
constructor(streamPath, client, libraryItem, transcodeOptions = {}) {
|
||||
super()
|
||||
|
||||
this.id = getId('str')
|
||||
this.client = client
|
||||
this.audiobook = audiobook
|
||||
this.libraryItem = libraryItem
|
||||
|
||||
this.transcodeOptions = transcodeOptions
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ class Stream extends EventEmitter {
|
|||
this.clientCurrentTime = 0
|
||||
|
||||
this.listeningSession = new UserListeningSession()
|
||||
this.listeningSession.setData(audiobook, client.user)
|
||||
this.listeningSession.setData(libraryItem, client.user)
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
|
@ -46,21 +46,21 @@ class Stream extends EventEmitter {
|
|||
return this.client ? this.client.socket || null : null
|
||||
}
|
||||
|
||||
get audiobookId() {
|
||||
return this.audiobook.id
|
||||
get libraryItemId() {
|
||||
return this.libraryItem.id
|
||||
}
|
||||
|
||||
get audiobookTitle() {
|
||||
return this.audiobook ? this.audiobook.title : null
|
||||
get itemTitle() {
|
||||
return this.libraryItem ? this.libraryItem.media.metadata.title : null
|
||||
}
|
||||
|
||||
get totalDuration() {
|
||||
return this.audiobook.duration
|
||||
return this.libraryItem.media.duration
|
||||
}
|
||||
|
||||
get tracksAudioFileType() {
|
||||
if (!this.tracks.length) return null
|
||||
return this.tracks[0].ext.toLowerCase().slice(1)
|
||||
return this.tracks[0].metadata.ext.toLowerCase().slice(1)
|
||||
}
|
||||
|
||||
// Fmp4 does not work on iOS devices: https://github.com/advplyr/audiobookshelf-app/issues/85
|
||||
|
|
@ -90,7 +90,7 @@ class Stream extends EventEmitter {
|
|||
}
|
||||
|
||||
get tracks() {
|
||||
return this.audiobook.tracks
|
||||
return this.libraryItem.media.tracks
|
||||
}
|
||||
|
||||
get clientUser() {
|
||||
|
|
@ -106,7 +106,7 @@ class Stream extends EventEmitter {
|
|||
}
|
||||
|
||||
get clientUserAudiobookData() {
|
||||
return this.client ? this.clientUserAudiobooks[this.audiobookId] : null
|
||||
return this.client ? this.clientUserAudiobooks[this.libraryItemId] : null
|
||||
}
|
||||
|
||||
get clientPlaylistUri() {
|
||||
|
|
@ -132,7 +132,7 @@ class Stream extends EventEmitter {
|
|||
id: this.id,
|
||||
clientId: this.client.id,
|
||||
userId: this.client.user.id,
|
||||
audiobook: this.audiobook.toJSONExpanded(),
|
||||
libraryItem: this.libraryItem.toJSONExpanded(),
|
||||
segmentLength: this.segmentLength,
|
||||
playlistPath: this.playlistPath,
|
||||
clientPlaylistUri: this.clientPlaylistUri,
|
||||
|
|
@ -147,7 +147,7 @@ class Stream extends EventEmitter {
|
|||
init() {
|
||||
if (this.clientUserAudiobookData) {
|
||||
var timeRemaining = this.totalDuration - this.clientUserAudiobookData.currentTime
|
||||
Logger.info('[STREAM] User has progress for audiobook', this.clientUserAudiobookData.progress, `Time Remaining: ${timeRemaining}s`)
|
||||
Logger.info('[STREAM] User has progress for item', this.clientUserAudiobookData.progress, `Time Remaining: ${timeRemaining}s`)
|
||||
if (timeRemaining > 15) {
|
||||
this.startTime = this.clientUserAudiobookData.currentTime
|
||||
this.clientCurrentTime = this.startTime
|
||||
|
|
@ -194,7 +194,7 @@ class Stream extends EventEmitter {
|
|||
return null
|
||||
}
|
||||
this.listeningSession = new UserListeningSession()
|
||||
this.listeningSession.setData(this.audiobook, this.clientUser)
|
||||
this.listeningSession.setData(this.libraryItem, this.clientUser)
|
||||
Logger.debug(`[Stream] Listening session rolled to next day`)
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +284,6 @@ class Stream extends EventEmitter {
|
|||
}
|
||||
|
||||
startLoop() {
|
||||
// Logger.info(`[Stream] ${this.audiobookTitle} (${this.id}) Start Loop`)
|
||||
if (this.socket) {
|
||||
this.socket.emit('stream_progress', { stream: this.id, chunks: [], numSegments: 0, percent: '0%' })
|
||||
}
|
||||
|
|
@ -295,7 +294,7 @@ class Stream extends EventEmitter {
|
|||
this.checkFiles()
|
||||
} else {
|
||||
if (this.socket) {
|
||||
Logger.info(`[Stream] ${this.audiobookTitle} sending stream_ready`)
|
||||
Logger.info(`[Stream] ${this.itemTitle} sending stream_ready`)
|
||||
this.socket.emit('stream_ready')
|
||||
}
|
||||
clearInterval(intervalId)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class UserAudiobookData {
|
|||
}
|
||||
|
||||
updateProgressFromStream(stream) {
|
||||
this.audiobookId = stream.audiobookId
|
||||
this.audiobookId = stream.libraryItemId
|
||||
this.totalDuration = stream.totalDuration
|
||||
this.progress = stream.clientProgress
|
||||
this.currentTime = stream.clientCurrentTime
|
||||
|
|
|
|||
|
|
@ -61,14 +61,15 @@ class UserListeningSession {
|
|||
this.startedAt = session.startedAt
|
||||
}
|
||||
|
||||
setData(audiobook, user) {
|
||||
setData(libraryItem, user) {
|
||||
this.id = getId('ls')
|
||||
this.userId = user.id
|
||||
this.audiobookId = audiobook.id
|
||||
this.audiobookTitle = audiobook.title || ''
|
||||
this.audiobookAuthor = audiobook.authorFL || ''
|
||||
this.audiobookDuration = audiobook.duration || 0
|
||||
this.audiobookGenres = [...audiobook.genres]
|
||||
this.audiobookId = libraryItem.id
|
||||
// TODO: For podcasts this needs to be generic
|
||||
this.audiobookTitle = libraryItem.media.metadata.title || ''
|
||||
this.audiobookAuthor = libraryItem.media.metadata.authorName || ''
|
||||
this.audiobookDuration = libraryItem.media.duration || 0
|
||||
this.audiobookGenres = [...libraryItem.media.metadata.genres]
|
||||
|
||||
this.timeListening = 0
|
||||
this.lastUpdate = Date.now()
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ async function writeConcatFile(tracks, outputPath, startTime = 0) {
|
|||
|
||||
var tracksToInclude = tracks.filter(t => t.index >= trackToStartWithIndex)
|
||||
var trackPaths = tracksToInclude.map(t => {
|
||||
var line = 'file ' + escapeSingleQuotes(t.fullPath) + '\n' + `duration ${t.duration}`
|
||||
var line = 'file ' + escapeSingleQuotes(t.metadata.path) + '\n' + `duration ${t.duration}`
|
||||
return line
|
||||
})
|
||||
var inputstr = trackPaths.join('\n\n')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue