New model update audio player, stream, collections

This commit is contained in:
advplyr 2022-03-12 19:59:35 -06:00
parent 2d19208340
commit 65df377a49
20 changed files with 145 additions and 145 deletions

View file

@ -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

View file

@ -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))

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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()

View file

@ -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')