Enable checking silence scheduler for /say and /sonos endpoints
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
android:parentActivityName="com.bartlomiejpluta.ttsserver.ui.main.MainActivity" />
|
||||
|
||||
<activity
|
||||
android:name="com.bartlomiejpluta.ttsserver.ui.preference.PreferencesActivity"
|
||||
android:name="com.bartlomiejpluta.ttsserver.ui.preference.component.PreferencesActivity"
|
||||
android:label="@string/title_activity_preferences"
|
||||
android:parentActivityName="com.bartlomiejpluta.ttsserver.ui.main.MainActivity" />
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO
|
||||
import com.bartlomiejpluta.ttsserver.core.web.endpoint.Endpoint
|
||||
import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService
|
||||
import com.bartlomiejpluta.ttsserver.service.state.ServiceState
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey
|
||||
import com.vmichalak.sonoscontroller.Snapshot
|
||||
import com.vmichalak.sonoscontroller.SonosDevice
|
||||
import com.vmichalak.sonoscontroller.SonosDiscovery
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.bartlomiejpluta.ttsserver.core.tts.model.TTSStream
|
||||
import com.bartlomiejpluta.ttsserver.core.tts.status.TTSStatus
|
||||
import com.bartlomiejpluta.ttsserver.core.tts.status.TTSStatusHolder
|
||||
import com.bartlomiejpluta.ttsserver.core.util.AudioConverter
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.content.Context
|
||||
import android.content.Context.WIFI_SERVICE
|
||||
import android.content.SharedPreferences
|
||||
import android.net.wifi.WifiManager
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey
|
||||
import java.net.InetAddress
|
||||
|
||||
|
||||
|
||||
@@ -18,13 +18,15 @@ import com.bartlomiejpluta.ttsserver.core.web.exception.WebException
|
||||
import com.bartlomiejpluta.ttsserver.core.web.mime.MimeType
|
||||
import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService
|
||||
import com.bartlomiejpluta.ttsserver.service.state.ServiceState
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.model.TimeRange
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
import fi.iki.elonen.NanoHTTPD.Response.Status.*
|
||||
import org.json.JSONObject
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.*
|
||||
|
||||
|
||||
class WebServer(
|
||||
@@ -34,6 +36,20 @@ class WebServer(
|
||||
private val tts: TTSEngine,
|
||||
private val sonos: SonosQueue
|
||||
) : NanoHTTPD(port) {
|
||||
private val speakersSilenceSchedulerEnabled: Boolean
|
||||
get() = preferences.getBoolean(PreferenceKey.ENABLE_SPEAKERS_SILENCE_SCHEDULER, false)
|
||||
|
||||
private val sonosSilenceSchedulerEnabled: Boolean
|
||||
get() = preferences.getBoolean(PreferenceKey.ENABLE_SONOS_SILENCE_SCHEDULER, false)
|
||||
|
||||
private val speakersSilenceSchedule: TimeRange
|
||||
get() = preferences.getString(PreferenceKey.SPEAKERS_SILENCE_SCHEDULE, "")!!
|
||||
.let { TimeRange.parse(it) }
|
||||
|
||||
private val sonosSilenceSchedule: TimeRange
|
||||
get() = preferences.getString(PreferenceKey.SONOS_SILENCE_SCHEDULE, "")!!
|
||||
.let { TimeRange.parse(it) }
|
||||
|
||||
override fun serve(session: IHTTPSession?): Response {
|
||||
try {
|
||||
assertThatTTSIsReady()
|
||||
@@ -97,6 +113,10 @@ class WebServer(
|
||||
throw WebException(BAD_REQUEST, "Only JSON data is accepted")
|
||||
}
|
||||
|
||||
if (speakersSilenceSchedulerEnabled && speakersSilenceSchedule.inRange(Calendar.getInstance())) {
|
||||
return newFixedLengthResponse(NO_CONTENT, MIME_JSON, "")
|
||||
}
|
||||
|
||||
val dto = extractBody(session) { BaseDTO(it) }
|
||||
|
||||
tts.performTTS(dto.text, dto.language)
|
||||
@@ -142,6 +162,10 @@ class WebServer(
|
||||
throw WebException(BAD_REQUEST, "Only JSON data is accepted")
|
||||
}
|
||||
|
||||
if (sonosSilenceSchedulerEnabled && sonosSilenceSchedule.inRange(Calendar.getInstance())) {
|
||||
return newFixedLengthResponse(NO_CONTENT, MIME_JSON, "")
|
||||
}
|
||||
|
||||
val dto = extractBody(session) { SonosDTO(it) }
|
||||
|
||||
sonos.push(dto)
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.bartlomiejpluta.ttsserver.core.sonos.queue.SonosQueue
|
||||
import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey
|
||||
|
||||
class WebServerFactory(
|
||||
private val preferences: SharedPreferences,
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bartlomiejpluta.ttsserver.di.module
|
||||
import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService
|
||||
import com.bartlomiejpluta.ttsserver.ui.help.HelpActivity
|
||||
import com.bartlomiejpluta.ttsserver.ui.main.MainActivity
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferencesActivity
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.component.PreferencesActivity
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.bartlomiejpluta.ttsserver.core.util.NetworkUtil
|
||||
import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService
|
||||
import com.bartlomiejpluta.ttsserver.service.state.ServiceState
|
||||
import com.bartlomiejpluta.ttsserver.ui.help.HelpActivity
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.PreferencesActivity
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.component.PreferencesActivity
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference.component
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@@ -11,7 +11,9 @@ class PreferencesActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_preferences)
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.preferences, PreferencesFragment())
|
||||
.replace(R.id.preferences,
|
||||
PreferencesFragment()
|
||||
)
|
||||
.commit()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference.component
|
||||
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -15,6 +16,9 @@ import com.bartlomiejpluta.R
|
||||
import com.bartlomiejpluta.ttsserver.core.web.mime.MimeType
|
||||
import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService
|
||||
import com.bartlomiejpluta.ttsserver.service.state.ServiceState
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.model.TimeRange
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey
|
||||
import com.bartlomiejpluta.ttsserver.ui.preference.custom.IntEditTextPreference
|
||||
|
||||
|
||||
class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
@@ -25,6 +29,8 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
private lateinit var httpDebugPreference: SwitchPreference
|
||||
private lateinit var enableGongPreference: SwitchPreference
|
||||
private lateinit var ttsEnginePreference: Preference
|
||||
private lateinit var enableSonosSilenceScheduler: SwitchPreference
|
||||
private lateinit var enableSpeakersSilenceScheduler: SwitchPreference
|
||||
private lateinit var clearSonosCachePreference: Preference
|
||||
|
||||
private val receiver = object : BroadcastReceiver() {
|
||||
@@ -75,6 +81,82 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
startActivity(Intent(ANDROID_TTS_SETTINGS))
|
||||
true
|
||||
}
|
||||
enableSpeakersSilenceScheduler = findPreference(PreferenceKey.ENABLE_SPEAKERS_SILENCE_SCHEDULER)!!
|
||||
enableSpeakersSilenceScheduler.setOnPreferenceClickListener { preference ->
|
||||
if(!enableSpeakersSilenceScheduler.isChecked) {
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
enableSpeakersSilenceScheduler.isChecked = false
|
||||
|
||||
val schedule = preference
|
||||
.sharedPreferences
|
||||
.getString(
|
||||
PreferenceKey.SPEAKERS_SILENCE_SCHEDULE,
|
||||
DEFAULT_SCHEDULE
|
||||
)!!
|
||||
.let {
|
||||
TimeRange.parse(
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
TimePickerDialog(context, { _, newBeginHour, newBeginMinute ->
|
||||
TimePickerDialog(context, { _, newEndHour, newEndMinute ->
|
||||
preference.sharedPreferences.edit()?.let { editor ->
|
||||
val newSchedule =
|
||||
TimeRange(
|
||||
newBeginHour,
|
||||
newBeginMinute,
|
||||
newEndHour,
|
||||
newEndMinute
|
||||
)
|
||||
editor.putString(PreferenceKey.SPEAKERS_SILENCE_SCHEDULE, newSchedule.toString())
|
||||
editor.apply()
|
||||
enableSpeakersSilenceScheduler.isChecked = true
|
||||
}
|
||||
}, schedule.endHour, schedule.endMinute, true).show()
|
||||
}, schedule.beginHour, schedule.beginMinute, true).show()
|
||||
|
||||
true
|
||||
}
|
||||
enableSonosSilenceScheduler = findPreference(PreferenceKey.ENABLE_SONOS_SILENCE_SCHEDULER)!!
|
||||
enableSonosSilenceScheduler.setOnPreferenceClickListener { preference ->
|
||||
if(!enableSonosSilenceScheduler.isChecked) {
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
enableSonosSilenceScheduler.isChecked = false
|
||||
|
||||
val schedule = preference
|
||||
.sharedPreferences
|
||||
.getString(
|
||||
PreferenceKey.SONOS_SILENCE_SCHEDULE,
|
||||
DEFAULT_SCHEDULE
|
||||
)!!
|
||||
.let {
|
||||
TimeRange.parse(
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
TimePickerDialog(context, { _, newBeginHour, newBeginMinute ->
|
||||
TimePickerDialog(context, { _, newEndHour, newEndMinute ->
|
||||
preference.sharedPreferences.edit()?.let { editor ->
|
||||
val newSchedule =
|
||||
TimeRange(
|
||||
newBeginHour,
|
||||
newBeginMinute,
|
||||
newEndHour,
|
||||
newEndMinute
|
||||
)
|
||||
editor.putString(PreferenceKey.SONOS_SILENCE_SCHEDULE, newSchedule.toString())
|
||||
editor.apply()
|
||||
enableSonosSilenceScheduler.isChecked = true
|
||||
}
|
||||
}, schedule.endHour, schedule.endMinute, true).show()
|
||||
}, schedule.beginHour, schedule.beginMinute, true).show()
|
||||
|
||||
true
|
||||
}
|
||||
clearSonosCachePreference = findPreference(PreferenceKey.INVALIDATE_SONOS_CACHE)!!
|
||||
clearSonosCachePreference.setOnPreferenceClickListener {
|
||||
context?.cacheDir?.listFiles()?.forEach { it.delete() }
|
||||
@@ -94,7 +176,9 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
.apply { type = MimeType.WAV.mimeType }
|
||||
.let { Intent.createChooser(it, getString(R.string.preference_gong_picker_prompt)) }
|
||||
|
||||
startActivityForResult(intent, PICKFILE_RESULT_CODE)
|
||||
startActivityForResult(intent,
|
||||
PICKFILE_RESULT_CODE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,5 +202,6 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
companion object {
|
||||
private const val ANDROID_TTS_SETTINGS = "com.android.settings.TTS_SETTINGS"
|
||||
private const val PICKFILE_RESULT_CODE = 1
|
||||
private val DEFAULT_SCHEDULE = "22:00-07:00"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference.custom
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference.key
|
||||
|
||||
|
||||
object PreferenceKey {
|
||||
@@ -10,5 +10,9 @@ object PreferenceKey {
|
||||
const val ENABLE_GONG = "preference_enable_gong"
|
||||
const val GONG = "preference_gong"
|
||||
const val TTS = "preference_tts"
|
||||
const val ENABLE_SPEAKERS_SILENCE_SCHEDULER = "preference_enable_speakers_silence_scheduler"
|
||||
const val SPEAKERS_SILENCE_SCHEDULE = "preference_speakers_silence_schedule"
|
||||
const val ENABLE_SONOS_SILENCE_SCHEDULER = "preference_enable_sonos_silence_scheduler"
|
||||
const val SONOS_SILENCE_SCHEDULE = "preference_sonos_silence_schedule"
|
||||
const val INVALIDATE_SONOS_CACHE = "preference_invalidate_sonos_cache"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.bartlomiejpluta.ttsserver.ui.preference.model
|
||||
|
||||
import java.util.*
|
||||
|
||||
data class TimeRange(val beginHour: Int, val beginMinute: Int, val endHour: Int, val endMinute: Int) {
|
||||
private val begin: Int
|
||||
get() = beginHour * 60 + beginMinute
|
||||
|
||||
private val end: Int
|
||||
get() = endHour * 60 + endMinute
|
||||
|
||||
fun inRange(calendar: Calendar): Boolean {
|
||||
val current = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)
|
||||
return when {
|
||||
begin <= end -> current in begin..end
|
||||
else -> !(current in end..begin)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString() = "$beginHour:$beginMinute-$endHour:$endMinute"
|
||||
|
||||
companion object {
|
||||
fun parse(range: String): TimeRange {
|
||||
val (beginTime, endTime) = range.splitAndMap("-") { it }
|
||||
val (beginHour, beginMinute) = beginTime.splitAndMap(":") { it.toInt() }
|
||||
val (endHour, endMinute) = endTime.splitAndMap(":") { it.toInt() }
|
||||
return TimeRange(
|
||||
beginHour,
|
||||
beginMinute,
|
||||
endHour,
|
||||
endMinute
|
||||
)
|
||||
}
|
||||
|
||||
private fun <T> String.splitAndMap(delimiter: String, mapper: (String) -> T): List<T> {
|
||||
return this.split(delimiter)
|
||||
.map { mapper(it) }
|
||||
.takeIf { it.size == 2 }
|
||||
?: throw IllegalArgumentException("Expected format: HH:mm-HH:mm")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,16 @@
|
||||
<string name="preference_enable_gong_title">Enable gong</string>
|
||||
<string name="preference_tts_summary">Go to platform\'s TTS engine settings and adjust its parameters</string>
|
||||
<string name="preference_tts_title">TTS engine settings</string>
|
||||
<string name="preference_enable_speakers_silence_scheduler_summary">Determine a time range when /say endpoint should be disabled</string>
|
||||
<string name="preference_enable_speakers_silence_scheduler_title">Enable silence scheduler</string>
|
||||
<string name="preference_enable_sonos_silence_scheduler_summary">Determine a time range when /sonos endpoint should be disabled</string>
|
||||
<string name="preference_enable_sonos_silence_scheduler_title">Enable silence scheduler</string>
|
||||
<string name="preference_invalidate_sonos_cache_summary">Clear application cache directory from already generated Sonos TTS data for given sentences. You typically want to do it when you change the TTS engine\'s voice settings.</string>
|
||||
<string name="preference_invalidate_sonos_cache_title">Invalidate Sonos cache</string>
|
||||
<string name="preference_category_server">Server</string>
|
||||
<string name="preference_category_features">Features</string>
|
||||
<string name="preference_category_tts">TTS engine</string>
|
||||
<string name="preference_category_speakers">Speakers</string>
|
||||
<string name="preference_category_sonos">Sonos</string>
|
||||
<string name="preference_invalidate_sonos_cache_toast">Sonos cache has been invalidated</string>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory android:title="@string/preference_category_server" app:iconSpaceReserved="false">
|
||||
<com.bartlomiejpluta.ttsserver.ui.preference.IntEditTextPreference
|
||||
<com.bartlomiejpluta.ttsserver.ui.preference.custom.IntEditTextPreference
|
||||
android:defaultValue="8080"
|
||||
android:inputType="number"
|
||||
android:key="preference_port"
|
||||
@@ -54,7 +54,21 @@
|
||||
app:iconSpaceReserved="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/preference_category_speakers" app:iconSpaceReserved="false">
|
||||
<SwitchPreference
|
||||
android:key="preference_enable_speakers_silence_scheduler"
|
||||
android:summary="@string/preference_enable_speakers_silence_scheduler_summary"
|
||||
app:title="@string/preference_enable_speakers_silence_scheduler_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/preference_category_sonos" app:iconSpaceReserved="false">
|
||||
<SwitchPreference
|
||||
android:key="preference_enable_sonos_silence_scheduler"
|
||||
android:summary="@string/preference_enable_sonos_silence_scheduler_summary"
|
||||
app:title="@string/preference_enable_sonos_silence_scheduler_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<Preference
|
||||
android:key="preference_invalidate_sonos_cache"
|
||||
android:summary="@string/preference_invalidate_sonos_cache_summary"
|
||||
|
||||
Reference in New Issue
Block a user