Merge branch 'advplyr:master' into stream-sync

This commit is contained in:
svdztn 2021-10-26 11:02:27 +08:00 committed by GitHub
commit ad823ca486
6 changed files with 134 additions and 47 deletions

View file

@ -16,6 +16,8 @@ class Server extends EventEmitter {
this.connected = false this.connected = false
this.stream = null this.stream = null
this.isConnectingSocket = false
} }
get token() { get token() {
@ -60,6 +62,10 @@ class Server extends EventEmitter {
} }
async connect(url, token) { async connect(url, token) {
if (this.connected) {
console.warn('[SOCKET] Connection already established for ' + this.url)
return true
}
if (!url) { if (!url) {
console.error('Invalid url to connect') console.error('Invalid url to connect')
return false return false
@ -151,38 +157,84 @@ class Server extends EventEmitter {
} }
connectSocket() { 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', () => { this.socket.on('connect', () => {
console.log('[Server] Socket Connected') console.log('[SOCKET] Socket Connected ' + this.socket.id)
// Authenticate socket with token // Authenticate socket with token
this.socket.emit('auth', this.token) this.socket.emit('auth', this.token)
this.connected = true this.connected = true
this.emit('connected', true) this.emit('connected', true)
this.store.commit('setSocketConnected', true) this.store.commit('setSocketConnected', true)
}) })
this.socket.on('disconnect', () => { this.socket.on('disconnect', (reason) => {
console.log('[Server] Socket Disconnected') console.log('[SOCKET] Socket Disconnected: ' + reason)
this.connected = false this.connected = false
this.emit('connected', false) this.emit('connected', false)
this.store.commit('setSocketConnected', 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) => { this.socket.on('init', (data) => {
console.log('[Server] Initial socket data received', data) console.log('[SOCKET] Initial socket data received', data)
if (data.stream) { if (data.stream) {
this.stream = data.stream this.stream = data.stream
this.store.commit('setStreamAudiobook', data.stream.audiobook) this.store.commit('setStreamAudiobook', data.stream.audiobook)
this.emit('initialStream', data.stream) this.emit('initialStream', data.stream)
} }
}) })
this.socket.on('user_updated', (user) => { this.socket.on('user_updated', (user) => {
if (this.user && user.id === this.user.id) { if (this.user && user.id === this.user.id) {
this.setUser(user) 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}`)
})
} }
} }

View file

@ -13,8 +13,8 @@ android {
applicationId "com.audiobookshelf.app" applicationId "com.audiobookshelf.app"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 25 versionCode 26
versionName "0.9.9-beta" versionName "0.9.10-beta"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions { aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

View file

@ -72,7 +72,9 @@ export default {
bufferTrackWidth: 0, bufferTrackWidth: 0,
playedTrackWidth: 0, playedTrackWidth: 0,
seekedTime: 0, seekedTime: 0,
seekLoading: false seekLoading: false,
onPlayingUpdateListener: null,
onMetadataListener: null
} }
}, },
computed: { computed: {
@ -308,28 +310,29 @@ export default {
terminateStream() { terminateStream() {
MyNativeAudio.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() { init() {
MyNativeAudio.addListener('onPlayingUpdate', (data) => { this.onPlayingUpdateListener = MyNativeAudio.addListener('onPlayingUpdate', this.onPlayingUpdate)
this.isPaused = !data.value this.onMetadataListener = MyNativeAudio.addListener('onMetadata', this.onMetadata)
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()
})
if (this.$refs.track) { if (this.$refs.track) {
this.trackWidth = this.$refs.track.clientWidth this.trackWidth = this.$refs.track.clientWidth
@ -342,6 +345,8 @@ export default {
this.$nextTick(this.init) this.$nextTick(this.init)
}, },
beforeDestroy() { beforeDestroy() {
if (this.onPlayingUpdateListener) this.onPlayingUpdateListener.remove()
if (this.onMetadataListener) this.onMetadataListener.remove()
clearInterval(this.playInterval) clearInterval(this.playInterval)
} }
} }

View file

@ -69,7 +69,6 @@ export default {
if (!this.networkConnected) return if (!this.networkConnected) return
this.$server.on('connected', this.socketConnected)
var localServerUrl = await this.$localStore.getServerUrl() var localServerUrl = await this.$localStore.getServerUrl()
var localUserToken = await this.$localStore.getToken() var localUserToken = await this.$localStore.getToken()
if (localServerUrl) { if (localServerUrl) {
@ -78,12 +77,16 @@ export default {
// Server and Token are stored // Server and Token are stored
if (localUserToken) { if (localUserToken) {
this.processing = true this.processing = true
var isSocketAlreadyEstablished = this.$server.socket
var success = await this.$server.connect(localServerUrl, localUserToken) var success = await this.$server.connect(localServerUrl, localUserToken)
if (!success && !this.$server.url) { if (!success && !this.$server.url) {
this.processing = false this.processing = false
this.serverUrl = null this.serverUrl = null
} else if (!success) { } else if (!success) {
this.processing = false this.processing = false
} else if (isSocketAlreadyEstablished) {
// No need to wait for connect event
this.processing = false
} }
} else { } else {
// Server only is stored // Server only is stored
@ -97,7 +100,18 @@ export default {
} }
}, },
mounted() { 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() this.init()
},
beforeDestroy() {
if (this.$server) this.$server.off('connected', this.socketConnected)
} }
} }
</script> </script>

View file

@ -32,18 +32,19 @@ export default {
}, },
methods: { methods: {
async connected(isConnected) { async connected(isConnected) {
if (this.$route.name === 'connect') { if (isConnected) {
if (isConnected) { this.syncUserProgress()
this.$router.push('/')
}
}
this.syncUserProgress()
// Load libraries // Load libraries
this.$store.dispatch('libraries/load') this.$store.dispatch('libraries/load')
}
},
socketConnectionFailed(err) {
this.$toast.error('Socket connection error: ' + err.message)
}, },
updateAudiobookProgressOnServer(audiobookProgress) { updateAudiobookProgressOnServer(audiobookProgress) {
if (this.$server.socket) { if (this.$server.socket) {
console.log(`[PROGRESSSYNC] Updating AB Progress on server ${JSON.stringify(audiobookProgress)}`)
this.$server.socket.emit('progress_update', audiobookProgress) this.$server.socket.emit('progress_update', audiobookProgress)
} }
}, },
@ -54,22 +55,27 @@ export default {
var localAudiobooks = this.$store.state.user.localUserAudiobooks var localAudiobooks = this.$store.state.user.localUserAudiobooks
var localHasUpdates = false var localHasUpdates = false
// console.log('[PROGRESSSYNC] Starting Sync USER', JSON.stringify(userAudiobooks))
// console.log('[PROGRESSSYNC] Starting Sync LOCAL', JSON.stringify(localAudiobooks))
var newestLocal = { ...localAudiobooks } var newestLocal = { ...localAudiobooks }
for (const audiobookId in userAudiobooks) { 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) { if (localAudiobooks[audiobookId].lastUpdate > userAudiobooks[audiobookId].lastUpdate) {
// Local progress is more recent than user progress // Local progress is more recent than user progress
this.updateAudiobookProgressOnServer(localAudiobooks[audiobookId]) this.updateAudiobookProgressOnServer(localAudiobooks[audiobookId])
} else if (localAudiobooks[audiobookId].lastUpdate < userAudiobooks[audiobookId].lastUpdate) { } else if (localAudiobooks[audiobookId].lastUpdate < userAudiobooks[audiobookId].lastUpdate) {
// Server is more recent than local // Server is more recent than local
newestLocal[audiobookId] = userAudiobooks[audiobookId] 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 localHasUpdates = true
} }
} else { } else {
// Not on local yet - store on local // Not on local yet - store on local
newestLocal[audiobookId] = userAudiobooks[audiobookId] 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 localHasUpdates = true
} }
} }
@ -82,10 +88,17 @@ export default {
} }
if (localHasUpdates) { 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) this.$localStore.setAllAudiobookProgress(newestLocal)
} }
}, },
currentUserAudiobookUpdate({ id, data }) {
if (data) {
this.$localStore.updateUserAudiobookProgress(data)
} else {
this.$localStore.removeAudiobookProgress(id)
}
},
initialStream(stream) { initialStream(stream) {
if (this.$refs.streamContainer && this.$refs.streamContainer.audioPlayerReady) { if (this.$refs.streamContainer && this.$refs.streamContainer.audioPlayerReady) {
this.$refs.streamContainer.streamOpen(stream) this.$refs.streamContainer.streamOpen(stream)
@ -368,9 +381,12 @@ export default {
}, },
mounted() { mounted() {
if (!this.$server) return console.error('No Server') 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('connected', this.connected)
this.$server.on('connectionFailed', this.socketConnectionFailed)
this.$server.on('initialStream', this.initialStream) this.$server.on('initialStream', this.initialStream)
this.$server.on('currentUserAudiobookUpdate', this.currentUserAudiobookUpdate)
if (this.$store.state.isFirstLoad) { if (this.$store.state.isFirstLoad) {
this.$store.commit('setIsFirstLoad', false) this.$store.commit('setIsFirstLoad', false)
@ -379,7 +395,6 @@ export default {
this.initMediaStore() this.initMediaStore()
} }
// For Testing Android Auto
MyNativeAudio.addListener('onPrepareMedia', (data) => { MyNativeAudio.addListener('onPrepareMedia', (data) => {
var audiobookId = data.audiobookId var audiobookId = data.audiobookId
var playWhenReady = data.playWhenReady var playWhenReady = data.playWhenReady
@ -403,8 +418,9 @@ export default {
console.error('No Server beforeDestroy') console.error('No Server beforeDestroy')
return return
} }
console.log('Default Before Destroy remove listeners')
this.$server.off('connected', this.connected) this.$server.off('connected', this.connected)
this.$server.off('connectionFailed', this.socketConnectionFailed)
this.$server.off('initialStream', this.initialStream) this.$server.off('initialStream', this.initialStream)
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf-app", "name": "audiobookshelf-app",
"version": "v0.9.9-beta", "version": "v0.9.10-beta",
"author": "advplyr", "author": "advplyr",
"scripts": { "scripts": {
"dev": "nuxt --hostname localhost --port 1337", "dev": "nuxt --hostname localhost --port 1337",