From 7b4420ddbd8d3f4c5005377879daaba44ddbd0dd Mon Sep 17 00:00:00 2001 From: rdkartono Date: Fri, 13 Feb 2026 17:04:20 +0700 Subject: [PATCH] commit 13/02/2026 --- src/Main.kt | 35 ++- src/MainExtension01.kt | 101 ++++---- src/codes/Somecodes.kt | 8 +- .../TCP_Android_Command_Server.kt | 29 +-- src/database/MariaDB.kt | 5 +- src/database/data/QueueTable.kt | 2 +- src/database/table/Table_Adzan.kt | 240 +++++++++++++----- src/database/table/Table_BroadcastZones.kt | 5 +- src/database/table/Table_Messagebank.kt | 21 ++ src/web/WebApp.kt | 117 +++++---- 10 files changed, 365 insertions(+), 198 deletions(-) diff --git a/src/Main.kt b/src/Main.kt index 145e5ab..f54e8a3 100644 --- a/src/Main.kt +++ b/src/Main.kt @@ -16,10 +16,13 @@ import content.Language import content.VoiceType import database.data.Log import database.MariaDB +import database.data.QueueTable import database.table.Table_Adzan import database.table.Table_BroadcastZones import database.table.Table_Logs import database.table.Table_Messagebank +import database.table.Table_QueuePaging +import database.table.Table_QueueSoundbank import database.table.Table_SoundChannel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -55,6 +58,8 @@ val apptick : Long = System.currentTimeMillis() lateinit var broadcastDB: Table_BroadcastZones lateinit var soundchannelDB: Table_SoundChannel lateinit var messageDB: Table_Messagebank +lateinit var queuetableDB: Table_QueueSoundbank +lateinit var queuepagingDB: Table_QueuePaging lateinit var logDB: Table_Logs lateinit var adzanTable : Table_Adzan @@ -182,6 +187,7 @@ fun main(args: Array) { longitude = config.Get(configKeys.LONGITUDE.key).toDouble(), timezone = TimeZone.getTimeZone(config.Get(configKeys.TIMEZONE.key)) ) + adzanTable.GetTodayPrayerTimes() val subcode01 = MainExtension01() @@ -190,18 +196,35 @@ fun main(args: Array) { CoroutineScope(Dispatchers.Default).launch { while (isActive) { delay(1000) + + adzanTable.CheckTime()?.let{ adz -> + Logger.info { "It's time for Adzan ${adz.prayerName} at ${adz.timeString}" } + val qt = QueueTable( + Source = "AAS", + Type = "ADZAN", + Message = adz.message, + Language = adzanTable.adzan_language, + SB_TAGS = adz.sb_tags, + BroadcastZones = adzanTable.adzan_broadcastzones + ) + queuetableDB.Add(qt) + } + + // prioritas 1 , habisin queue paging if (subcode01.Read_Queue_Paging()){ // processing paging, skip selanjutnya delay(2000) continue } - // prioritas 2, habisin queue shalat - if (subcode01.Read_Queue_Shalat()){ - // processing shalat, skip selanjutnya - delay(2000) - continue - } +// // prioritas 2, habisin queue shalat +// if (subcode01.Read_Queue_Shalat()){ +// // processing shalat, skip selanjutnya +// delay(2000) +// continue +// } + + // prioritas 3, habisin queue timer if (subcode01.Read_Queue_Timer()){ // processing timer, skip selanjutnya diff --git a/src/MainExtension01.kt b/src/MainExtension01.kt index 39757cb..b0f81f0 100644 --- a/src/MainExtension01.kt +++ b/src/MainExtension01.kt @@ -9,7 +9,6 @@ import codes.Somecodes.Companion.SoundbankResult_directory import codes.Somecodes.Companion.ValidFile import codes.Somecodes.Companion.ValidString import codes.Somecodes.Companion.dateformat1 -import codes.Somecodes.Companion.datetimeformat1 import codes.Somecodes.Companion.timeformat2 import codes.configKeys import content.Category @@ -22,7 +21,6 @@ import database.data.Soundbank import org.tinylog.Logger import java.time.DayOfWeek import java.time.LocalDate -import java.time.LocalDateTime import java.time.LocalTime /** @@ -676,8 +674,8 @@ class MainExtension01 { * @return true if a paging job is processed and started streaming, false otherwise */ fun Read_Queue_Paging(): Boolean { - db.queuepagingDB.Get() - val qp = db.queuepagingDB.List.firstOrNull { it.Type.equals("PAGING", true) } + queuepagingDB.Get() + val qp = queuepagingDB.List.firstOrNull { it.Type.equals("PAGING", true) } if (qp == null) return false try { if (!ValidFile(qp.Message)) throw Exception("Invalid audio file ${qp.Message}") @@ -722,14 +720,14 @@ class MainExtension01 { "Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}" Logger.info { logmessage } logDB.Add("AAS", logmessage) - db.queuepagingDB.DeleteByIndex(qp.index.toInt()) - db.queuepagingDB.Resort() + queuepagingDB.DeleteByIndex(qp.index.toInt()) + queuepagingDB.Resort() return true } else throw Exception("Audio file ${qp.Message} is not valid") } } catch (e: Exception) { - db.queuepagingDB.DeleteByIndex(qp.index.toInt()) - db.queuepagingDB.Resort() + queuepagingDB.DeleteByIndex(qp.index.toInt()) + queuepagingDB.Resort() val msg = "Canceled paging message $qp due to exception: ${e.message}" logDB.Add("AAS", msg) Logger.error { msg } @@ -742,8 +740,8 @@ class MainExtension01 { * @return true if a shalat job is processed and started streaming, false otherwise */ fun Read_Queue_Shalat(): Boolean { - db.queuepagingDB.Get() - val qp = db.queuepagingDB.List.firstOrNull { it.Type.equals("SHALAT", true) } + queuepagingDB.Get() + val qp = queuepagingDB.List.firstOrNull { it.Type.equals("SHALAT", true) } if (qp == null) return false try { val ann_id = Get_ANN_ID(qp.Message) @@ -829,14 +827,14 @@ class MainExtension01 { "Broadcast started SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}" Logger.info { logmsg } logDB.Add("AAS", logmsg) - db.queuepagingDB.DeleteByIndex(qp.index.toInt()) - db.queuepagingDB.Resort() + queuepagingDB.DeleteByIndex(qp.index.toInt()) + queuepagingDB.Resort() return true } } catch (e: Exception) { - db.queuepagingDB.DeleteByIndex(qp.index.toInt()) - db.queuepagingDB.Resort() + queuepagingDB.DeleteByIndex(qp.index.toInt()) + queuepagingDB.Resort() val msg = "Canceled shalat message $qp due to exception: ${e.message}" logDB.Add("AAS", msg) Logger.error { msg } @@ -849,8 +847,8 @@ class MainExtension01 { * @return true if a timer job is processed and started streaming, false otherwise */ fun Read_Queue_Timer(): Boolean { - db.queuetableDB.Get() - val qa = db.queuetableDB.List.firstOrNull { it.Type.equals("TIMER", true) } + queuetableDB.Get() + val qa = queuetableDB.List.firstOrNull { it.Type.equals("TIMER", true) } if (qa == null) return false try { val ann_id = Get_ANN_ID(qa.SB_TAGS) @@ -928,14 +926,14 @@ class MainExtension01 { "Broadcast started TIMER message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" Logger.info { logmsg } logDB.Add("AAS", logmsg) - db.queuetableDB.DeleteByIndex(qa.index.toInt()) - db.queuetableDB.Resort() + queuetableDB.DeleteByIndex(qa.index.toInt()) + queuetableDB.Resort() return true } } catch (e: Exception) { - db.queuetableDB.DeleteByIndex(qa.index.toInt()) - db.queuetableDB.Resort() + queuetableDB.DeleteByIndex(qa.index.toInt()) + queuetableDB.Resort() val msg = "Canceled TIMER message $qa due to exception: ${e.message}" logDB.Add("AAS", msg) Logger.error { msg } @@ -949,8 +947,8 @@ class MainExtension01 { * @return true if a soundbank job is processed and started streaming, false otherwise */ fun Read_Queue_Soundbank(): Boolean { - db.queuetableDB.Get() - val qa = db.queuetableDB.List.firstOrNull { it.Type.equals("SOUNDBANK", true) } + queuetableDB.Get() + val qa = queuetableDB.List.firstOrNull { it.Type.equals("SOUNDBANK", true) } if (qa == null) return false //println("Processing $qa") try { @@ -1084,8 +1082,8 @@ class MainExtension01 { "Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" Logger.info { logmsg } logDB.Add("AAS", logmsg) - db.queuetableDB.DeleteByIndex(qa.index.toInt()) - db.queuetableDB.Resort() + queuetableDB.DeleteByIndex(qa.index.toInt()) + queuetableDB.Resort() return true } @@ -1094,8 +1092,8 @@ class MainExtension01 { val msg = "Canceled SOUNDBANK message $qa due to exception: ${e.message}" logDB.Add("AAS", msg) Logger.error { msg } - db.queuetableDB.DeleteByIndex(qa.index.toInt()) - db.queuetableDB.Resort() + queuetableDB.DeleteByIndex(qa.index.toInt()) + queuetableDB.Resort() } return false } @@ -1125,17 +1123,14 @@ class MainExtension01 { } if (specialdate != null) { val qt = QueueTable( - 0u, - LocalDateTime.now().format(datetimeformat1), - "AAS", - "TIMER", - specialdate.Description, - specialdate.Soundpath, - specialdate.BroadcastZones, - 1.toUInt(), - specialdate.Language + Source="AAS", + Type="TIMER", + Message=specialdate.Description, + SB_TAGS = specialdate.Soundpath, + BroadcastZones = specialdate.BroadcastZones, + Language = specialdate.Language ) - db.queuetableDB.Add(qt) + queuetableDB.Add(qt) return } @@ -1153,17 +1148,14 @@ class MainExtension01 { } if (weekly != null) { val qt = QueueTable( - 0u, - LocalDateTime.now().format(datetimeformat1), - "AAS", - "TIMER", - weekly.Description, - weekly.Soundpath, - weekly.BroadcastZones, - 1.toUInt(), - weekly.Language + Source="AAS", + Type="TIMER", + Message=weekly.Description, + SB_TAGS = weekly.Soundpath, + BroadcastZones = weekly.BroadcastZones, + Language = weekly.Language ) - db.queuetableDB.Add(qt) + queuetableDB.Add(qt) return } @@ -1173,17 +1165,14 @@ class MainExtension01 { } if (daily != null) { val qt = QueueTable( - 0u, - LocalDateTime.now().format(datetimeformat1), - "AAS", - "TIMER", - daily.Description, - daily.Soundpath, - daily.BroadcastZones, - 1.toUInt(), - daily.Language + Source="AAS", + Type="TIMER", + Message = daily.Description, + SB_TAGS = daily.Soundpath, + BroadcastZones = daily.BroadcastZones, + Language = daily.Language ) - db.queuetableDB.Add(qt) + queuetableDB.Add(qt) return } diff --git a/src/codes/Somecodes.kt b/src/codes/Somecodes.kt index d872879..0a7e3f2 100644 --- a/src/codes/Somecodes.kt +++ b/src/codes/Somecodes.kt @@ -710,7 +710,13 @@ class Somecodes { return false } - + /** + * Get a list of all available time zones. + * @return A list of strings representing the available time zones. + */ + fun Get_TimeZones() : List{ + return ZoneId.getAvailableZoneIds().sorted() + } /** * Find a schedule day by its name. diff --git a/src/commandServer/TCP_Android_Command_Server.kt b/src/commandServer/TCP_Android_Command_Server.kt index 2b6c095..bb3bd82 100644 --- a/src/commandServer/TCP_Android_Command_Server.kt +++ b/src/commandServer/TCP_Android_Command_Server.kt @@ -17,6 +17,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import messageDB import org.tinylog.Logger +import queuepagingDB +import queuetableDB import tcpreceiver import udpreceiver import java.net.ServerSocket @@ -234,8 +236,8 @@ class TCP_Android_Command_Server { pj.broadcastzones ) Logger.info{"Inserting paging audio to queue paging table from Android $key, data=$qp"} - if (db.queuepagingDB.Add(qp)) { - db.queuepagingDB.Resort() + if (queuepagingDB.Add(qp)) { + queuepagingDB.Resort() logcb.accept("Paging audio inserted to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}") cb.accept("PCMFILE_STOP;OK@") return @@ -289,8 +291,8 @@ class TCP_Android_Command_Server { pj.filePath.absolutePathString(), pj.broadcastzones ) - if (db.queuepagingDB.Add(qp)){ - db.queuepagingDB.Resort() + if (queuepagingDB.Add(qp)){ + queuepagingDB.Resort() logcb.accept("Paging audio inserted to queue paging table from IPM $key, file ${pj.filePath.absolutePathString()}") cb.accept("STOPPAGINGAND;OK@") return @@ -579,18 +581,15 @@ class TCP_Android_Command_Server { if (ValidString(tags)){ if (ValidString(zone)){ val qt = QueueTable( - 0u, - LocalDateTime.now().format(datetimeformat1), - "ANDROID", - "SOUNDBANK", - desc, - tags, - zone, - 1u, - lang + Source="ANDROID", + Type="SOUNDBANK", + Message=desc, + SB_TAGS = tags, + BroadcastZones = zone, + Language = lang ) - if (db.queuetableDB.Add(qt)){ - db.queuetableDB.Resort() + if (queuetableDB.Add(qt)){ + queuetableDB.Resort() logcb.accept("Broadcast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} inserted. Message: $desc;$lang;$tags;$zone") cb.accept("BROADCASTAND;OK@") return diff --git a/src/database/MariaDB.kt b/src/database/MariaDB.kt index 75ccdf1..f5d5ad9 100644 --- a/src/database/MariaDB.kt +++ b/src/database/MariaDB.kt @@ -24,6 +24,8 @@ import database.table.Table_Users import messageDB import broadcastDB import logDB +import queuepagingDB +import queuetableDB import soundchannelDB class MariaDB { @@ -32,8 +34,7 @@ class MariaDB { lateinit var soundDB: Table_Soundbank lateinit var languageDB: Table_LanguageLink lateinit var scheduleDB: Table_Schedule - lateinit var queuetableDB: Table_QueueSoundbank - lateinit var queuepagingDB: Table_QueuePaging + lateinit var userDB: Table_Users diff --git a/src/database/data/QueueTable.kt b/src/database/data/QueueTable.kt index ba4f4c5..cf680dd 100644 --- a/src/database/data/QueueTable.kt +++ b/src/database/data/QueueTable.kt @@ -4,7 +4,7 @@ import codes.Somecodes.Companion.datetimeformat1 import java.time.Duration import java.time.LocalDateTime -data class QueueTable(var index: UInt, var Date_Time: String, var Source: String, var Type: String, var Message: String, var SB_TAGS: String, var BroadcastZones: String, var Repeat: UInt, var Language: String){ +data class QueueTable(var index: UInt=0u, var Date_Time: String =LocalDateTime.now().format(datetimeformat1), var Source: String, var Type: String, var Message: String, var SB_TAGS: String, var BroadcastZones: String, var Repeat: UInt=1u, var Language: String){ /** * Check if all fields are not empty diff --git a/src/database/table/Table_Adzan.kt b/src/database/table/Table_Adzan.kt index 49e4078..a899717 100644 --- a/src/database/table/Table_Adzan.kt +++ b/src/database/table/Table_Adzan.kt @@ -1,12 +1,17 @@ package database.table +import codes.Somecodes.Companion.timeformat2 import com.batoulapps.adhan.CalculationMethod import com.batoulapps.adhan.CalculationParameters import com.batoulapps.adhan.Coordinates import com.batoulapps.adhan.Madhab import com.batoulapps.adhan.PrayerTimes import com.batoulapps.adhan.data.DateComponents +import content.Language +import messageDB +import org.tinylog.Logger import java.text.SimpleDateFormat +import java.time.LocalTime import java.util.Date import java.util.TimeZone @@ -16,7 +21,6 @@ import java.util.TimeZone * @param longitude The longitude of the location. Default is Monas, Jakarta (longitude: 106.8272). * @param timezone The time zone for formatting prayer times. Default is "Asia/Jakarta". */ -@Suppress("unused") class Table_Adzan(val latitude: Double = -6.1751, val longitude: Double = 106.8272, val timezone : TimeZone = TimeZone.getTimeZone("Asia/Jakarta")) { var coordinate: Coordinates = Coordinates(latitude, longitude) @@ -30,11 +34,21 @@ class Table_Adzan(val latitude: Double = -6.1751, val longitude: Double = 106.82 var maghrib_enable = false var isya_enable = false - var fajar_sound = "" - var dzuhur_sound = "" - var ashar_sound = "" - var maghrib_sound = "" - var isya_sound = "" + var fajar_message = "" + var dzuhur_message = "" + var ashar_message = "" + var maghrib_message = "" + var isya_message = "" + + var fajar_time = "" + var dzuhur_time = "" + var ashar_time = "" + var maghrib_time = "" + var isya_time = "" + + var adzan_broadcastzones = "" + + var adzan_language = Language.DEFAULT.value init{ // sumber chatgpt Kemenag @@ -44,14 +58,93 @@ class Table_Adzan(val latitude: Double = -6.1751, val longitude: Double = 106.82 timeformatter.timeZone = timezone } - /** - * Change the time zone used for formatting prayer times. - * @param timezone The new AdzanTimeZone. - */ - fun ChangeTimezone(timezone: AdzanTimeZone) { - ChangeTimeZone(timezone.toTimeZoneString()) + data class AdzanTask( + val prayerName : String, + val timeString : String, + val message : String, + val sb_tags : String + ) + + fun CheckTime() : AdzanTask?{ + val hhmm = LocalTime.now().format(timeformat2) + if (hhmm == fajar_time){ + if (fajar_enable){ + val mb = messageDB.Find_Messagebank(fajar_message, adzan_language) + if (mb!=null){ + return AdzanTask( + "Fajar", + fajar_time, + mb.Description, + mb.Message_TAGS + ) + } else Logger.error { "Skipped Adzan Fajar because Unable to find $fajar_message in messageDB" } + } else Logger.info{"Skipped Adzan Fajar because fajr_enable is false"} + } + if (hhmm == dzuhur_time){ + if (dzuhur_enable){ + val mb = messageDB.Find_Messagebank(dzuhur_message, adzan_language) + if (mb!=null){ + return AdzanTask( + "Dzuhur", + dzuhur_time, + mb.Description, + mb.Message_TAGS + ) + } else Logger.error { "Skipped Adzan Dzuhur because Unable to find $dzuhur_message in messageDB" } + } else Logger.info{"Skipped Adzan Dzuhur because dzuhur_enable is false"} + } + if (hhmm == ashar_time) { + if (ashar_enable){ + val mb = messageDB.Find_Messagebank(ashar_message, adzan_language) + if (mb!=null){ + return AdzanTask( + "Ashar", + ashar_time, + mb.Description, + mb.Message_TAGS + ) + } else Logger.error { "Skipped Adzan Ashar because Unable to find $ashar_message in messageDB" } + } else Logger.info{"Skipped Adzan Ashar because ashar_enable is false"} + } + if (hhmm == maghrib_time){ + if (maghrib_enable){ + val mb = messageDB.Find_Messagebank(maghrib_message, adzan_language) + if (mb!=null){ + return AdzanTask( + "Maghrib", + maghrib_time, + mb.Description, + mb.Message_TAGS + ) + } else Logger.error { "Skipped Adzan Maghrib because Unable to find $maghrib_message in messageDB" } + + } else Logger.info{"Skipped Adzan Maghrib because maghrib_enable is false"} + } + if (hhmm == isya_time) { + if (isya_enable){ + val mb = messageDB.Find_Messagebank(isya_message, adzan_language) + if (mb!=null){ + return AdzanTask( + "Isya", + isya_time, + mb.Description, + mb.Message_TAGS + ) + } else Logger.error { "Skipped Adzan Isya because Unable to find $isya_message in messageDB" } + + } else Logger.info{"Skipped Adzan Isya because isya_enable is false"} + } + return null } +// /** +// * Change the time zone used for formatting prayer times. +// * @param timezone The new AdzanTimeZone. +// */ +// fun ChangeTimezone(timezone: AdzanTimeZone) { +// ChangeTimeZone(timezone.toTimeZoneString()) +// } + /** * Change the time zone used for formatting prayer times. * @param timezoneString The new time zone string (e.g., "Asia/Jakarta"). @@ -60,29 +153,29 @@ class Table_Adzan(val latitude: Double = -6.1751, val longitude: Double = 106.82 timeformatter.timeZone = TimeZone.getTimeZone(timezoneString) } - /** - * Set prayer time adjustments in minutes. - * @param fajrMinute Adjustment for Fajr prayer time in minutes. - * @param dhuhrMinute Adjustment for Dhuhr prayer time in minutes. - * @param asrMinute Adjustment for Asr prayer time in minutes. - * @param maghribMinute Adjustment for Maghrib prayer time in minutes. - * @param ishaMinute Adjustment for Isha prayer time in minutes. - */ - fun SetPrayerAdjustment(fajrMinute: Int = 0, dhuhrMinute: Int = 0, asrMinute: Int = 0,maghribMinute: Int = 0, ishaMinute: Int = 0) { - params.adjustments.fajr = fajrMinute - params.adjustments.dhuhr = dhuhrMinute - params.adjustments.asr = asrMinute - params.adjustments.maghrib = maghribMinute - params.adjustments.isha = ishaMinute - } - /** - * Change the coordinates used for Adzan calculations. - * @param lat The new latitude. - * @param long The new longitude. - */ - fun ChangeCoordinate(lat: Double, long: Double) { - coordinate = Coordinates(lat, long) - } +// /** +// * Set prayer time adjustments in minutes. +// * @param fajrMinute Adjustment for Fajr prayer time in minutes. +// * @param dhuhrMinute Adjustment for Dhuhr prayer time in minutes. +// * @param asrMinute Adjustment for Asr prayer time in minutes. +// * @param maghribMinute Adjustment for Maghrib prayer time in minutes. +// * @param ishaMinute Adjustment for Isha prayer time in minutes. +// */ +// fun SetPrayerAdjustment(fajrMinute: Int = 0, dhuhrMinute: Int = 0, asrMinute: Int = 0,maghribMinute: Int = 0, ishaMinute: Int = 0) { +// params.adjustments.fajr = fajrMinute +// params.adjustments.dhuhr = dhuhrMinute +// params.adjustments.asr = asrMinute +// params.adjustments.maghrib = maghribMinute +// params.adjustments.isha = ishaMinute +// } +// /** +// * Change the coordinates used for Adzan calculations. +// * @param lat The new latitude. +// * @param long The new longitude. +// */ +// fun ChangeCoordinate(lat: Double, long: Double) { +// coordinate = Coordinates(lat, long) +// } fun ChangeLatitude(lat: Double) { coordinate = Coordinates(lat, coordinate.longitude) @@ -92,19 +185,19 @@ class Table_Adzan(val latitude: Double = -6.1751, val longitude: Double = 106.82 coordinate = Coordinates(coordinate.latitude, long) } - /** - * Get prayer times for a specific date string in the format "dd/MM/yyyy". - * @param date_string The date string for which to get prayer times. - * @return An AdzanPrayerTime object containing the prayer times, or null if the date string is invalid. - */ - fun GetPrayerTimes(date_string: String) : AdzanPrayerTime?{ - try{ - val date = dateformatter.parse(date_string) - return GetPrayerTimes(date) - } catch (e: Exception){ - return null - } - } +// /** +// * Get prayer times for a specific date string in the format "dd/MM/yyyy". +// * @param date_string The date string for which to get prayer times. +// * @return An AdzanPrayerTime object containing the prayer times, or null if the date string is invalid. +// */ +// fun GetPrayerTimes(date_string: String) : AdzanPrayerTime?{ +// try{ +// val date = dateformatter.parse(date_string) +// return GetPrayerTimes(date) +// } catch (_: Exception){ +// return null +// } +// } /** * Get prayer times for a specific date. @@ -125,31 +218,38 @@ class Table_Adzan(val latitude: Double = -6.1751, val longitude: Double = 106.82 /** * Get prayer times for the current date. + * this will update fajar_time, dzuhur_time, ashar_time, maghrib_time, isya_time properties * @return An AdzanPrayerTime object containing the prayer times for today. */ fun GetTodayPrayerTimes() : AdzanPrayerTime{ - return GetPrayerTimes(Date()) + val result = GetPrayerTimes(Date()) + fajar_time = result.fajr + dzuhur_time = result.dhuhr + ashar_time = result.asr + maghrib_time = result.maghrib + isya_time = result.isha + return result } - /** - * Get prayer times for all days in a specific month and year. - * @param month The month (1-12) for which to get prayer times. - * @param year The year for which to get prayer times. - * @return A list of AdzanPrayerTime objects for each day in the specified month and year. - */ - fun GetMonthlyPrayerTimes(month: Int, year: Int) : List{ - val prayerTimesList = mutableListOf() - val calendar = java.util.Calendar.getInstance() - calendar.set(year, month - 1, 1) // Month is 0-based in Calendar - val daysInMonth = calendar.getActualMaximum(java.util.Calendar.DAY_OF_MONTH) - - for (day in 1..daysInMonth) { - calendar.set(year, month - 1, day) - val date = calendar.time - val prayerTimes = GetPrayerTimes(date) - prayerTimesList.add(prayerTimes) - } - - return prayerTimesList - } +// /** +// * Get prayer times for all days in a specific month and year. +// * @param month The month (1-12) for which to get prayer times. +// * @param year The year for which to get prayer times. +// * @return A list of AdzanPrayerTime objects for each day in the specified month and year. +// */ +// fun GetMonthlyPrayerTimes(month: Int, year: Int) : List{ +// val prayerTimesList = mutableListOf() +// val calendar = java.util.Calendar.getInstance() +// calendar.set(year, month - 1, 1) // Month is 0-based in Calendar +// val daysInMonth = calendar.getActualMaximum(java.util.Calendar.DAY_OF_MONTH) +// +// for (day in 1..daysInMonth) { +// calendar.set(year, month - 1, day) +// val date = calendar.time +// val prayerTimes = GetPrayerTimes(date) +// prayerTimesList.add(prayerTimes) +// } +// +// return prayerTimesList +// } } \ No newline at end of file diff --git a/src/database/table/Table_BroadcastZones.kt b/src/database/table/Table_BroadcastZones.kt index 0df8d5e..daba80d 100644 --- a/src/database/table/Table_BroadcastZones.kt +++ b/src/database/table/Table_BroadcastZones.kt @@ -1,7 +1,6 @@ package database.table import StreamerOutputs -import broadcastDB import codes.Somecodes.Companion.ValidIPV4 import codes.Somecodes.Companion.ValidString import database.data.BroadcastZones @@ -223,8 +222,8 @@ class Table_BroadcastZones(connection: Connection) : dbFunctions } /** - * Check if all broadcast zones in a comma-separated string are valid - * Valid means the broadcast zone name exists in the BroadcastZones table, its SoundChannel exists in the SoundChannel table, and its IP is valid + * Check if all broadcast zones in a comma-separated string are valid, + * means the broadcast zone name exists in the BroadcastZones table, its SoundChannel exists in the SoundChannel table, and its IP is valid * @param zones Comma-separated string of broadcast zones * @param checkOnline Whether to check if the sound channel is really online, recorded in StreamerOutputs map * @return true if all broadcast zones are valid, false otherwise diff --git a/src/database/table/Table_Messagebank.kt b/src/database/table/Table_Messagebank.kt index cfc2a90..8bb4d8a 100644 --- a/src/database/table/Table_Messagebank.kt +++ b/src/database/table/Table_Messagebank.kt @@ -258,4 +258,25 @@ class Table_Messagebank(connection: Connection) : dbFunctions("mess } return false } + + /** + * Find a messagebank entry based on messagedetail and language + * @param messagedetail the messagedetail in format "message_name [ann_id]" + * @param language the language to find + * @return the messagebank entry if found, null otherwise + */ + fun Find_Messagebank(messagedetail: String, language: String) : Messagebank?{ + return try{ + val match = messageDetailRegex.find(messagedetail) + if (match != null){ + val msg = match.groupValues[1].trim() + val annid = match.groupValues[2].toUIntOrNull() ?: return null // kalau bukan number, return null + List.firstOrNull{ it.ANN_ID == annid && it.Description == msg && it.Language.equals(language, ignoreCase = true) } + } else { + null + } + } catch (_: Exception){ + null + } + } } \ No newline at end of file diff --git a/src/web/WebApp.kt b/src/web/WebApp.kt index 11e06ed..89f0a38 100644 --- a/src/web/WebApp.kt +++ b/src/web/WebApp.kt @@ -55,12 +55,13 @@ import io.javalin.websocket.WsCloseStatus import logDB import messageDB import org.tinylog.Logger +import queuepagingDB +import queuetableDB import soundchannelDB import version import java.io.File import java.nio.ByteBuffer import java.nio.file.Path -import java.util.TimeZone import java.util.UUID @@ -221,7 +222,7 @@ class WebApp(val listenPort: Int, var userlist: List>, val SendReply( wsMessageContext, cmd.command, - objectmapper.writeValueAsString(db.queuepagingDB.List) + objectmapper.writeValueAsString(queuepagingDB.List) ) } @@ -229,7 +230,7 @@ class WebApp(val listenPort: Int, var userlist: List>, val SendReply( wsMessageContext, cmd.command, - objectmapper.writeValueAsString(db.queuetableDB.List) + objectmapper.writeValueAsString(queuetableDB.List) ) } @@ -362,7 +363,7 @@ class WebApp(val listenPort: Int, var userlist: List>, val SendReply( wsMessageContext, cmd.command, - objectmapper.writeValueAsString(db.queuepagingDB.List) + objectmapper.writeValueAsString(queuepagingDB.List) ) } @@ -370,7 +371,7 @@ class WebApp(val listenPort: Int, var userlist: List>, val SendReply( wsMessageContext, cmd.command, - objectmapper.writeValueAsString(db.queuetableDB.List) + objectmapper.writeValueAsString(queuetableDB.List) ) } @@ -2180,8 +2181,8 @@ class WebApp(val listenPort: Int, var userlist: List>, val path("QueuePaging") { get("List") { ctx -> - db.queuepagingDB.Get({ - ctx.json(db.queuepagingDB.List) + queuepagingDB.Get({ + ctx.json(queuepagingDB.List) }, { msgFail -> ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) }) @@ -2189,8 +2190,8 @@ class WebApp(val listenPort: Int, var userlist: List>, val } delete("List") { // truncate queue paging table - if (db.queuepagingDB.Clear()) { - db.queuepagingDB.Get() + if (queuepagingDB.Clear()) { + queuepagingDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500) @@ -2204,8 +2205,8 @@ class WebApp(val listenPort: Int, var userlist: List>, val it.status(400) .result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.queuepagingDB.DeleteByIndex(index.toInt())) { - db.queuepagingDB.Resort() + if (queuepagingDB.DeleteByIndex(index.toInt())) { + queuepagingDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) logDB.Add("AAS", "Deleted queue paging with index $index") } else { @@ -2218,8 +2219,8 @@ class WebApp(val listenPort: Int, var userlist: List>, val } path("QueueTable") { get("List") { ctx -> - db.queuetableDB.Get({ - ctx.json(db.queuetableDB.List) + queuetableDB.Get({ + ctx.json(queuetableDB.List) }, { msgFail -> ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) }) @@ -2227,8 +2228,8 @@ class WebApp(val listenPort: Int, var userlist: List>, val } delete("List") { // truncate queue table - if (db.queuetableDB.Clear()) { - db.queuetableDB.Get() + if (queuetableDB.Clear()) { + queuetableDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500) @@ -2242,8 +2243,8 @@ class WebApp(val listenPort: Int, var userlist: List>, val it.status(400) .result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.queuetableDB.DeleteByIndex(index.toInt())) { - db.queuetableDB.Resort() + if (queuetableDB.DeleteByIndex(index.toInt())) { + queuetableDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) logDB.Add("AAS", "Deleted queue sound with index $index") @@ -2470,28 +2471,30 @@ class WebApp(val listenPort: Int, var userlist: List>, val } } path("Settings") { + get("TimezoneList"){ + it.json(Somecodes.Get_TimeZones()) + } path("AdzanSetting"){ get{ - val todayadzan = adzanTable.GetTodayPrayerTimes() val value = AdzanSetting( latitude = _config.Get(configKeys.LATITUDE.key).toDoubleOrNull() ?: 0.0, longitude = _config.Get(configKeys.LONGITUDE.key).toDoubleOrNull() ?: 0.0, timezone = _config.Get(configKeys.TIMEZONE.key), fajar_sound = _config.Get(configKeys.ADZAN_FAJR_SOUND.key), fajar_enable = _config.Get(configKeys.ADZAN_FAJR_ENABLED.key).toBoolean(), - fajar_time = todayadzan.fajr, + fajar_time = adzanTable.fajar_time, dzuhur_sound = _config.Get(configKeys.ADZAN_DHUHR_SOUND.key), dzuhur_enable = _config.Get(configKeys.ADZAN_DHUHR_ENABLED.key).toBoolean(), - dzuhur_time = todayadzan.dhuhr, + dzuhur_time = adzanTable.dzuhur_time, ashar_sound = _config.Get(configKeys.ADZAN_ASR_SOUND.key), ashar_enable = _config.Get(configKeys.ADZAN_FAJR_ENABLED.key).toBoolean(), - ashar_time = todayadzan.asr, + ashar_time = adzanTable.ashar_time, maghrib_sound = _config.Get(configKeys.ADZAN_MAGHRIB_SOUND.key), maghrib_enable = _config.Get(configKeys.ADZAN_MAGHRIB_ENABLED.key).toBoolean(), - maghrib_time = todayadzan.maghrib, + maghrib_time = adzanTable.maghrib_time, isya_sound = _config.Get(configKeys.ADZAN_ISHA_SOUND.key), isya_enable = _config.Get(configKeys.ADZAN_ISHA_ENABLED.key).toBoolean(), - isya_time = todayadzan.isha + isya_time = adzanTable.isya_time ) it.json(value) } @@ -2499,6 +2502,7 @@ class WebApp(val listenPort: Int, var userlist: List>, val val json: JsonNode = objectmapper.readTree(it.body()) try{ val newsetting = AdzanSetting.FromJsonNode(json) + var need_recalculate_adzan_today = false _config.CompareWithAdzanSetting(newsetting).let { changes -> if (changes.isNotEmpty()){ // something changes @@ -2506,19 +2510,28 @@ class WebApp(val listenPort: Int, var userlist: List>, val _config.Set(change.key, change.newValue) Logger.info{"AdzanSetting change: ${change.key} from ${change.oldValue} to ${change.newValue}"} when(change.key){ - configKeys.LATITUDE.key -> adzanTable.ChangeLatitude(change.newValue.toDouble()) - configKeys.LONGITUDE.key -> adzanTable.ChangeLongitude(change.newValue.toDouble()) - configKeys.TIMEZONE.key -> adzanTable.ChangeTimeZone(change.newValue) + configKeys.LATITUDE.key -> { + adzanTable.ChangeLatitude(change.newValue.toDouble()) + need_recalculate_adzan_today = true + } + configKeys.LONGITUDE.key -> { + adzanTable.ChangeLongitude(change.newValue.toDouble()) + need_recalculate_adzan_today = true + } + configKeys.TIMEZONE.key -> { + adzanTable.ChangeTimeZone(change.newValue) + need_recalculate_adzan_today = true + } configKeys.ADZAN_FAJR_ENABLED.key -> adzanTable.fajar_enable = change.newValue.toBoolean() configKeys.ADZAN_DHUHR_ENABLED.key -> adzanTable.dzuhur_enable = change.newValue.toBoolean() configKeys.ADZAN_ASR_ENABLED.key -> adzanTable.ashar_enable = change.newValue.toBoolean() configKeys.ADZAN_MAGHRIB_ENABLED.key -> adzanTable.maghrib_enable = change.newValue.toBoolean() configKeys.ADZAN_ISHA_ENABLED.key -> adzanTable.isya_enable = change.newValue.toBoolean() - configKeys.ADZAN_FAJR_SOUND.key -> adzanTable.fajar_sound = change.newValue - configKeys.ADZAN_DHUHR_SOUND.key -> adzanTable.dzuhur_sound = change.newValue - configKeys.ADZAN_ASR_SOUND.key -> adzanTable.ashar_sound = change.newValue - configKeys.ADZAN_MAGHRIB_SOUND.key -> adzanTable.maghrib_sound = change.newValue - configKeys.ADZAN_ISHA_SOUND.key -> adzanTable.isya_sound = change.newValue + configKeys.ADZAN_FAJR_SOUND.key -> adzanTable.fajar_message = change.newValue + configKeys.ADZAN_DHUHR_SOUND.key -> adzanTable.dzuhur_message = change.newValue + configKeys.ADZAN_ASR_SOUND.key -> adzanTable.ashar_message = change.newValue + configKeys.ADZAN_MAGHRIB_SOUND.key -> adzanTable.maghrib_message = change.newValue + configKeys.ADZAN_ISHA_SOUND.key -> adzanTable.isya_message = change.newValue else -> { // nothing to do @@ -2531,9 +2544,28 @@ class WebApp(val listenPort: Int, var userlist: List>, val Logger.info { "No changes detected in AdzanSetting"} } } + if (need_recalculate_adzan_today) { + adzanTable.GetTodayPrayerTimes() + } + if (newsetting.fajar_time != adzanTable.fajar_time){ + adzanTable.fajar_time = newsetting.fajar_time + } + if (newsetting.dzuhur_time != adzanTable.dzuhur_time){ + adzanTable.dzuhur_time = newsetting.dzuhur_time + } + if (newsetting.ashar_time != adzanTable.ashar_time){ + adzanTable.ashar_time = newsetting.ashar_time + } + if (newsetting.maghrib_time != adzanTable.maghrib_time){ + adzanTable.maghrib_time = newsetting.maghrib_time + } + if (newsetting.isya_time != adzanTable.isya_time){ + adzanTable.isya_time = newsetting.isya_time + } + Logger.info{"AdzanSetting updated successfully"} + Logger.info{"Today's Prayer Times: Fajar=${adzanTable.fajar_time}, Dzuhur=${adzanTable.dzuhur_time}, Ashar=${adzanTable.ashar_time}, Maghrib=${adzanTable.maghrib_time}, Isya=${adzanTable.isya_time}"} + Logger.info{"Fajar Enabled=${adzanTable.fajar_enable}, Dzuhur Enabled=${adzanTable.dzuhur_enable}, Ashar Enabled=${adzanTable.ashar_enable}, Maghrib Enabled=${adzanTable.maghrib_enable}, Isya Enabled=${adzanTable.isya_enable}"} it.result(objectmapper.writeValueAsString(resultMessage("OK"))) - - } catch (e : Exception){ it.status(400) .result(objectmapper.writeValueAsString(resultMessage("Incomplete AdzanSetting data: ${e.message}"))) @@ -2804,18 +2836,15 @@ class WebApp(val listenPort: Int, var userlist: List>, val if (tags.isNotEmpty()) { if (broadcastzones.isNotEmpty()) { val qt = QueueTable( - 0u, - LocalDateTime.now().format(datetimeformat1), - "SEMIAUTOWEB", - "SOUNDBANK", - description, - tags, - broadcastzones, - 1u, - languages + Source ="SEMIAUTOWEB", + Type="SOUNDBANK", + Message=description, + SB_TAGS =tags, + BroadcastZones = broadcastzones, + Language=languages ) - if (db.queuetableDB.Add(qt)) { - db.queuetableDB.Resort() + if (queuetableDB.Add(qt)) { + queuetableDB.Resort() Logger.info { "SemiAutoWeb added to queue table: $qt" } ctx.result(objectmapper.writeValueAsString(resultMessage("OK"))) db.logSemiAuto.Add(