mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-19 10:15:14 +02:00
Change:Sleep timer shake to extend time 15m and fade out audio #44 #10, Change:Audio player show time remaining accounting for current playback speed #40, Fix:highlighted current chapter, Update api endpoints
This commit is contained in:
parent
d3343d722f
commit
edc45addc9
17 changed files with 272 additions and 117 deletions
|
@ -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 46
|
versionCode 47
|
||||||
versionName "0.9.27-beta"
|
versionName "0.9.28-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.
|
||||||
|
|
|
@ -132,7 +132,7 @@ class AudiobookManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openStream(audiobook:Audiobook, streamListener:OnStreamData) {
|
fun openStream(audiobook:Audiobook, streamListener:OnStreamData) {
|
||||||
var url = "$serverUrl/api/audiobook/${audiobook.id}/stream"
|
var url = "$serverUrl/api/books/${audiobook.id}/stream"
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(url).addHeader("Authorization", "Bearer $token")
|
.url(url).addHeader("Authorization", "Bearer $token")
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -5,6 +5,8 @@ import android.app.DownloadManager
|
||||||
import android.app.SearchManager
|
import android.app.SearchManager
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.hardware.Sensor
|
||||||
|
import android.hardware.SensorManager
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
@ -27,6 +29,11 @@ class MainActivity : BridgeActivity() {
|
||||||
val storageHelper = SimpleStorageHelper(this)
|
val storageHelper = SimpleStorageHelper(this)
|
||||||
val storage = SimpleStorage(this)
|
val storage = SimpleStorage(this)
|
||||||
|
|
||||||
|
// The following are used for the shake detection
|
||||||
|
private var mSensorManager: SensorManager? = null
|
||||||
|
private var mAccelerometer: Sensor? = null
|
||||||
|
private var mShakeDetector: ShakeDetector? = null
|
||||||
|
|
||||||
val broadcastReceiver = object: BroadcastReceiver() {
|
val broadcastReceiver = object: BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
when (intent?.action) {
|
when (intent?.action) {
|
||||||
|
@ -54,6 +61,24 @@ class MainActivity : BridgeActivity() {
|
||||||
addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED)
|
addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED)
|
||||||
}
|
}
|
||||||
registerReceiver(broadcastReceiver, filter)
|
registerReceiver(broadcastReceiver, filter)
|
||||||
|
|
||||||
|
initSensor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
Log.d(tag, "onResume Register sensor listener")
|
||||||
|
mSensorManager!!.registerListener(
|
||||||
|
mShakeDetector,
|
||||||
|
mAccelerometer,
|
||||||
|
SensorManager.SENSOR_DELAY_UI
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
mSensorManager!!.unregisterListener(mShakeDetector)
|
||||||
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
@ -128,6 +153,19 @@ class MainActivity : BridgeActivity() {
|
||||||
storageHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
storageHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initSensor() {
|
||||||
|
// ShakeDetector initialization
|
||||||
|
mSensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
|
||||||
|
mAccelerometer = mSensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
|
||||||
|
mShakeDetector = ShakeDetector()
|
||||||
|
mShakeDetector!!.setOnShakeListener(object : ShakeDetector.OnShakeListener {
|
||||||
|
override fun onShake(count: Int) {
|
||||||
|
Log.d(tag, "PHONE SHAKE! $count")
|
||||||
|
foregroundService.handleShake()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// override fun onUserInteraction() {
|
// override fun onUserInteraction() {
|
||||||
// super.onUserInteraction()
|
// super.onUserInteraction()
|
||||||
// Log.d(tag, "USER INTERACTION")
|
// Log.d(tag, "USER INTERACTION")
|
||||||
|
|
|
@ -38,6 +38,9 @@ class MyNativeAudio : Plugin() {
|
||||||
override fun onSleepTimerEnded(currentPosition:Long) {
|
override fun onSleepTimerEnded(currentPosition:Long) {
|
||||||
emit("onSleepTimerEnded", currentPosition)
|
emit("onSleepTimerEnded", currentPosition)
|
||||||
}
|
}
|
||||||
|
override fun onSleepTimerSet(sleepTimerEndTime:Long) {
|
||||||
|
emit("onSleepTimerSet", sleepTimerEndTime)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mainActivity.pluginCallback = foregroundServiceReady
|
mainActivity.pluginCallback = foregroundServiceReady
|
||||||
|
@ -81,7 +84,6 @@ class MyNativeAudio : Plugin() {
|
||||||
fun getCurrentTime(call: PluginCall) {
|
fun getCurrentTime(call: PluginCall) {
|
||||||
Handler(Looper.getMainLooper()).post() {
|
Handler(Looper.getMainLooper()).post() {
|
||||||
var currentTime = playerNotificationService.getCurrentTime()
|
var currentTime = playerNotificationService.getCurrentTime()
|
||||||
Log.d(tag, "Get Current Time $currentTime")
|
|
||||||
val ret = JSObject()
|
val ret = JSObject()
|
||||||
ret.put("value", currentTime)
|
ret.put("value", currentTime)
|
||||||
call.resolve(ret)
|
call.resolve(ret)
|
||||||
|
@ -95,7 +97,6 @@ class MyNativeAudio : Plugin() {
|
||||||
var lastPauseTime = playerNotificationService.getTheLastPauseTime()
|
var lastPauseTime = playerNotificationService.getTheLastPauseTime()
|
||||||
Log.d(tag, "Get Last Pause Time $lastPauseTime")
|
Log.d(tag, "Get Last Pause Time $lastPauseTime")
|
||||||
var currentTime = playerNotificationService.getCurrentTime()
|
var currentTime = playerNotificationService.getCurrentTime()
|
||||||
Log.d(tag, "Get Current Time $currentTime")
|
|
||||||
//if (!isPlaying) currentTime -= playerNotificationService.calcPauseSeekBackTime()
|
//if (!isPlaying) currentTime -= playerNotificationService.calcPauseSeekBackTime()
|
||||||
var id = playerNotificationService.getCurrentAudiobookId()
|
var id = playerNotificationService.getCurrentAudiobookId()
|
||||||
Log.d(tag, "Get Current id $id")
|
Log.d(tag, "Get Current id $id")
|
||||||
|
|
|
@ -49,9 +49,11 @@ import okhttp3.OkHttpClient
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
const val NOTIFICATION_LARGE_ICON_SIZE = 144 // px
|
const val NOTIFICATION_LARGE_ICON_SIZE = 144 // px
|
||||||
|
const val SLEEP_EXTENSION_TIME = 900000L // 15m
|
||||||
|
|
||||||
class PlayerNotificationService : MediaBrowserServiceCompat() {
|
class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
fun onMetadata(metadata: JSObject)
|
fun onMetadata(metadata: JSObject)
|
||||||
fun onPrepare(audiobookId: String, playWhenReady: Boolean)
|
fun onPrepare(audiobookId: String, playWhenReady: Boolean)
|
||||||
fun onSleepTimerEnded(currentPosition: Long)
|
fun onSleepTimerEnded(currentPosition: Long)
|
||||||
|
fun onSleepTimerSet(sleepTimerEndTime:Long)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +104,8 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
private var onSeekBack: Boolean = false
|
private var onSeekBack: Boolean = false
|
||||||
|
|
||||||
private var sleepTimerTask:TimerTask? = null
|
private var sleepTimerTask:TimerTask? = null
|
||||||
private var sleepChapterTime:Long = 0L
|
private var sleepTimerRunning:Boolean = false
|
||||||
|
private var sleepTimerEndTime:Long = 0L
|
||||||
|
|
||||||
private lateinit var audiobookManager:AudiobookManager
|
private lateinit var audiobookManager:AudiobookManager
|
||||||
private var newConnectionListener:SessionListener? = null
|
private var newConnectionListener:SessionListener? = null
|
||||||
|
@ -490,7 +494,12 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_MEDIA_PLAY -> {
|
KeyEvent.KEYCODE_MEDIA_PLAY -> {
|
||||||
if (0 == mediaButtonClickCount) play()
|
if (0 == mediaButtonClickCount) {
|
||||||
|
play()
|
||||||
|
if (sleepTimerRunning) {
|
||||||
|
extendSleepTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
||||||
|
@ -511,7 +520,12 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
if (0 == mediaButtonClickCount) pause()
|
if (0 == mediaButtonClickCount) pause()
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
} else {
|
} else {
|
||||||
if (0 == mediaButtonClickCount) play()
|
if (0 == mediaButtonClickCount) {
|
||||||
|
play()
|
||||||
|
if (sleepTimerRunning) {
|
||||||
|
extendSleepTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -759,7 +773,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
|
|
||||||
|
|
||||||
fun getCurrentTime() : Long {
|
fun getCurrentTime() : Long {
|
||||||
return mPlayer.currentPosition
|
return currentPlayer.currentPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTheLastPauseTime() : Long {
|
fun getTheLastPauseTime() : Long {
|
||||||
|
@ -767,7 +781,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDuration() : Long {
|
fun getDuration() : Long {
|
||||||
return mPlayer.duration
|
return currentPlayer.duration
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calcPauseSeekBackTime() : Long {
|
fun calcPauseSeekBackTime() : Long {
|
||||||
|
@ -989,57 +1003,89 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
fun setSleepTimer(time: Long, isChapterTime: Boolean) : Boolean {
|
fun setSleepTimer(time: Long, isChapterTime: Boolean) : Boolean {
|
||||||
Log.d(tag, "Setting Sleep Timer for $time is chapter time $isChapterTime")
|
Log.d(tag, "Setting Sleep Timer for $time is chapter time $isChapterTime")
|
||||||
sleepTimerTask?.cancel()
|
sleepTimerTask?.cancel()
|
||||||
sleepChapterTime = 0L
|
sleepTimerRunning = false
|
||||||
|
|
||||||
|
var currentTime = getCurrentTime()
|
||||||
if (isChapterTime) {
|
if (isChapterTime) {
|
||||||
// Validate time
|
if (currentTime > time) {
|
||||||
if (currentPlayer.isPlaying) {
|
Log.d(tag, "Invalid sleep timer - current time is already passed chapter time $time")
|
||||||
if (currentPlayer.currentPosition >= time) {
|
return false
|
||||||
Log.d(tag, "Invalid setSleepTimer chapter time is already passed")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
sleepTimerEndTime = time
|
||||||
|
} else {
|
||||||
|
sleepTimerEndTime = currentTime + time
|
||||||
|
}
|
||||||
|
|
||||||
sleepChapterTime = time
|
if (sleepTimerEndTime > getDuration()) {
|
||||||
sleepTimerTask = Timer("SleepTimer", false).schedule(0L, 1000L) {
|
sleepTimerEndTime = getDuration()
|
||||||
Handler(Looper.getMainLooper()).post() {
|
}
|
||||||
if (currentPlayer.isPlaying && currentPlayer.currentPosition > sleepChapterTime) {
|
|
||||||
|
Log.d(tag, "SLEEP VOLUME ${currentPlayer.volume} | ${currentPlayer.deviceVolume}")
|
||||||
|
// if (isChapterTime) {
|
||||||
|
// sleepChapterTime = time
|
||||||
|
listener?.onSleepTimerSet(sleepTimerEndTime)
|
||||||
|
|
||||||
|
sleepTimerRunning = true
|
||||||
|
sleepTimerTask = Timer("SleepTimer", false).schedule(0L, 1000L) {
|
||||||
|
Handler(Looper.getMainLooper()).post() {
|
||||||
|
if (currentPlayer.isPlaying) {
|
||||||
|
var sleepTimeRemaining = sleepTimerEndTime - getCurrentTime()
|
||||||
|
var sleepTimeSecondsRemaining = ((sleepTimeRemaining / 1000).toDouble()).roundToInt()
|
||||||
|
Log.d(tag, "Sleep TIMER time remaining $sleepTimeSecondsRemaining s")
|
||||||
|
|
||||||
|
if (sleepTimeRemaining <= 0) {
|
||||||
Log.d(tag, "Sleep Timer Pausing Player on Chapter")
|
Log.d(tag, "Sleep Timer Pausing Player on Chapter")
|
||||||
currentPlayer.pause()
|
currentPlayer.pause()
|
||||||
|
|
||||||
listener?.onSleepTimerEnded(currentPlayer.currentPosition)
|
listener?.onSleepTimerEnded(currentPlayer.currentPosition)
|
||||||
sleepTimerTask?.cancel()
|
sleepTimerTask?.cancel()
|
||||||
|
sleepTimerRunning = false
|
||||||
|
} else if (sleepTimeSecondsRemaining <= 30) {
|
||||||
|
// Start fading out audio
|
||||||
|
var volume = sleepTimeSecondsRemaining / 30F
|
||||||
|
Log.d(tag, "SLEEP VOLUME FADE $volume | ${sleepTimeSecondsRemaining}s remaining")
|
||||||
|
currentPlayer.volume = volume
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
sleepTimerTask = Timer("SleepTimer", false).schedule(time) {
|
|
||||||
Log.d(tag, "Sleep Timer Done")
|
|
||||||
Handler(Looper.getMainLooper()).post() {
|
|
||||||
if (currentPlayer.isPlaying) {
|
|
||||||
Log.d(tag, "Sleep Timer Pausing Player")
|
|
||||||
currentPlayer.pause()
|
|
||||||
}
|
|
||||||
listener?.onSleepTimerEnded(currentPlayer.currentPosition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSleepTimerTime():Long? {
|
fun getSleepTimerTime():Long? {
|
||||||
var time = sleepTimerTask?.scheduledExecutionTime()
|
return sleepTimerEndTime
|
||||||
Log.d(tag, "Sleep Timer execution time $time")
|
|
||||||
return time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancelSleepTimer() {
|
fun cancelSleepTimer() {
|
||||||
Log.d(tag, "Canceling Sleep Timer")
|
Log.d(tag, "Canceling Sleep Timer")
|
||||||
sleepTimerTask?.cancel()
|
sleepTimerTask?.cancel()
|
||||||
sleepTimerTask = null
|
sleepTimerTask = null
|
||||||
sleepChapterTime = 0L
|
sleepTimerEndTime = 0
|
||||||
|
sleepTimerRunning = false
|
||||||
|
listener?.onSleepTimerSet(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun extendSleepTime() {
|
||||||
|
if (!sleepTimerRunning) return
|
||||||
|
currentPlayer.volume = 1F
|
||||||
|
sleepTimerEndTime += SLEEP_EXTENSION_TIME
|
||||||
|
if (sleepTimerEndTime > getDuration()) sleepTimerEndTime = getDuration()
|
||||||
|
listener?.onSleepTimerSet(sleepTimerEndTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleShake() {
|
||||||
|
Log.d(tag, "HANDLE SHAKE HERE")
|
||||||
|
if (sleepTimerRunning) {
|
||||||
|
Log.d(tag, "Sleep Timer is Running, EXTEND TIME")
|
||||||
|
extendSleepTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
CAST STUFF
|
||||||
|
*/
|
||||||
|
|
||||||
private inner class CastSessionAvailabilityListener : SessionAvailabilityListener {
|
private inner class CastSessionAvailabilityListener : SessionAvailabilityListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package com.audiobookshelf.app
|
||||||
|
|
||||||
|
import android.hardware.Sensor
|
||||||
|
import android.hardware.SensorEvent
|
||||||
|
import android.hardware.SensorEventListener
|
||||||
|
import android.hardware.SensorManager
|
||||||
|
import java.lang.Math.sqrt
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
class ShakeDetector : SensorEventListener {
|
||||||
|
private var mListener: OnShakeListener? = null
|
||||||
|
private var mShakeTimestamp: Long = 0
|
||||||
|
private var mShakeCount = 0
|
||||||
|
fun setOnShakeListener(listener: OnShakeListener?) {
|
||||||
|
mListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnShakeListener {
|
||||||
|
fun onShake(count: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAccuracyChanged(
|
||||||
|
sensor: Sensor,
|
||||||
|
accuracy: Int
|
||||||
|
) { // ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSensorChanged(event: SensorEvent) {
|
||||||
|
if (mListener != null) {
|
||||||
|
val x = event.values[0]
|
||||||
|
val y = event.values[1]
|
||||||
|
val z = event.values[2]
|
||||||
|
val gX = x / SensorManager.GRAVITY_EARTH
|
||||||
|
val gY = y / SensorManager.GRAVITY_EARTH
|
||||||
|
val gZ = z / SensorManager.GRAVITY_EARTH
|
||||||
|
// gForce will be close to 1 when there is no movement.
|
||||||
|
val gForce: Float = sqrt(gX * gX + gY * gY + gZ * gZ)
|
||||||
|
if (gForce > SHAKE_THRESHOLD_GRAVITY) {
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
// ignore shake events too close to each other (500ms)
|
||||||
|
if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// reset the shake count after 3 seconds of no shakes
|
||||||
|
if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
|
||||||
|
mShakeCount = 0
|
||||||
|
}
|
||||||
|
mShakeTimestamp = now
|
||||||
|
mShakeCount++
|
||||||
|
mListener!!.onShake(mShakeCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/*
|
||||||
|
* The gForce that is necessary to register as shake.
|
||||||
|
* Must be greater than 1G (one earth gravity unit).
|
||||||
|
* You can install "G-Force", by Blake La Pierre
|
||||||
|
* from the Google Play Store and run it to see how
|
||||||
|
* many G's it takes to register a shake
|
||||||
|
*/
|
||||||
|
private const val SHAKE_THRESHOLD_GRAVITY = 2.7f
|
||||||
|
private const val SHAKE_SLOP_TIME_MS = 500
|
||||||
|
private const val SHAKE_COUNT_RESET_TIME_MS = 3000
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,8 +32,7 @@
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||||
</svg>
|
</svg>
|
||||||
<div v-else class="h-7 w-7 flex items-center justify-around cursor-pointer" @click.stop="$emit('showSleepTimer')">
|
<div v-else class="h-7 w-7 flex items-center justify-around cursor-pointer" @click.stop="$emit('showSleepTimer')">
|
||||||
<p v-if="sleepTimerEndOfChapterTime" class="text-lg font-mono text-warning">-{{ $secondsToTimestamp(timeLeftInChapter) }}</p>
|
<p class="text-xl font-mono text-success">{{ sleepTimeRemainingPretty }}</p>
|
||||||
<p v-else class="text-xl font-mono text-success">{{ Math.ceil(sleepTimeoutCurrentTime / 1000 / 60) }}m</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="material-icons text-3xl text-white cursor-pointer" :class="chapters.length ? 'text-opacity-75' : 'text-opacity-10'" @click="$emit('selectChapter')">format_list_bulleted</span>
|
<span class="material-icons text-3xl text-white cursor-pointer" :class="chapters.length ? 'text-opacity-75' : 'text-opacity-10'" @click="$emit('selectChapter')">format_list_bulleted</span>
|
||||||
|
@ -54,17 +53,17 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="playerTrack" class="absolute bottom-0 left-0 w-full px-3">
|
<div id="playerTrack" class="absolute bottom-0 left-0 w-full px-3">
|
||||||
<div ref="track" class="h-2 w-full bg-gray-500 bg-opacity-50 relative" :class="loading ? 'animate-pulse' : ''" @click.stop="clickTrack">
|
<div ref="track" class="h-2 w-full bg-gray-500 bg-opacity-50 relative" :class="loading ? 'animate-pulse' : ''" @click="clickTrack">
|
||||||
<div ref="readyTrack" class="h-full bg-gray-600 absolute top-0 left-0 pointer-events-none" />
|
<div ref="readyTrack" class="h-full bg-gray-600 absolute top-0 left-0 pointer-events-none" />
|
||||||
<div ref="bufferTrack" class="h-full bg-gray-400 absolute top-0 left-0 pointer-events-none" />
|
<div ref="bufferTrack" class="h-full bg-gray-400 absolute top-0 left-0 pointer-events-none" />
|
||||||
<div ref="playedTrack" class="h-full bg-gray-200 absolute top-0 left-0 pointer-events-none" />
|
<div ref="playedTrack" class="h-full bg-gray-200 absolute top-0 left-0 pointer-events-none" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex pt-0.5">
|
<div class="flex pt-0.5">
|
||||||
<p class="font-mono text-sm" ref="currentTimestamp">0:00</p>
|
<p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem" ref="currentTimestamp">0:00</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<p v-show="showFullscreen" class="text-sm truncate text-white text-opacity-75" style="max-width: 65%">{{ currentChapterTitle }}</p>
|
<p v-show="showFullscreen" class="text-sm truncate text-white text-opacity-75" style="max-width: 65%">{{ currentChapterTitle }}</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<p class="font-mono text-sm">{{ totalDurationPretty }}</p>
|
<p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem">{{ timeRemainingPretty }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -76,6 +75,7 @@ import MyNativeAudio from '@/plugins/my-native-audio'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
playing: Boolean,
|
||||||
audiobook: {
|
audiobook: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
@ -90,8 +90,7 @@ export default {
|
||||||
},
|
},
|
||||||
loading: Boolean,
|
loading: Boolean,
|
||||||
sleepTimerRunning: Boolean,
|
sleepTimerRunning: Boolean,
|
||||||
sleepTimeoutCurrentTime: Number,
|
sleepTimerEndTime: Number
|
||||||
sleepTimerEndOfChapterTime: Number
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -127,6 +126,14 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
isPlaying: {
|
||||||
|
get() {
|
||||||
|
return this.playing
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('update:playing', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
book() {
|
book() {
|
||||||
return this.audiobook.book || {}
|
return this.audiobook.book || {}
|
||||||
},
|
},
|
||||||
|
@ -156,9 +163,31 @@ export default {
|
||||||
totalDurationPretty() {
|
totalDurationPretty() {
|
||||||
return this.$secondsToTimestamp(this.totalDuration)
|
return this.$secondsToTimestamp(this.totalDuration)
|
||||||
},
|
},
|
||||||
|
timeRemaining() {
|
||||||
|
return (this.totalDuration - this.currentTime) / this.currentPlaybackRate
|
||||||
|
},
|
||||||
|
timeRemainingPretty() {
|
||||||
|
if (this.timeRemaining < 0) {
|
||||||
|
return this.$secondsToTimestamp(this.timeRemaining * -1)
|
||||||
|
}
|
||||||
|
return '-' + this.$secondsToTimestamp(this.timeRemaining)
|
||||||
|
},
|
||||||
timeLeftInChapter() {
|
timeLeftInChapter() {
|
||||||
if (!this.currentChapter) return 0
|
if (!this.currentChapter) return 0
|
||||||
return this.currentChapter.end - this.currentTime
|
return this.currentChapter.end - this.currentTime
|
||||||
|
},
|
||||||
|
sleepTimeRemaining() {
|
||||||
|
if (!this.sleepTimerEndTime) return 0
|
||||||
|
return Math.max(0, this.sleepTimerEndTime / 1000 - this.currentTime)
|
||||||
|
},
|
||||||
|
sleepTimeRemainingPretty() {
|
||||||
|
if (!this.sleepTimeRemaining) return '0s'
|
||||||
|
var secondsRemaining = Math.round(this.sleepTimeRemaining)
|
||||||
|
if (secondsRemaining > 91) {
|
||||||
|
return Math.ceil(secondsRemaining / 60) + 'm'
|
||||||
|
} else {
|
||||||
|
return secondsRemaining + 's'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -269,9 +298,6 @@ export default {
|
||||||
if (this.loading) return
|
if (this.loading) return
|
||||||
MyNativeAudio.seekForward({ amount: '10000' })
|
MyNativeAudio.seekForward({ amount: '10000' })
|
||||||
},
|
},
|
||||||
// sendStreamUpdate() {
|
|
||||||
// this.$emit('updateTime', this.currentTime)
|
|
||||||
// },
|
|
||||||
setStreamReady() {
|
setStreamReady() {
|
||||||
this.readyTrackWidth = this.trackWidth
|
this.readyTrackWidth = this.trackWidth
|
||||||
this.$refs.readyTrack.style.width = this.trackWidth + 'px'
|
this.$refs.readyTrack.style.width = this.trackWidth + 'px'
|
||||||
|
@ -310,6 +336,7 @@ export default {
|
||||||
console.error('Invalid no played track ref')
|
console.error('Invalid no played track ref')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
this.$emit('updateTime', this.currentTime)
|
||||||
|
|
||||||
if (this.seekLoading) {
|
if (this.seekLoading) {
|
||||||
this.seekLoading = false
|
this.seekLoading = false
|
||||||
|
@ -354,6 +381,12 @@ export default {
|
||||||
},
|
},
|
||||||
clickTrack(e) {
|
clickTrack(e) {
|
||||||
if (this.loading) return
|
if (this.loading) return
|
||||||
|
if (!this.showFullscreen) {
|
||||||
|
// Track not clickable on mini-player
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (e) e.stopPropagation()
|
||||||
|
|
||||||
var offsetX = e.offsetX
|
var offsetX = e.offsetX
|
||||||
var perc = offsetX / this.trackWidth
|
var perc = offsetX / this.trackWidth
|
||||||
var time = perc * this.totalDuration
|
var time = perc * this.totalDuration
|
||||||
|
@ -462,10 +495,12 @@ export default {
|
||||||
play() {
|
play() {
|
||||||
MyNativeAudio.playPlayer()
|
MyNativeAudio.playPlayer()
|
||||||
this.startPlayInterval()
|
this.startPlayInterval()
|
||||||
|
this.isPlaying = true
|
||||||
},
|
},
|
||||||
pause() {
|
pause() {
|
||||||
MyNativeAudio.pausePlayer()
|
MyNativeAudio.pausePlayer()
|
||||||
this.stopPlayInterval()
|
this.stopPlayInterval()
|
||||||
|
this.isPlaying = false
|
||||||
},
|
},
|
||||||
startPlayInterval() {
|
startPlayInterval() {
|
||||||
this.startListenTimeInterval()
|
this.startListenTimeInterval()
|
||||||
|
@ -474,6 +509,7 @@ export default {
|
||||||
this.playInterval = setInterval(async () => {
|
this.playInterval = setInterval(async () => {
|
||||||
var data = await MyNativeAudio.getCurrentTime()
|
var data = await MyNativeAudio.getCurrentTime()
|
||||||
this.currentTime = Number((data.value / 1000).toFixed(2))
|
this.currentTime = Number((data.value / 1000).toFixed(2))
|
||||||
|
|
||||||
this.timeupdate()
|
this.timeupdate()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,18 +3,19 @@
|
||||||
<div v-if="audiobook" id="streamContainer">
|
<div v-if="audiobook" id="streamContainer">
|
||||||
<app-audio-player
|
<app-audio-player
|
||||||
ref="audioPlayer"
|
ref="audioPlayer"
|
||||||
|
:playing.sync="isPlaying"
|
||||||
:audiobook="audiobook"
|
:audiobook="audiobook"
|
||||||
:download="download"
|
:download="download"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
:bookmarks="bookmarks"
|
:bookmarks="bookmarks"
|
||||||
:sleep-timer-running="isSleepTimerRunning"
|
:sleep-timer-running="isSleepTimerRunning"
|
||||||
:sleep-timer-end-of-chapter-time="sleepTimerEndOfChapterTime"
|
:sleep-timer-end-time="sleepTimerEndTime"
|
||||||
:sleep-timeout-current-time="sleepTimeoutCurrentTime"
|
|
||||||
@close="cancelStream"
|
@close="cancelStream"
|
||||||
@sync="sync"
|
@sync="sync"
|
||||||
@setTotalDuration="setTotalDuration"
|
@setTotalDuration="setTotalDuration"
|
||||||
@selectPlaybackSpeed="showPlaybackSpeedModal = true"
|
@selectPlaybackSpeed="showPlaybackSpeedModal = true"
|
||||||
@selectChapter="clickChapterBtn"
|
@selectChapter="clickChapterBtn"
|
||||||
|
@updateTime="(t) => (currentTime = t)"
|
||||||
@showSleepTimer="showSleepTimer"
|
@showSleepTimer="showSleepTimer"
|
||||||
@showBookmarks="showBookmarks"
|
@showBookmarks="showBookmarks"
|
||||||
@hook:mounted="audioPlayerMounted"
|
@hook:mounted="audioPlayerMounted"
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
|
|
||||||
<modals-playback-speed-modal v-model="showPlaybackSpeedModal" :playback-speed.sync="playbackSpeed" @change="changePlaybackSpeed" />
|
<modals-playback-speed-modal v-model="showPlaybackSpeedModal" :playback-speed.sync="playbackSpeed" @change="changePlaybackSpeed" />
|
||||||
<modals-chapters-modal v-model="showChapterModal" :current-chapter="currentChapter" :chapters="chapters" @select="selectChapter" />
|
<modals-chapters-modal v-model="showChapterModal" :current-chapter="currentChapter" :chapters="chapters" @select="selectChapter" />
|
||||||
<modals-sleep-timer-modal v-model="showSleepTimerModal" :current-time="sleepTimeoutCurrentTime" :sleep-timer-running="isSleepTimerRunning" :current-end-of-chapter-time="currentEndOfChapterTime" :end-of-chapter-time-set="sleepTimerEndOfChapterTime" @change="selectSleepTimeout" @cancel="cancelSleepTimer" />
|
<modals-sleep-timer-modal v-model="showSleepTimerModal" :current-time="sleepTimeRemaining" :sleep-timer-running="isSleepTimerRunning" :current-end-of-chapter-time="currentEndOfChapterTime" @change="selectSleepTimeout" @cancel="cancelSleepTimer" />
|
||||||
<modals-bookmarks-modal v-model="showBookmarksModal" :audiobook-id="audiobookId" :bookmarks="bookmarks" :current-time="currentTime" @select="selectBookmark" />
|
<modals-bookmarks-modal v-model="showBookmarksModal" :audiobook-id="audiobookId" :bookmarks="bookmarks" :current-time="currentTime" @select="selectBookmark" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -35,6 +36,7 @@ import MyNativeAudio from '@/plugins/my-native-audio'
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
isPlaying: false,
|
||||||
audioPlayerReady: false,
|
audioPlayerReady: false,
|
||||||
stream: null,
|
stream: null,
|
||||||
download: null,
|
download: null,
|
||||||
|
@ -45,10 +47,10 @@ export default {
|
||||||
playbackSpeed: 1,
|
playbackSpeed: 1,
|
||||||
showChapterModal: false,
|
showChapterModal: false,
|
||||||
currentTime: 0,
|
currentTime: 0,
|
||||||
sleepTimeoutCurrentTime: 0,
|
|
||||||
isSleepTimerRunning: false,
|
isSleepTimerRunning: false,
|
||||||
sleepTimerEndOfChapterTime: 0,
|
sleepTimerEndTime: 0,
|
||||||
onSleepTimerEndedListener: null,
|
onSleepTimerEndedListener: null,
|
||||||
|
onSleepTimerSetListener: null,
|
||||||
sleepInterval: null,
|
sleepInterval: null,
|
||||||
currentEndOfChapterTime: 0,
|
currentEndOfChapterTime: 0,
|
||||||
totalDuration: 0
|
totalDuration: 0
|
||||||
|
@ -138,6 +140,10 @@ export default {
|
||||||
if (this.cover.startsWith('http')) return this.cover
|
if (this.cover.startsWith('http')) return this.cover
|
||||||
var coverSrc = this.$store.getters['audiobooks/getBookCoverSrc'](this.audiobook)
|
var coverSrc = this.$store.getters['audiobooks/getBookCoverSrc'](this.audiobook)
|
||||||
return coverSrc
|
return coverSrc
|
||||||
|
},
|
||||||
|
sleepTimeRemaining() {
|
||||||
|
if (!this.sleepTimerEndTime) return 0
|
||||||
|
return Math.max(0, this.sleepTimerEndTime / 1000 - this.currentTime)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -154,16 +160,24 @@ export default {
|
||||||
},
|
},
|
||||||
onSleepTimerEnded({ value: currentPosition }) {
|
onSleepTimerEnded({ value: currentPosition }) {
|
||||||
this.isSleepTimerRunning = false
|
this.isSleepTimerRunning = false
|
||||||
if (this.sleepInterval) clearInterval(this.sleepInterval)
|
|
||||||
|
|
||||||
if (currentPosition) {
|
if (currentPosition) {
|
||||||
console.log('Sleep Timer Ended Current Position: ' + currentPosition)
|
console.log('Sleep Timer Ended Current Position: ' + currentPosition)
|
||||||
var currentTime = Math.floor(currentPosition / 1000)
|
var currentTime = Math.floor(currentPosition / 1000)
|
||||||
this.updateTime(currentTime)
|
this.updateTime(currentTime)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onSleepTimerSet({ value: sleepTimerEndTime }) {
|
||||||
|
console.log('SLEEP TIMER SET', sleepTimerEndTime)
|
||||||
|
if (sleepTimerEndTime === 0) {
|
||||||
|
console.log('Sleep timer canceled')
|
||||||
|
this.isSleepTimerRunning = false
|
||||||
|
} else {
|
||||||
|
this.isSleepTimerRunning = true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sleepTimerEndTime = sleepTimerEndTime
|
||||||
|
},
|
||||||
showSleepTimer() {
|
showSleepTimer() {
|
||||||
console.log('show sleep timer')
|
|
||||||
if (this.currentChapter) {
|
if (this.currentChapter) {
|
||||||
this.currentEndOfChapterTime = Math.floor(this.currentChapter.end)
|
this.currentEndOfChapterTime = Math.floor(this.currentChapter.end)
|
||||||
} else {
|
} else {
|
||||||
|
@ -171,60 +185,16 @@ export default {
|
||||||
}
|
}
|
||||||
this.showSleepTimerModal = true
|
this.showSleepTimerModal = true
|
||||||
},
|
},
|
||||||
async getSleepTimerTime() {
|
|
||||||
var res = await MyNativeAudio.getSleepTimerTime()
|
|
||||||
if (res && res.value) {
|
|
||||||
var time = Number(res.value)
|
|
||||||
return time - Date.now()
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
},
|
|
||||||
async selectSleepTimeout({ time, isChapterTime }) {
|
async selectSleepTimeout({ time, isChapterTime }) {
|
||||||
console.log('Setting sleep timer', time, isChapterTime)
|
console.log('Setting sleep timer', time, isChapterTime)
|
||||||
var res = await MyNativeAudio.setSleepTimer({ time: String(time), isChapterTime })
|
var res = await MyNativeAudio.setSleepTimer({ time: String(time), isChapterTime })
|
||||||
if (!res.success) {
|
if (!res.success) {
|
||||||
return this.$toast.error('Sleep timer did not set, invalid time')
|
return this.$toast.error('Sleep timer did not set, invalid time')
|
||||||
}
|
}
|
||||||
if (isChapterTime) {
|
|
||||||
this.sleepTimerEndOfChapterTime = time
|
|
||||||
this.isSleepTimerRunning = true
|
|
||||||
} else {
|
|
||||||
this.sleepTimerEndOfChapterTime = 0
|
|
||||||
this.setSleepTimeoutTimer(time)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async cancelSleepTimer() {
|
async cancelSleepTimer() {
|
||||||
console.log('Canceling sleep timer')
|
console.log('Canceling sleep timer')
|
||||||
await MyNativeAudio.cancelSleepTimer()
|
await MyNativeAudio.cancelSleepTimer()
|
||||||
this.isSleepTimerRunning = false
|
|
||||||
this.sleepTimerEndOfChapterTime = 0
|
|
||||||
if (this.sleepInterval) clearInterval(this.sleepInterval)
|
|
||||||
},
|
|
||||||
async syncSleepTimer() {
|
|
||||||
var time = await this.getSleepTimerTime()
|
|
||||||
this.setSleepTimeoutTimer(time)
|
|
||||||
},
|
|
||||||
setSleepTimeoutTimer(startTime) {
|
|
||||||
if (this.sleepInterval) clearInterval(this.sleepInterval)
|
|
||||||
|
|
||||||
this.sleepTimeoutCurrentTime = startTime
|
|
||||||
this.isSleepTimerRunning = true
|
|
||||||
var elapsed = 0
|
|
||||||
this.sleepInterval = setInterval(() => {
|
|
||||||
this.sleepTimeoutCurrentTime = Math.max(0, this.sleepTimeoutCurrentTime - 1000)
|
|
||||||
|
|
||||||
if (this.sleepTimeoutCurrentTime <= 0) {
|
|
||||||
clearInterval(this.sleepInterval)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync with the actual time from android Timer
|
|
||||||
elapsed++
|
|
||||||
if (elapsed > 5) {
|
|
||||||
clearInterval(this.sleepInterval)
|
|
||||||
this.syncSleepTimer()
|
|
||||||
}
|
|
||||||
}, 1000)
|
|
||||||
},
|
},
|
||||||
clickChapterBtn() {
|
clickChapterBtn() {
|
||||||
if (!this.chapters.length) return
|
if (!this.chapters.length) return
|
||||||
|
@ -477,6 +447,7 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.onSleepTimerEndedListener = MyNativeAudio.addListener('onSleepTimerEnded', this.onSleepTimerEnded)
|
this.onSleepTimerEndedListener = MyNativeAudio.addListener('onSleepTimerEnded', this.onSleepTimerEnded)
|
||||||
|
this.onSleepTimerSetListener = MyNativeAudio.addListener('onSleepTimerSet', this.onSleepTimerSet)
|
||||||
|
|
||||||
this.playbackSpeed = this.$store.getters['user/getUserSetting']('playbackRate')
|
this.playbackSpeed = this.$store.getters['user/getUserSetting']('playbackRate')
|
||||||
console.log(`[AudioPlayerContainer] Init Playback Speed: ${this.playbackSpeed}`)
|
console.log(`[AudioPlayerContainer] Init Playback Speed: ${this.playbackSpeed}`)
|
||||||
|
@ -487,6 +458,7 @@ export default {
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.onSleepTimerEndedListener) this.onSleepTimerEndedListener.remove()
|
if (this.onSleepTimerEndedListener) this.onSleepTimerEndedListener.remove()
|
||||||
|
if (this.onSleepTimerSetListener) this.onSleepTimerSetListener.remove()
|
||||||
|
|
||||||
if (this.$server.socket) {
|
if (this.$server.socket) {
|
||||||
this.$server.socket.off('stream_open', this.streamOpen)
|
this.$server.socket.off('stream_open', this.streamOpen)
|
||||||
|
|
|
@ -68,7 +68,7 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.isFetching = true
|
this.isFetching = true
|
||||||
var results = await this.$axios.$get(`/api/audiobooks?q=${value}`).catch((error) => {
|
var results = await this.$axios.$get(`/api/books?q=${value}`).catch((error) => {
|
||||||
console.error('Search error', error)
|
console.error('Search error', error)
|
||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div v-else class="px-2 py-4">
|
<div v-else class="px-2 py-4">
|
||||||
<p v-if="endOfChapterTimeSet" class="mb-4 text-2xl font-mono text-center">EOC: {{ endOfChapterTimePretty }}</p>
|
<p class="mb-4 text-2xl font-mono text-center">{{ timeRemainingPretty }}</p>
|
||||||
<p v-else class="mb-4 text-2xl font-mono text-center">{{ timeRemainingPretty }}</p>
|
|
||||||
<ui-btn @click="cancelSleepTimer" class="w-full">Cancel Timer</ui-btn>
|
<ui-btn @click="cancelSleepTimer" class="w-full">Cancel Timer</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,8 +37,7 @@ export default {
|
||||||
value: Boolean,
|
value: Boolean,
|
||||||
currentTime: Number,
|
currentTime: Number,
|
||||||
sleepTimerRunning: Boolean,
|
sleepTimerRunning: Boolean,
|
||||||
currentEndOfChapterTime: Number,
|
currentEndOfChapterTime: Number
|
||||||
endOfChapterTimeSet: Number
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return {}
|
||||||
|
@ -57,10 +55,7 @@ export default {
|
||||||
return [1, 15, 30, 45, 60, 75, 90, 120]
|
return [1, 15, 30, 45, 60, 75, 90, 120]
|
||||||
},
|
},
|
||||||
timeRemainingPretty() {
|
timeRemainingPretty() {
|
||||||
return this.$secondsToTimestamp(this.currentTime / 1000)
|
return this.$secondsToTimestamp(this.currentTime)
|
||||||
},
|
|
||||||
endOfChapterTimePretty() {
|
|
||||||
return this.$secondsToTimestamp(this.endOfChapterTimeSet / 1000)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.isProcessingReadUpdate = true
|
this.isProcessingReadUpdate = true
|
||||||
this.$axios
|
this.$axios
|
||||||
.$patch(`/api/user/audiobook/${this.book.id}`, updatePayload)
|
.$patch(`/api/me/audiobook/${this.book.id}`, updatePayload)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.isProcessingReadUpdate = false
|
this.isProcessingReadUpdate = false
|
||||||
this.$toast.success(`"${this.bookTitle}" Marked as ${updatePayload.isRead ? 'Read' : 'Not Read'}`)
|
this.$toast.success(`"${this.bookTitle}" Marked as ${updatePayload.isRead ? 'Read' : 'Not Read'}`)
|
||||||
|
@ -104,7 +104,7 @@ export default {
|
||||||
this.processingRemove = true
|
this.processingRemove = true
|
||||||
|
|
||||||
this.$axios
|
this.$axios
|
||||||
.$delete(`/api/collection/${this.collectionId}/book/${this.book.id}`)
|
.$delete(`/api/collections/${this.collectionId}/book/${this.book.id}`)
|
||||||
.then((updatedCollection) => {
|
.then((updatedCollection) => {
|
||||||
console.log(`Book removed from collection`, updatedCollection)
|
console.log(`Book removed from collection`, updatedCollection)
|
||||||
this.$toast.success('Book removed from collection')
|
this.$toast.success('Book removed from collection')
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "audiobookshelf-app",
|
"name": "audiobookshelf-app",
|
||||||
"version": "v0.9.27-beta",
|
"version": "v0.9.28-beta",
|
||||||
"author": "advplyr",
|
"author": "advplyr",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nuxt --hostname localhost --port 1337",
|
"dev": "nuxt --hostname localhost --port 1337",
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default {
|
||||||
var audiobook = null
|
var audiobook = null
|
||||||
|
|
||||||
if (app.$server.connected) {
|
if (app.$server.connected) {
|
||||||
audiobook = await app.$axios.$get(`/api/audiobook/${audiobookId}`).catch((error) => {
|
audiobook = await app.$axios.$get(`/api/books/${audiobookId}`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
@ -229,7 +229,7 @@ export default {
|
||||||
|
|
||||||
if (this.$server.connected) {
|
if (this.$server.connected) {
|
||||||
await this.$axios
|
await this.$axios
|
||||||
.$patch(`/api/user/audiobook/${this.audiobookId}/reset-progress`)
|
.$patch(`/api/me/audiobook/${this.audiobookId}/reset-progress`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('Progress reset complete')
|
console.log('Progress reset complete')
|
||||||
this.$toast.success(`Your progress was reset`)
|
this.$toast.success(`Your progress was reset`)
|
||||||
|
@ -245,7 +245,7 @@ export default {
|
||||||
audiobookUpdated() {
|
audiobookUpdated() {
|
||||||
console.log('Audiobook Updated - Fetch full audiobook')
|
console.log('Audiobook Updated - Fetch full audiobook')
|
||||||
this.$axios
|
this.$axios
|
||||||
.$get(`/api/audiobook/${this.audiobookId}`)
|
.$get(`/api/books/${this.audiobookId}`)
|
||||||
.then((audiobook) => {
|
.then((audiobook) => {
|
||||||
this.audiobook = audiobook
|
this.audiobook = audiobook
|
||||||
})
|
})
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
return redirect(`/connect?redirect=${route.path}`)
|
return redirect(`/connect?redirect=${route.path}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
var collection = await app.$axios.$get(`/api/collection/${params.id}`).catch((error) => {
|
var collection = await app.$axios.$get(`/api/collections/${params.id}`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.isFetching = true
|
this.isFetching = true
|
||||||
var results = await this.$axios.$get(`/api/audiobooks?q=${value}`).catch((error) => {
|
var results = await this.$axios.$get(`/api/books?q=${value}`).catch((error) => {
|
||||||
console.error('Search error', error)
|
console.error('Search error', error)
|
||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
|
|
|
@ -28,7 +28,7 @@ export const actions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.$axios
|
return this.$axios
|
||||||
.$get(`/api/library/${libraryId}`)
|
.$get(`/api/libraries/${libraryId}`)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
commit('addUpdate', data)
|
commit('addUpdate', data)
|
||||||
commit('setCurrentLibrary', libraryId)
|
commit('setCurrentLibrary', libraryId)
|
||||||
|
|
|
@ -42,7 +42,7 @@ export const actions = {
|
||||||
var updatePayload = {
|
var updatePayload = {
|
||||||
...payload
|
...payload
|
||||||
}
|
}
|
||||||
return this.$axios.$patch('/api/user/settings', updatePayload).then((result) => {
|
return this.$axios.$patch('/api/me/settings', updatePayload).then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
commit('setSettings', result.settings)
|
commit('setSettings', result.settings)
|
||||||
return true
|
return true
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue