mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-22 19:54:45 +02:00
Update:Metered network connections to send progress syncs every 60s instead of every 5s and show metered/unmetered in connection status icon #238
This commit is contained in:
parent
fd134097a1
commit
4c678836fb
6 changed files with 71 additions and 9 deletions
|
@ -19,6 +19,7 @@ data class MediaProgressSyncData(
|
|||
|
||||
class MediaProgressSyncer(val playerNotificationService:PlayerNotificationService, private val apiHandler: ApiHandler) {
|
||||
private val tag = "MediaProgressSync"
|
||||
private val METERED_CONNECTION_SYNC_INTERVAL = 60000
|
||||
|
||||
private var listeningTimerTask: TimerTask? = null
|
||||
var listeningTimerRunning:Boolean = false
|
||||
|
@ -57,8 +58,11 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
listeningTimerTask = Timer("ListeningTimer", false).schedule(0L, 5000L) {
|
||||
Handler(Looper.getMainLooper()).post() {
|
||||
if (playerNotificationService.currentPlayer.isPlaying) {
|
||||
// Only sync with server on unmetered connection every 5s OR sync with server if last sync time is >= 60s
|
||||
val shouldSyncServer = PlayerNotificationService.isUnmeteredNetwork || System.currentTimeMillis() - lastSyncTime >= METERED_CONNECTION_SYNC_INTERVAL
|
||||
|
||||
val currentTime = playerNotificationService.getCurrentTimeSeconds()
|
||||
sync(currentTime) {
|
||||
sync(shouldSyncServer, currentTime) {
|
||||
Log.d(tag, "Sync complete")
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +75,7 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
Log.d(tag, "stop: Stopping listening for $currentDisplayTitle")
|
||||
|
||||
val currentTime = playerNotificationService.getCurrentTimeSeconds()
|
||||
sync(currentTime) {
|
||||
sync(true, currentTime) {
|
||||
reset()
|
||||
cb()
|
||||
}
|
||||
|
@ -82,7 +86,7 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
Log.d(tag, "pause: Pausing progress syncer for $currentDisplayTitle")
|
||||
|
||||
val currentTime = playerNotificationService.getCurrentTimeSeconds()
|
||||
sync(currentTime) {
|
||||
sync(true, currentTime) {
|
||||
listeningTimerTask?.cancel()
|
||||
listeningTimerTask = null
|
||||
listeningTimerRunning = false
|
||||
|
@ -102,13 +106,12 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
}
|
||||
}
|
||||
|
||||
fun sync(currentTime:Double, cb: () -> Unit) {
|
||||
fun sync(shouldSyncServer:Boolean, currentTime:Double, cb: () -> Unit) {
|
||||
val diffSinceLastSync = System.currentTimeMillis() - lastSyncTime
|
||||
if (diffSinceLastSync < 1000L) {
|
||||
return cb()
|
||||
}
|
||||
val listeningTimeToAdd = diffSinceLastSync / 1000L
|
||||
lastSyncTime = System.currentTimeMillis()
|
||||
|
||||
val syncData = MediaProgressSyncData(listeningTimeToAdd,currentPlaybackDuration,currentTime)
|
||||
|
||||
|
@ -124,10 +127,11 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
currentPlaybackSession?.let {
|
||||
DeviceManager.dbManager.saveLocalPlaybackSession(it)
|
||||
saveLocalProgress(it)
|
||||
lastSyncTime = System.currentTimeMillis()
|
||||
|
||||
// Local library item is linked to a server library item
|
||||
// Send sync to server also if connected to this server and local item belongs to this server
|
||||
if (!it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) {
|
||||
if (shouldSyncServer && !it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) {
|
||||
apiHandler.sendLocalProgressSync(it) { syncSuccess ->
|
||||
Log.d(
|
||||
tag,
|
||||
|
@ -151,12 +155,13 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
cb()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (shouldSyncServer) {
|
||||
apiHandler.sendProgressSync(currentSessionId, syncData) {
|
||||
if (it) {
|
||||
Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime")
|
||||
failedSyncs = 0
|
||||
playerNotificationService.alertSyncSuccess()
|
||||
lastSyncTime = System.currentTimeMillis()
|
||||
} else {
|
||||
failedSyncs++
|
||||
if (failedSyncs == 2) {
|
||||
|
@ -167,6 +172,8 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
|||
}
|
||||
cb()
|
||||
}
|
||||
} else {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@ import android.content.Intent
|
|||
import android.graphics.Color
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.os.*
|
||||
import android.support.v4.media.MediaBrowserCompat
|
||||
import android.support.v4.media.MediaDescriptionCompat
|
||||
|
@ -45,6 +49,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
companion object {
|
||||
var isStarted = false
|
||||
var isClosed = false
|
||||
var isUnmeteredNetwork = false
|
||||
}
|
||||
|
||||
interface ClientEventEmitter {
|
||||
|
@ -59,6 +64,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
fun onMediaPlayerChanged(mediaPlayer:String)
|
||||
fun onProgressSyncFailing()
|
||||
fun onProgressSyncSuccess()
|
||||
fun onNetworkMeteredChanged(isUnmetered:Boolean)
|
||||
}
|
||||
|
||||
private val tag = "PlayerService"
|
||||
|
@ -164,6 +170,15 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
super.onCreate()
|
||||
ctx = this
|
||||
|
||||
// To listen for network change from metered to unmetered
|
||||
val networkRequest = NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.build()
|
||||
val connectivityManager = getSystemService(ConnectivityManager::class.java) as ConnectivityManager
|
||||
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
|
||||
|
||||
DbManager.initialize(ctx)
|
||||
|
||||
// Initialize API
|
||||
|
@ -914,5 +929,19 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
// Network capabilities have changed for the network
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities
|
||||
) {
|
||||
super.onCapabilitiesChanged(network, networkCapabilities)
|
||||
val unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
|
||||
Log.i(tag, "Network capabilities changed is unmetered = $unmetered")
|
||||
isUnmeteredNetwork = unmetered
|
||||
clientEventEmitter?.onNetworkMeteredChanged(unmetered)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,10 @@ class AbsAudioPlayer : Plugin() {
|
|||
override fun onProgressSyncSuccess() {
|
||||
emit("onProgressSyncSuccess", "")
|
||||
}
|
||||
|
||||
override fun onNetworkMeteredChanged(isUnmetered:Boolean) {
|
||||
emit("onNetworkMeteredChanged", isUnmetered)
|
||||
}
|
||||
})
|
||||
}
|
||||
mainActivity.pluginCallback = foregroundServiceReady
|
||||
|
|
|
@ -79,6 +79,12 @@ class ApiHandler(var ctx:Context) {
|
|||
return false
|
||||
}
|
||||
|
||||
fun isUsingCellularData(): Boolean {
|
||||
val connectivityManager = ctx.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||
return capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true
|
||||
}
|
||||
|
||||
fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) {
|
||||
val client = httpClient ?: defaultClient
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
|
|
|
@ -24,6 +24,9 @@ export default {
|
|||
networkConnectionType() {
|
||||
return this.$store.state.networkConnectionType
|
||||
},
|
||||
isNetworkUnmetered() {
|
||||
return this.$store.state.isNetworkUnmetered
|
||||
},
|
||||
isCellular() {
|
||||
return this.networkConnectionType === 'cellular'
|
||||
},
|
||||
|
@ -43,6 +46,7 @@ export default {
|
|||
iconClass() {
|
||||
if (!this.networkConnected) return 'text-error'
|
||||
else if (!this.socketConnected) return 'text-warning'
|
||||
else if (!this.isNetworkUnmetered) return 'text-yellow-400'
|
||||
else if (this.isCellular) return 'text-gray-200'
|
||||
else return 'text-success'
|
||||
}
|
||||
|
@ -50,14 +54,15 @@ export default {
|
|||
methods: {
|
||||
showAlertDialog() {
|
||||
var msg = ''
|
||||
var meteredString = this.isNetworkUnmetered ? 'unmetered' : 'metered'
|
||||
if (!this.networkConnected) {
|
||||
msg = 'No internet'
|
||||
} else if (!this.socketConnected) {
|
||||
msg = 'Socket not connected'
|
||||
} else if (this.isCellular) {
|
||||
msg = 'Socket connected over cellular'
|
||||
msg = `Socket connected over ${meteredString} cellular`
|
||||
} else {
|
||||
msg = 'Socket connected over wifi'
|
||||
msg = `Socket connected over ${meteredString} wifi`
|
||||
}
|
||||
Dialog.alert({
|
||||
title: 'Connection Status',
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Network } from '@capacitor/network'
|
||||
import { AbsAudioPlayer } from '@/plugins/capacitor'
|
||||
|
||||
export const state = () => ({
|
||||
deviceData: null,
|
||||
|
@ -12,6 +13,7 @@ export const state = () => ({
|
|||
socketConnected: false,
|
||||
networkConnected: false,
|
||||
networkConnectionType: null,
|
||||
isNetworkUnmetered: true,
|
||||
isFirstLoad: true,
|
||||
hasStoragePermission: false,
|
||||
selectedLibraryItem: null,
|
||||
|
@ -62,6 +64,12 @@ export const actions = {
|
|||
console.log('Network status changed', status.connected, status.connectionType)
|
||||
commit('setNetworkStatus', status)
|
||||
})
|
||||
|
||||
AbsAudioPlayer.addListener('onNetworkMeteredChanged', (payload) => {
|
||||
const isUnmetered = payload.value
|
||||
console.log('On network metered changed', isUnmetered)
|
||||
commit('setIsNetworkUnmetered', isUnmetered)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +122,9 @@ export const mutations = {
|
|||
state.networkConnected = val.connected
|
||||
state.networkConnectionType = val.connectionType
|
||||
},
|
||||
setIsNetworkUnmetered(state, val) {
|
||||
state.isNetworkUnmetered = val
|
||||
},
|
||||
openReader(state, libraryItem) {
|
||||
state.selectedLibraryItem = libraryItem
|
||||
state.showReader = true
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue