mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-08 21:14:47 +02:00
Merge branch 'advplyr:master' into stream-sync
This commit is contained in:
commit
ad823ca486
6 changed files with 134 additions and 47 deletions
66
Server.js
66
Server.js
|
@ -16,6 +16,8 @@ class Server extends EventEmitter {
|
|||
this.connected = false
|
||||
|
||||
this.stream = null
|
||||
|
||||
this.isConnectingSocket = false
|
||||
}
|
||||
|
||||
get token() {
|
||||
|
@ -60,6 +62,10 @@ class Server extends EventEmitter {
|
|||
}
|
||||
|
||||
async connect(url, token) {
|
||||
if (this.connected) {
|
||||
console.warn('[SOCKET] Connection already established for ' + this.url)
|
||||
return true
|
||||
}
|
||||
if (!url) {
|
||||
console.error('Invalid url to connect')
|
||||
return false
|
||||
|
@ -151,38 +157,84 @@ class Server extends EventEmitter {
|
|||
}
|
||||
|
||||
connectSocket() {
|
||||
console.log('[SERVER] Connect Socket', this.url)
|
||||
if (this.connected || this.socket) {
|
||||
if (this.socket) console.error('[SOCKET] Socket already established', this.url)
|
||||
else console.error('[SOCKET] Already connected to socket', this.url)
|
||||
return
|
||||
}
|
||||
|
||||
this.socket = io(this.url)
|
||||
console.log('[SOCKET] Connect Socket', this.url)
|
||||
|
||||
const socketOptions = {
|
||||
transports: ['websocket'],
|
||||
upgrade: false,
|
||||
// reconnectionAttempts: 3
|
||||
}
|
||||
this.socket = io(this.url, socketOptions)
|
||||
this.socket.on('connect', () => {
|
||||
console.log('[Server] Socket Connected')
|
||||
console.log('[SOCKET] Socket Connected ' + this.socket.id)
|
||||
|
||||
// Authenticate socket with token
|
||||
this.socket.emit('auth', this.token)
|
||||
|
||||
this.connected = true
|
||||
this.emit('connected', true)
|
||||
this.store.commit('setSocketConnected', true)
|
||||
})
|
||||
this.socket.on('disconnect', () => {
|
||||
console.log('[Server] Socket Disconnected')
|
||||
this.socket.on('disconnect', (reason) => {
|
||||
console.log('[SOCKET] Socket Disconnected: ' + reason)
|
||||
this.connected = false
|
||||
this.emit('connected', false)
|
||||
this.store.commit('setSocketConnected', false)
|
||||
|
||||
// this.socket.removeAllListeners()
|
||||
// if (this.socket.io && this.socket.io.removeAllListeners) {
|
||||
// console.log(`[SOCKET] Removing ALL IO listeners`)
|
||||
// this.socket.io.removeAllListeners()
|
||||
// }
|
||||
})
|
||||
this.socket.on('init', (data) => {
|
||||
console.log('[Server] Initial socket data received', data)
|
||||
console.log('[SOCKET] Initial socket data received', data)
|
||||
if (data.stream) {
|
||||
this.stream = data.stream
|
||||
this.store.commit('setStreamAudiobook', data.stream.audiobook)
|
||||
this.emit('initialStream', data.stream)
|
||||
}
|
||||
})
|
||||
|
||||
this.socket.on('user_updated', (user) => {
|
||||
if (this.user && user.id === this.user.id) {
|
||||
this.setUser(user)
|
||||
}
|
||||
})
|
||||
|
||||
this.socket.on('current_user_audiobook_update', (payload) => {
|
||||
this.emit('currentUserAudiobookUpdate', payload)
|
||||
})
|
||||
|
||||
this.socket.onAny((evt, args) => {
|
||||
console.log(`[SOCKET] ${this.socket.id}: ${evt} ${JSON.stringify(args)}`)
|
||||
})
|
||||
|
||||
this.socket.on('connect_error', (err) => {
|
||||
console.error('[SOCKET] connection failed', err)
|
||||
this.emit('socketConnectionFailed', err)
|
||||
})
|
||||
|
||||
this.socket.io.on("reconnect_attempt", (attempt) => {
|
||||
console.log(`[SOCKET] Reconnect Attempt ${this.socket.id}: ${attempt}`)
|
||||
})
|
||||
|
||||
this.socket.io.on("reconnect_error", (err) => {
|
||||
console.log(`[SOCKET] Reconnect Error ${this.socket.id}: ${err}`)
|
||||
})
|
||||
|
||||
this.socket.io.on("reconnect_failed", () => {
|
||||
console.log(`[SOCKET] Reconnect Failed ${this.socket.id}`)
|
||||
})
|
||||
|
||||
this.socket.io.on("reconnect", () => {
|
||||
console.log(`[SOCKET] Reconnect Success ${this.socket.id}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ android {
|
|||
applicationId "com.audiobookshelf.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 25
|
||||
versionName "0.9.9-beta"
|
||||
versionCode 26
|
||||
versionName "0.9.10-beta"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
|
|
@ -72,7 +72,9 @@ export default {
|
|||
bufferTrackWidth: 0,
|
||||
playedTrackWidth: 0,
|
||||
seekedTime: 0,
|
||||
seekLoading: false
|
||||
seekLoading: false,
|
||||
onPlayingUpdateListener: null,
|
||||
onMetadataListener: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -308,28 +310,29 @@ export default {
|
|||
terminateStream() {
|
||||
MyNativeAudio.terminateStream()
|
||||
},
|
||||
onPlayingUpdate(data) {
|
||||
this.isPaused = !data.value
|
||||
if (!this.isPaused) {
|
||||
this.startPlayInterval()
|
||||
} else {
|
||||
this.stopPlayInterval()
|
||||
}
|
||||
},
|
||||
onMetadata(data) {
|
||||
console.log('Native Audio On Metadata', JSON.stringify(data))
|
||||
this.totalDuration = Number((data.duration / 1000).toFixed(2))
|
||||
this.currentTime = Number((data.currentTime / 1000).toFixed(2))
|
||||
this.stateName = data.stateName
|
||||
|
||||
if (this.stateName === 'ended' && this.isResetting) {
|
||||
this.setFromObj()
|
||||
}
|
||||
|
||||
this.timeupdate()
|
||||
},
|
||||
init() {
|
||||
MyNativeAudio.addListener('onPlayingUpdate', (data) => {
|
||||
this.isPaused = !data.value
|
||||
if (!this.isPaused) {
|
||||
this.startPlayInterval()
|
||||
} else {
|
||||
this.stopPlayInterval()
|
||||
}
|
||||
})
|
||||
|
||||
MyNativeAudio.addListener('onMetadata', (data) => {
|
||||
console.log('Native Audio On Metadata', JSON.stringify(data))
|
||||
this.totalDuration = Number((data.duration / 1000).toFixed(2))
|
||||
this.currentTime = Number((data.currentTime / 1000).toFixed(2))
|
||||
this.stateName = data.stateName
|
||||
|
||||
if (this.stateName === 'ended' && this.isResetting) {
|
||||
this.setFromObj()
|
||||
}
|
||||
|
||||
this.timeupdate()
|
||||
})
|
||||
this.onPlayingUpdateListener = MyNativeAudio.addListener('onPlayingUpdate', this.onPlayingUpdate)
|
||||
this.onMetadataListener = MyNativeAudio.addListener('onMetadata', this.onMetadata)
|
||||
|
||||
if (this.$refs.track) {
|
||||
this.trackWidth = this.$refs.track.clientWidth
|
||||
|
@ -342,6 +345,8 @@ export default {
|
|||
this.$nextTick(this.init)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.onPlayingUpdateListener) this.onPlayingUpdateListener.remove()
|
||||
if (this.onMetadataListener) this.onMetadataListener.remove()
|
||||
clearInterval(this.playInterval)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ export default {
|
|||
|
||||
if (!this.networkConnected) return
|
||||
|
||||
this.$server.on('connected', this.socketConnected)
|
||||
var localServerUrl = await this.$localStore.getServerUrl()
|
||||
var localUserToken = await this.$localStore.getToken()
|
||||
if (localServerUrl) {
|
||||
|
@ -78,12 +77,16 @@ export default {
|
|||
// Server and Token are stored
|
||||
if (localUserToken) {
|
||||
this.processing = true
|
||||
var isSocketAlreadyEstablished = this.$server.socket
|
||||
var success = await this.$server.connect(localServerUrl, localUserToken)
|
||||
if (!success && !this.$server.url) {
|
||||
this.processing = false
|
||||
this.serverUrl = null
|
||||
} else if (!success) {
|
||||
this.processing = false
|
||||
} else if (isSocketAlreadyEstablished) {
|
||||
// No need to wait for connect event
|
||||
this.processing = false
|
||||
}
|
||||
} else {
|
||||
// Server only is stored
|
||||
|
@ -97,7 +100,18 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.$server) {
|
||||
console.error('Server not initalized in connection icon')
|
||||
return
|
||||
}
|
||||
if (this.$server.connected) {
|
||||
this.isConnected = true
|
||||
}
|
||||
this.$server.on('connected', this.socketConnected)
|
||||
this.init()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.$server) this.$server.off('connected', this.socketConnected)
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -32,18 +32,19 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
async connected(isConnected) {
|
||||
if (this.$route.name === 'connect') {
|
||||
if (isConnected) {
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
this.syncUserProgress()
|
||||
if (isConnected) {
|
||||
this.syncUserProgress()
|
||||
|
||||
// Load libraries
|
||||
this.$store.dispatch('libraries/load')
|
||||
// Load libraries
|
||||
this.$store.dispatch('libraries/load')
|
||||
}
|
||||
},
|
||||
socketConnectionFailed(err) {
|
||||
this.$toast.error('Socket connection error: ' + err.message)
|
||||
},
|
||||
updateAudiobookProgressOnServer(audiobookProgress) {
|
||||
if (this.$server.socket) {
|
||||
console.log(`[PROGRESSSYNC] Updating AB Progress on server ${JSON.stringify(audiobookProgress)}`)
|
||||
this.$server.socket.emit('progress_update', audiobookProgress)
|
||||
}
|
||||
},
|
||||
|
@ -54,22 +55,27 @@ export default {
|
|||
var localAudiobooks = this.$store.state.user.localUserAudiobooks
|
||||
var localHasUpdates = false
|
||||
|
||||
// console.log('[PROGRESSSYNC] Starting Sync USER', JSON.stringify(userAudiobooks))
|
||||
// console.log('[PROGRESSSYNC] Starting Sync LOCAL', JSON.stringify(localAudiobooks))
|
||||
|
||||
var newestLocal = { ...localAudiobooks }
|
||||
for (const audiobookId in userAudiobooks) {
|
||||
if (localAudiobooks[audiobookId]) {
|
||||
if (!audiobookId || !userAudiobooks[audiobookId] || audiobookId === 'undefined') {
|
||||
console.error(`[PROGRESSSYNC] Invalid audiobookId ${audiobookId} - ${JSON.stringify(userAudiobooks[audiobookId])}`)
|
||||
} else if (localAudiobooks[audiobookId]) {
|
||||
if (localAudiobooks[audiobookId].lastUpdate > userAudiobooks[audiobookId].lastUpdate) {
|
||||
// Local progress is more recent than user progress
|
||||
this.updateAudiobookProgressOnServer(localAudiobooks[audiobookId])
|
||||
} else if (localAudiobooks[audiobookId].lastUpdate < userAudiobooks[audiobookId].lastUpdate) {
|
||||
// Server is more recent than local
|
||||
newestLocal[audiobookId] = userAudiobooks[audiobookId]
|
||||
console.log('SYNCUSERPROGRESS Server IS MORE RECENT for', audiobookId)
|
||||
// console.log('[PROGRESSSYNC] Server IS MORE RECENT for', audiobookId, JSON.stringify(newestLocal[audiobookId]))
|
||||
localHasUpdates = true
|
||||
}
|
||||
} else {
|
||||
// Not on local yet - store on local
|
||||
newestLocal[audiobookId] = userAudiobooks[audiobookId]
|
||||
console.log('SYNCUSERPROGRESS LOCAL Is NOT Stored YET for', audiobookId, JSON.stringify(newestLocal[audiobookId]))
|
||||
// console.log('[PROGRESSSYNC] LOCAL Is NOT Stored YET for', audiobookId, JSON.stringify(newestLocal[audiobookId]))
|
||||
localHasUpdates = true
|
||||
}
|
||||
}
|
||||
|
@ -82,10 +88,17 @@ export default {
|
|||
}
|
||||
|
||||
if (localHasUpdates) {
|
||||
console.log('Local audiobook progress has updates from server')
|
||||
// console.log('[PROGRESSSYNC] Local audiobook progress has updates from server')
|
||||
this.$localStore.setAllAudiobookProgress(newestLocal)
|
||||
}
|
||||
},
|
||||
currentUserAudiobookUpdate({ id, data }) {
|
||||
if (data) {
|
||||
this.$localStore.updateUserAudiobookProgress(data)
|
||||
} else {
|
||||
this.$localStore.removeAudiobookProgress(id)
|
||||
}
|
||||
},
|
||||
initialStream(stream) {
|
||||
if (this.$refs.streamContainer && this.$refs.streamContainer.audioPlayerReady) {
|
||||
this.$refs.streamContainer.streamOpen(stream)
|
||||
|
@ -368,9 +381,12 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
if (!this.$server) return console.error('No Server')
|
||||
// console.log(`Default Mounted set SOCKET listeners ${this.$server.connected}`)
|
||||
|
||||
this.$server.on('connected', this.connected)
|
||||
this.$server.on('connectionFailed', this.socketConnectionFailed)
|
||||
this.$server.on('initialStream', this.initialStream)
|
||||
this.$server.on('currentUserAudiobookUpdate', this.currentUserAudiobookUpdate)
|
||||
|
||||
if (this.$store.state.isFirstLoad) {
|
||||
this.$store.commit('setIsFirstLoad', false)
|
||||
|
@ -379,7 +395,6 @@ export default {
|
|||
this.initMediaStore()
|
||||
}
|
||||
|
||||
// For Testing Android Auto
|
||||
MyNativeAudio.addListener('onPrepareMedia', (data) => {
|
||||
var audiobookId = data.audiobookId
|
||||
var playWhenReady = data.playWhenReady
|
||||
|
@ -403,8 +418,9 @@ export default {
|
|||
console.error('No Server beforeDestroy')
|
||||
return
|
||||
}
|
||||
console.log('Default Before Destroy remove listeners')
|
||||
|
||||
this.$server.off('connected', this.connected)
|
||||
this.$server.off('connectionFailed', this.socketConnectionFailed)
|
||||
this.$server.off('initialStream', this.initialStream)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "audiobookshelf-app",
|
||||
"version": "v0.9.9-beta",
|
||||
"version": "v0.9.10-beta",
|
||||
"author": "advplyr",
|
||||
"scripts": {
|
||||
"dev": "nuxt --hostname localhost --port 1337",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue