diff --git a/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt b/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt index 41aa0dec..57fca917 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt @@ -32,8 +32,8 @@ object DeviceManager { var deviceData: DeviceData = dbManager.getDeviceData() var serverConnectionConfig: ServerConnectionConfig? = null - val serverConnectionConfigId - get() = serverConnectionConfig?.id ?: "" + val serverConnectionConfigId get() = serverConnectionConfig?.id ?: "" + val serverConnectionConfigName get() = serverConnectionConfig?.name ?: "" val serverAddress get() = serverConnectionConfig?.address ?: "" val serverUserId diff --git a/android/app/src/main/java/com/audiobookshelf/app/managers/DbManager.kt b/android/app/src/main/java/com/audiobookshelf/app/managers/DbManager.kt index fa840c2d..b2f8293e 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/managers/DbManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/managers/DbManager.kt @@ -5,6 +5,7 @@ import android.util.Log import com.audiobookshelf.app.data.* import com.audiobookshelf.app.models.DownloadItem import com.audiobookshelf.app.plugins.AbsLog +import com.audiobookshelf.app.plugins.AbsLogger import io.paperdb.Paper import java.io.File @@ -299,6 +300,24 @@ class DbManager { logs.add(it) } } - return logs + return logs.sortedBy { it.timestamp } + } + fun removeAllLogs() { + Paper.book("log").destroy() + } + fun cleanLogs() { + val numberOfHoursToKeep = 48 + val keepLogCutoff = System.currentTimeMillis() - (3600000 * numberOfHoursToKeep) + val allLogs = getAllLogs() + var logsRemoved = 0 + allLogs.forEach { + if (it.timestamp < keepLogCutoff) { + Paper.book("log").delete(it.id) + logsRemoved++ + } + } + if (logsRemoved > 0) { + AbsLogger.info("DbManager", "cleanLogs: Removed $logsRemoved logs older than $numberOfHoursToKeep hours") + } } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/media/MediaProgressSyncer.kt b/android/app/src/main/java/com/audiobookshelf/app/media/MediaProgressSyncer.kt index ae110498..1aeed0a0 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/media/MediaProgressSyncer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/media/MediaProgressSyncer.kt @@ -8,6 +8,7 @@ import com.audiobookshelf.app.data.MediaProgress import com.audiobookshelf.app.data.PlaybackSession import com.audiobookshelf.app.device.DeviceManager import com.audiobookshelf.app.player.PlayerNotificationService +import com.audiobookshelf.app.plugins.AbsLogger import com.audiobookshelf.app.server.ApiHandler import java.util.* import kotlin.concurrent.schedule @@ -208,6 +209,7 @@ class MediaProgressSyncer( MediaEventManager.seekEvent(currentPlaybackSession!!, null) } + // Currently unused fun syncFromServerProgress(mediaProgress: MediaProgress) { currentPlaybackSession?.let { it.updatedAt = mediaProgress.lastUpdate @@ -260,44 +262,46 @@ class MediaProgressSyncer( tag, "Sync local device current serverConnectionConfigId=${DeviceManager.serverConnectionConfig?.id}" ) + AbsLogger.info("MediaProgressSyncer", "sync: Saved local progress (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: ${it.id})") // 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 + val isConnectedToSameServer = it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId if (hasNetworkConnection && shouldSyncServer && !it.libraryItemId.isNullOrEmpty() && - it.serverConnectionConfigId != null && - DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId + isConnectedToSameServer ) { apiHandler.sendLocalProgressSync(it) { syncSuccess, errorMsg -> if (syncSuccess) { failedSyncs = 0 playerNotificationService.alertSyncSuccess() DeviceManager.dbManager.removePlaybackSession(it.id) // Remove session from db + AbsLogger.info("MediaProgressSyncer", "sync: Successfully synced local progress (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: ${it.id})") } else { failedSyncs++ if (failedSyncs == 2) { playerNotificationService.alertSyncFailing() // Show alert in client failedSyncs = 0 } - Log.e( - tag, - "Local Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime with session id=${it.id}" - ) + AbsLogger.error("MediaProgressSyncer", "sync: Local progress sync failed (count: $failedSyncs) (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: ${it.id}) (${DeviceManager.serverConnectionConfigName})") } cb(SyncResult(true, syncSuccess, errorMsg)) } } else { + AbsLogger.info("MediaProgressSyncer", "sync: Not sending local progress to server (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: ${it.id}) (hasNetworkConnection: $hasNetworkConnection) (isConnectedToSameServer: $isConnectedToSameServer)") cb(SyncResult(false, null, null)) } } } else if (hasNetworkConnection && shouldSyncServer) { - Log.d(tag, "sync: currentSessionId=$currentSessionId") + AbsLogger.info("MediaProgressSyncer", "sync: Sending progress sync to server (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: ${currentSessionId}) (${DeviceManager.serverConnectionConfigName})") + apiHandler.sendProgressSync(currentSessionId, syncData) { syncSuccess, errorMsg -> if (syncSuccess) { - Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime") + AbsLogger.info("MediaProgressSyncer", "sync: Successfully synced progress (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: ${currentSessionId}) (${DeviceManager.serverConnectionConfigName})") + failedSyncs = 0 playerNotificationService.alertSyncSuccess() lastSyncTime = System.currentTimeMillis() @@ -308,14 +312,12 @@ class MediaProgressSyncer( playerNotificationService.alertSyncFailing() // Show alert in client failedSyncs = 0 } - Log.e( - tag, - "Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime with session id=${currentSessionId}" - ) + AbsLogger.error("MediaProgressSyncer", "sync: Progress sync failed (count: $failedSyncs) (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: $currentSessionId) (${DeviceManager.serverConnectionConfigName})") } cb(SyncResult(true, syncSuccess, errorMsg)) } } else { + AbsLogger.info("MediaProgressSyncer", "sync: Not sending progress to server (title: \"$currentDisplayTitle\") (currentTime: $currentTime) (session id: $currentSessionId) (${DeviceManager.serverConnectionConfigName}) (hasNetworkConnection: $hasNetworkConnection)") cb(SyncResult(false, null, null)) } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index e9e792b7..6cfc9cc1 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -36,6 +36,7 @@ import com.audiobookshelf.app.media.MediaManager import com.audiobookshelf.app.media.MediaProgressSyncer import com.audiobookshelf.app.media.getUriToAbsIconDrawable import com.audiobookshelf.app.media.getUriToDrawable +import com.audiobookshelf.app.plugins.AbsLogger import com.audiobookshelf.app.server.ApiHandler import com.google.android.exoplayer2.* import com.google.android.exoplayer2.audio.AudioAttributes @@ -452,7 +453,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { playbackSession ) // Save playback session to use when app is closed - Log.d(tag, "Set CurrentPlaybackSession MediaPlayer ${currentPlaybackSession?.mediaPlayer}") + AbsLogger.info("PlayerNotificationService", "preparePlayer: Started playback session for item ${currentPlaybackSession?.mediaItemId}. MediaPlayer ${currentPlaybackSession?.mediaPlayer}") // Notify client clientEventEmitter?.onPlaybackSession(playbackSession) @@ -469,7 +470,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { val mediaSource: MediaSource if (playbackSession.isLocal) { - Log.d(tag, "Playing Local Item") + AbsLogger.info("PlayerNotificationService", "preparePlayer: Playing local item ${currentPlaybackSession?.mediaItemId}.") val dataSourceFactory = DefaultDataSource.Factory(ctx) val extractorsFactory = DefaultExtractorsFactory() @@ -483,7 +484,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory) .createMediaSource(mediaItems[0]) } else if (!playbackSession.isHLS) { - Log.d(tag, "Direct Playing Item") + AbsLogger.info("PlayerNotificationService", "preparePlayer: Direct playing item ${currentPlaybackSession?.mediaItemId}.") val dataSourceFactory = DefaultHttpDataSource.Factory() val extractorsFactory = DefaultExtractorsFactory() @@ -498,7 +499,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory) .createMediaSource(mediaItems[0]) } else { - Log.d(tag, "Playing HLS Item") + AbsLogger.info("PlayerNotificationService", "preparePlayer: Playing HLS stream of item ${currentPlaybackSession?.mediaItemId}.") val dataSourceFactory = DefaultHttpDataSource.Factory() dataSourceFactory.setUserAgent(channelId) dataSourceFactory.setDefaultRequestProperties( diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt index e51e2ee6..79a460d1 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt @@ -180,7 +180,8 @@ class AbsAudioPlayer : Plugin() { val playWhenReady = call.getBoolean("playWhenReady") == true val playbackRate = call.getFloat("playbackRate",1f) ?: 1f val startTimeOverride = call.getDouble("startTime") - Log.d(tag, "prepareLibraryItem lid=$libraryItemId, startTimeOverride=$startTimeOverride, playbackRate=$playbackRate") + + AbsLogger.info("AbsAudioPlayer", "prepareLibraryItem: lid=$libraryItemId, startTimeOverride=$startTimeOverride, playbackRate=$playbackRate") if (libraryItemId.isEmpty()) { Log.e(tag, "Invalid call to play library item no library item id") diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt index 955f3d69..bcf0e34d 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt @@ -36,6 +36,7 @@ class AbsDatabase : Plugin() { DeviceManager.dbManager.cleanLocalMediaProgress() DeviceManager.dbManager.cleanLocalLibraryItems() + DeviceManager.dbManager.cleanLogs() } @PluginMethod @@ -219,15 +220,12 @@ class AbsDatabase : Plugin() { @PluginMethod fun syncLocalSessionsWithServer(call:PluginCall) { - AbsLogger.info("[AbsDatabase] syncLocalSessionsWithServer") if (DeviceManager.serverConnectionConfig == null) { - Log.e(tag, "syncLocalSessionsWithServer not connected to server") + AbsLogger.error("AbsDatabase", "syncLocalSessionsWithServer: not connected to server") return call.resolve() } apiHandler.syncLocalMediaProgressForUser { - Log.d(tag, "Finished syncing local media progress for user") - AbsLogger.info("[AbsDatabase] Finished syncing local media progress for user") val savedSessions = DeviceManager.dbManager.getPlaybackSessions().filter { it.serverConnectionConfigId == DeviceManager.serverConnectionConfigId } if (savedSessions.isNotEmpty()) { @@ -235,6 +233,7 @@ class AbsDatabase : Plugin() { if (!success) { call.resolve(JSObject("{\"error\":\"$errorMsg\"}")) } else { + AbsLogger.info("AbsDatabase", "syncLocalSessionsWithServer: Finished sending local playback sessions to server. Removing ${savedSessions.size} saved sessions.") // Remove all local sessions savedSessions.forEach { DeviceManager.dbManager.removePlaybackSession(it.id) @@ -243,6 +242,7 @@ class AbsDatabase : Plugin() { } } } else { + AbsLogger.info("AbsDatabase", "syncLocalSessionsWithServer: No saved local playback sessions to send to server.") call.resolve() } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsLogger.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsLogger.kt index 1da1ab11..ce52a550 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsLogger.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsLogger.kt @@ -13,6 +13,7 @@ import java.util.UUID data class AbsLog( var id:String, + var tag:String, var level:String, var message:String, var timestamp:Long @@ -25,31 +26,43 @@ class AbsLogger : Plugin() { private var jacksonMapper = jacksonObjectMapper().enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature()) override fun load() { + onLogEmitter = { log:AbsLog -> + notifyListeners("onLog", JSObject(jacksonMapper.writeValueAsString(log))) + } Log.i("AbsLogger", "Initialize AbsLogger plugin") } companion object { - fun info(message:String) { - Log.i("AbsLogger", message) - DeviceManager.dbManager.saveLog(AbsLog(id = UUID.randomUUID().toString(), level = "info", message, timestamp = System.currentTimeMillis())) + lateinit var onLogEmitter:(log:AbsLog) -> Unit + + fun log(level:String, tag:String, message:String) { + val absLog = AbsLog(id = UUID.randomUUID().toString(), tag, level, message, timestamp = System.currentTimeMillis()) + DeviceManager.dbManager.saveLog(absLog) + onLogEmitter(absLog) } - fun error(message:String) { + fun info(tag:String, message:String) { + Log.i("AbsLogger", message) + log("info", tag, message) + } + fun error(tag:String, message:String) { Log.e("AbsLogger", message) - DeviceManager.dbManager.saveLog(AbsLog(id = UUID.randomUUID().toString(), level = "error", message, timestamp = System.currentTimeMillis())) + log("error", tag, message) } } @PluginMethod fun info(call: PluginCall) { val msg = call.getString("message") ?: return call.reject("No message") - info(msg) + val tag = call.getString("tag") ?: "" + info(tag, msg) call.resolve() } @PluginMethod fun error(call: PluginCall) { val msg = call.getString("message") ?: return call.reject("No message") - error(msg) + val tag = call.getString("tag") ?: "" + error(tag, msg) call.resolve() } @@ -58,4 +71,10 @@ class AbsLogger : Plugin() { val absLogs = DeviceManager.dbManager.getAllLogs() call.resolve(JSObject(jacksonMapper.writeValueAsString(AbsLogList(absLogs)))) } + + @PluginMethod + fun clearLogs(call: PluginCall) { + DeviceManager.dbManager.removeAllLogs() + call.resolve() + } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt b/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt index dfd97064..bf807f73 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt @@ -13,6 +13,7 @@ import com.audiobookshelf.app.media.MediaProgressSyncData import com.audiobookshelf.app.media.SyncResult import com.audiobookshelf.app.models.User import com.audiobookshelf.app.BuildConfig +import com.audiobookshelf.app.plugins.AbsLogger import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.core.json.JsonReadFeature import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper @@ -468,22 +469,27 @@ class ApiHandler(var ctx:Context) { val deviceInfo = DeviceInfo(deviceId, Build.MANUFACTURER, Build.MODEL, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME) val payload = JSObject(jacksonMapper.writeValueAsString(LocalSessionsSyncRequestPayload(playbackSessions, deviceInfo))) - Log.d(tag, "Sending ${playbackSessions.size} saved local playback sessions to server") + AbsLogger.info("ApiHandler", "sendSyncLocalSessions: Sending ${playbackSessions.size} saved local playback sessions to server (${DeviceManager.serverConnectionConfigName})") + postRequest("/api/session/local-all", payload, null) { if (!it.getString("error").isNullOrEmpty()) { - Log.e(tag, "Failed to sync local sessions") + AbsLogger.error("ApiHandler", "sendSyncLocalSessions: Failed to sync local sessions. (${it.getString("error")})") cb(false, it.getString("error")) } else { val response = jacksonMapper.readValue(it.toString()) response.results.forEach { localSessionSyncResult -> Log.d(tag, "Synced session result ${localSessionSyncResult.id}|${localSessionSyncResult.progressSynced}|${localSessionSyncResult.success}") + playbackSessions.find { ps -> ps.id == localSessionSyncResult.id }?.let { session -> if (localSessionSyncResult.progressSynced == true) { val syncResult = SyncResult(true, true, "Progress synced on server") MediaEventManager.saveEvent(session, syncResult) - Log.i(tag, "Successfully synced session ${session.displayTitle} with server") + + AbsLogger.info("ApiHandler", "sendSyncLocalSessions: Synced session \"${session.displayTitle}\" with server, server progress was updated for item ${session.mediaItemId}") } else if (!localSessionSyncResult.success) { - Log.e(tag, "Failed to sync session ${session.displayTitle} with server. Error: ${localSessionSyncResult.error}") + AbsLogger.error("ApiHandler", "sendSyncLocalSessions: Failed to sync session \"${session.displayTitle}\" with server. Error: ${localSessionSyncResult.error}") + } else { + AbsLogger.info("ApiHandler", "sendSyncLocalSessions: Synced session \"${session.displayTitle}\" with server. Server progress was up-to-date for item ${session.mediaItemId}") } } } @@ -493,37 +499,72 @@ class ApiHandler(var ctx:Context) { } fun syncLocalMediaProgressForUser(cb: () -> Unit) { + AbsLogger.info("ApiHandler", "[ApiHandler] syncLocalMediaProgressForUser: Server connection ${DeviceManager.serverConnectionConfigName}") + // Get all local media progress for this server val allLocalMediaProgress = DeviceManager.dbManager.getAllLocalMediaProgress().filter { it.serverConnectionConfigId == DeviceManager.serverConnectionConfigId } if (allLocalMediaProgress.isEmpty()) { - Log.d(tag, "No local media progress to sync") + AbsLogger.info("ApiHandler", "[ApiHandler] syncLocalMediaProgressForUser: No local media progress to sync") return cb() } - getCurrentUser { _user -> - _user?.let { user-> + AbsLogger.info("ApiHandler", "syncLocalMediaProgressForUser: Found ${allLocalMediaProgress.size} local media progress") + + getCurrentUser { user -> + if (user == null) { + AbsLogger.error("ApiHandler", "syncLocalMediaProgressForUser: Failed to load user from server (${DeviceManager.serverConnectionConfigName})") + } else { + var numLocalMediaProgressUptToDate = 0 + var numLocalMediaProgressUpdated = 0 + // Compare server user progress with local progress user.mediaProgress.forEach { mediaProgress -> // Get matching local media progress allLocalMediaProgress.find { it.isMatch(mediaProgress) }?.let { localMediaProgress -> if (mediaProgress.lastUpdate > localMediaProgress.lastUpdate) { - Log.d(tag, "Server progress for media item id=\"${mediaProgress.mediaItemId}\" is more recent then local. Updating local current time ${localMediaProgress.currentTime} to ${mediaProgress.currentTime}") + val updateLogs = mutableListOf() + if (mediaProgress.progress != localMediaProgress.progress) { + updateLogs.add("Updated progress from ${localMediaProgress.progress} to ${mediaProgress.progress}") + } + if (mediaProgress.currentTime != localMediaProgress.currentTime) { + updateLogs.add("Updated currentTime from ${localMediaProgress.currentTime} to ${mediaProgress.currentTime}") + } + if (mediaProgress.isFinished != localMediaProgress.isFinished) { + updateLogs.add("Updated isFinished from ${localMediaProgress.isFinished} to ${mediaProgress.isFinished}") + } + if (mediaProgress.ebookProgress != localMediaProgress.ebookProgress) { + updateLogs.add("Updated ebookProgress from ${localMediaProgress.isFinished} to ${mediaProgress.isFinished}") + } + if (updateLogs.isNotEmpty()) { + AbsLogger.info("ApiHandler", "syncLocalMediaProgressForUser: Server progress for item \"${mediaProgress.mediaItemId}\" is more recent than local (server lastUpdate=${mediaProgress.lastUpdate}, local lastUpdate=${localMediaProgress.lastUpdate}). ${updateLogs.joinToString()}") + } + localMediaProgress.updateFromServerMediaProgress(mediaProgress) - MediaEventManager.syncEvent(mediaProgress, "Sync on server connection") + + // Only report sync if progress changed + if (updateLogs.isNotEmpty()) { + MediaEventManager.syncEvent(mediaProgress, "Sync on server connection") + } DeviceManager.dbManager.saveLocalMediaProgress(localMediaProgress) + numLocalMediaProgressUpdated++ } else if (localMediaProgress.lastUpdate > mediaProgress.lastUpdate && localMediaProgress.ebookLocation != null && localMediaProgress.ebookLocation != mediaProgress.ebookLocation) { // Patch ebook progress to server + AbsLogger.info("ApiHandler", "syncLocalMediaProgressForUser: Local progress for ebook item \"${mediaProgress.mediaItemId}\" is more recent than server progress. Local progress last updated ${localMediaProgress.lastUpdate}, server progress last updated ${mediaProgress.lastUpdate}. Sending server request to update ebook progress from ${mediaProgress.ebookProgress} to ${localMediaProgress.ebookProgress}") val endpoint = "/api/me/progress/${localMediaProgress.libraryItemId}" val updatePayload = JSObject() updatePayload.put("ebookLocation", localMediaProgress.ebookLocation) updatePayload.put("ebookProgress", localMediaProgress.ebookProgress) updatePayload.put("lastUpdate", localMediaProgress.lastUpdate) patchRequest(endpoint,updatePayload) { - Log.d(tag, "syncLocalMediaProgressForUser patched ebook progress") + AbsLogger.info("ApiHandler", "syncLocalMediaProgressForUser: Successfully updated server ebook progress for item item \"${mediaProgress.mediaItemId}\"") } + } else { + numLocalMediaProgressUptToDate++ } } } + + AbsLogger.info("ApiHandler", "syncLocalMediaProgressForUser: Finishing syncing local media progress with server. $numLocalMediaProgressUptToDate up-to-date, $numLocalMediaProgressUpdated updated") } cb() } diff --git a/components/app/AudioPlayerContainer.vue b/components/app/AudioPlayerContainer.vue index fe3f569d..958fc968 100644 --- a/components/app/AudioPlayerContainer.vue +++ b/components/app/AudioPlayerContainer.vue @@ -9,7 +9,7 @@ + diff --git a/plugins/capacitor/AbsAudioPlayer.js b/plugins/capacitor/AbsAudioPlayer.js index cec8f6c7..43326165 100644 --- a/plugins/capacitor/AbsAudioPlayer.js +++ b/plugins/capacitor/AbsAudioPlayer.js @@ -1,4 +1,5 @@ import { registerPlugin, WebPlugin } from '@capacitor/core' +import { AbsLogger } from '@/plugins/capacitor' import { nanoid } from 'nanoid' const { PlayerState } = require('../constants') @@ -88,6 +89,9 @@ class AbsAudioPlayerWeb extends WebPlugin { return } + // For testing onLog events in web while on the logs page + AbsLogger.info({ tag: 'AbsAudioPlayer', message: 'playPause' }) + if (this.player.paused) this.player.play() else this.player.pause() return { diff --git a/plugins/capacitor/AbsLogger.js b/plugins/capacitor/AbsLogger.js index eb1f7606..be65787a 100644 --- a/plugins/capacitor/AbsLogger.js +++ b/plugins/capacitor/AbsLogger.js @@ -7,31 +7,44 @@ class AbsLoggerWeb extends WebPlugin { this.logs = [] } - saveLog(level, message) { - this.logs.push({ + saveLog(level, tag, message) { + const log = { id: Math.random().toString(36).substring(2, 15), + tag: tag, timestamp: Date.now(), level: level, message: message - }) + } + this.logs.push(log) + this.notifyListeners('onLog', log) } + // PluginMethod async info(data) { if (data?.message) { - this.saveLog('info', data.message) - console.log('AbsLogger: info', data.message) + this.saveLog('info', data.tag || '', data.message) + console.log('AbsLogger: info', `[${data.tag || ''}]:`, data.message) } } + // PluginMethod async error(data) { if (data?.message) { - this.saveLog('error', data.message) - console.error('AbsLogger: error', data.message) + this.saveLog('error', data.tag || '', data.message) + console.error('AbsLogger: error', `[${data.tag || ''}]:`, data.message) } } + // PluginMethod async getAllLogs() { - return this.logs + return { + value: this.logs + } + } + + // PluginMethod + async clearLogs() { + this.logs = [] } } diff --git a/strings/en-us.json b/strings/en-us.json index ea710c5b..0330a661 100644 --- a/strings/en-us.json +++ b/strings/en-us.json @@ -6,6 +6,7 @@ "ButtonCancel": "Cancel", "ButtonCancelTimer": "Cancel Timer", "ButtonClearFilter": "Clear Filter", + "ButtonClearLogs": "Clear Logs", "ButtonCloseFeed": "Close Feed", "ButtonCollections": "Collections", "ButtonConnect": "Connect", @@ -28,6 +29,7 @@ "ButtonLocalMedia": "Local Media", "ButtonLogs": "Logs", "ButtonManageLocalFiles": "Manage Local Files", + "ButtonMaskServerAddress": "Mask server address", "ButtonNewFolder": "New Folder", "ButtonNextEpisode": "Next Episode", "ButtonOk": "Ok", @@ -51,6 +53,7 @@ "ButtonStream": "Stream", "ButtonSubmit": "Submit", "ButtonSwitchServerUser": "Switch Server/User", + "ButtonUnmaskServerAddress": "Unmask server address", "ButtonUserStats": "User Stats", "ButtonYes": "Yes", "HeaderAccount": "Account", @@ -311,6 +314,7 @@ "MessageNoItems": "No Items", "MessageNoItemsFound": "No items found", "MessageNoListeningSessions": "No Listening Sessions", + "MessageNoLogs": "No logs", "MessageNoMediaFolders": "No Media Folders", "MessageNoNetworkConnection": "No network connection", "MessageNoPodcastsFound": "No podcasts found",