diff --git a/.gitignore b/.gitignore
index 60e45c6..e8a8e4b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ out/
!**/src/main/**/out/
!**/src/test/**/out/
+
### Kotlin ###
.kotlin
@@ -45,4 +46,7 @@ LOCAL/
chimedown.wav
chimeup.wav
silence1s.wav
-silencehalf.wav
\ No newline at end of file
+silencehalf.wav
+bass*.dll
+bass*.so
+sdx.dll
diff --git a/.idea/artifacts/AAS_NewGen_jar.xml b/.idea/artifacts/AAS_NewGen_jar.xml
new file mode 100644
index 0000000..450298a
--- /dev/null
+++ b/.idea/artifacts/AAS_NewGen_jar.xml
@@ -0,0 +1,115 @@
+
+
+ $PROJECT_DIR$/out/artifacts/AAS_NewGen_jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/html/webpage/assets/css/bss-overrides.css b/html/webpage/assets/css/bss-overrides.css
index f977d16..9f8ae72 100644
--- a/html/webpage/assets/css/bss-overrides.css
+++ b/html/webpage/assets/css/bss-overrides.css
@@ -50,6 +50,10 @@
margin-top: 1rem!important;
}
+.me-1 {
+ margin-right: .25rem!important;
+}
+
.me-2 {
margin-right: .5rem!important;
}
@@ -78,6 +82,10 @@
margin-bottom: auto!important;
}
+.ms-1 {
+ margin-left: .25rem!important;
+}
+
@media (min-width:768px) {
.me-md-auto {
margin-right: auto!important;
diff --git a/html/webpage/assets/js/log.js b/html/webpage/assets/js/log.js
index 8fdaa47..4e3754b 100644
--- a/html/webpage/assets/js/log.js
+++ b/html/webpage/assets/js/log.js
@@ -54,6 +54,8 @@ function reloadLogs(APIURL = "Log/", date, filter) {
});
}
+
+
$(document).ready(function () {
console.log("log.js ready");
let selectedlogdate = "";
@@ -100,4 +102,6 @@ $(document).ready(function () {
$('#btnExport').off('click').on('click', function () {
DoExport(APIURL, "log.xlsx", { date: selectedlogdate, filter: logfilter });
});
+
+
});
\ No newline at end of file
diff --git a/html/webpage/assets/js/overview.js b/html/webpage/assets/js/overview.js
index 58ac499..32b66de 100644
--- a/html/webpage/assets/js/overview.js
+++ b/html/webpage/assets/js/overview.js
@@ -49,7 +49,7 @@ function getCardByIndex(index) {
* @param {StreamerOutputData[]} values
*/
function UpdateStreamerCard(values) {
-
+
function setProgress(index, $bar, value, max = 100) {
const v = Number(value ?? 0);
const pct = Math.max(0, Math.min(100, Math.round((v / max) * 100)));
@@ -304,6 +304,14 @@ function LiveAudioCommand(command, bz, cbOK = null, cbFail = null) {
window.streamws = null;
window.mediasource = null;
+/**
+ * handler for ws_connected, ws_disconnected, ws_message events
+ */
+
+ws_connected_handler;
+ws_disconnected_handler;
+ws_message_handler;
+
$(document).ready(function () {
@@ -351,7 +359,7 @@ $(document).ready(function () {
if (event.data instanceof ArrayBuffer) {
const chunk = new Uint8Array(event.data);
sourceBuffer.appendBuffer(chunk);
- }
+ }
};
});
@@ -426,50 +434,64 @@ $(document).ready(function () {
runIntervalJob();
- window.addEventListener('ws_connected', () => {
- console.log("overview.js ws_connected event triggered");
- runIntervalJob();
- });
+ if (!ws_connected_handler) {
+ ws_connected_handler = function () {
+ console.log("overview.js ws_connected event triggered");
+ runIntervalJob();
+ };
+ }
- window.addEventListener('ws_disconnected', () => {
- console.log("overview.js ws_disconnected event triggered");
- if (intervaljob1) clearInterval(intervaljob1);
- if (intervaljob2) clearInterval(intervaljob2);
- intervaljob1 = null;
- intervaljob2 = null;
- });
- window.addEventListener('ws_message', (event) => {
- let rep = event.detail;
- let cmd = rep.reply;
- let data = rep.data;
- if (cmd && cmd.length > 0) {
- switch (cmd) {
- case "getPagingQueue":
- let pq = JSON.parse(data);
- window.PagingQueue = [];
- if (Array.isArray(pq) && pq.length > 0) {
- window.PagingQueue.push(...pq);
- }
- fill_pagingqueuetablebody(window.PagingQueue);
- break;
- case "getAASQueue":
- let aq = JSON.parse(data);
- window.QueueTable = [];
- if (Array.isArray(aq) && aq.length > 0) {
- window.QueueTable.push(...aq);
- }
- fill_automaticqueuetablebody(window.QueueTable);
- break;
- case "getStreamerOutputs":
- /**
- * @type {StreamerOutputData[]}
- */
- let so = JSON.parse(data);
- UpdateStreamerCard(so);
- break;
+ if (!ws_disconnected_handler) {
+ ws_disconnected_handler = function () {
+ console.log("overview.js ws_disconnected event triggered");
+ if (intervaljob1) clearInterval(intervaljob1);
+ if (intervaljob2) clearInterval(intervaljob2);
+ intervaljob1 = null;
+ intervaljob2 = null;
+ };
+ }
+
+ if (!ws_message_handler) {
+ ws_message_handler = function (event) {
+ let rep = event.detail;
+ let cmd = rep.reply;
+ let data = rep.data;
+ if (cmd && cmd.length > 0) {
+ switch (cmd) {
+ case "getPagingQueue":
+ let pq = JSON.parse(data);
+ window.PagingQueue = [];
+ if (Array.isArray(pq) && pq.length > 0) {
+ window.PagingQueue.push(...pq);
+ }
+ fill_pagingqueuetablebody(window.PagingQueue);
+ break;
+ case "getAASQueue":
+ let aq = JSON.parse(data);
+ window.QueueTable = [];
+ if (Array.isArray(aq) && aq.length > 0) {
+ window.QueueTable.push(...aq);
+ }
+ fill_automaticqueuetablebody(window.QueueTable);
+ break;
+ case "getStreamerOutputs":
+ /**
+ * @type {StreamerOutputData[]}
+ */
+ let so = JSON.parse(data);
+ UpdateStreamerCard(so);
+ break;
+ }
}
- }
- });
+ };
+ }
+
+ window.removeEventListener('ws_connected', ws_connected_handler);
+ window.removeEventListener('ws_disconnected', ws_disconnected_handler);
+ window.removeEventListener('ws_message', ws_message_handler);
+ window.addEventListener('ws_connected', ws_connected_handler);
+ window.addEventListener('ws_disconnected', ws_disconnected_handler);
+ window.addEventListener('ws_message', ws_message_handler);
$(window).on('beforeunload', function () {
console.log("overview.js beforeunload event triggered");
diff --git a/html/webpage/assets/js/usermanagement.js b/html/webpage/assets/js/usermanagement.js
index 69806d8..067ffbd 100644
--- a/html/webpage/assets/js/usermanagement.js
+++ b/html/webpage/assets/js/usermanagement.js
@@ -217,6 +217,14 @@ $(document).ready(function () {
`;
$('#citylist').append(row);
});
+ $('#city_selectall').off('click').on('click', function () {
+ // select all checkboxes
+ $('#citylist input[type=checkbox]').prop('checked', true);
+ });
+ $('#city_clearall').off('click').on('click', function () {
+ // deselect all checkboxes
+ $('#citylist input[type=checkbox]').prop('checked', false);
+ });
}
function fill_airlinelist() {
@@ -231,6 +239,14 @@ $(document).ready(function () {
`;
$('#airlinelist').append(row);
});
+ $('#airline_selectall').off('click').on('click', function () {
+ // select all checkboxes
+ $('#airlinelist input[type=checkbox]').prop('checked', true);
+ });
+ $('#airline_clearall').off('click').on('click', function () {
+ // deselect all checkboxes
+ $('#airlinelist input[type=checkbox]').prop('checked', false);
+ });
}
// broadcast zone selection modal elements
@@ -246,6 +262,14 @@ $(document).ready(function () {
`;
$('#broadcastzonelist').append(row);
});
+ $('#bzone_selectall').off('click').on('click', function () {
+ // select all checkboxes
+ $('#broadcastzonelist input[type=checkbox]').prop('checked', true);
+ });
+ $('#bzone_clearall').off('click').on('click', function () {
+ // deselect all checkboxes
+ $('#broadcastzonelist input[type=checkbox]').prop('checked', false);
+ });
}
@@ -263,6 +287,14 @@ $(document).ready(function () {
`;
$('#messagebanklist').append(row);
});
+ $('#mbank_selectall').off('click').on('click', function () {
+ // select all checkboxes
+ $('#messagebanklist input[type=checkbox]').prop('checked', true);
+ });
+ $('#mbank_clearall').off('click').on('click', function () {
+ // deselect all checkboxes
+ $('#messagebanklist input[type=checkbox]').prop('checked', false);
+ });
}
diff --git a/html/webpage/usermanagement.html b/html/webpage/usermanagement.html
index c414738..fc6a253 100644
--- a/html/webpage/usermanagement.html
+++ b/html/webpage/usermanagement.html
@@ -153,18 +153,38 @@
-
-
+
+
-
+
+
+
+
+
+
+
-
-
+
+
-
+
+
+
+
+
+
+
@@ -181,7 +201,15 @@
Broadcast Zones Selection
-
+
+
+
+
+
@@ -194,7 +222,15 @@
Message Bank Selection
-
+
+
+
+
+
diff --git a/libs/META-INF/MANIFEST.MF b/libs/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..82c7964
--- /dev/null
+++ b/libs/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: MainKt
+
diff --git a/src/Main.kt b/src/Main.kt
index 5b8d861..f016408 100644
--- a/src/Main.kt
+++ b/src/Main.kt
@@ -1,4 +1,5 @@
import audio.AudioPlayer
+
import audio.ContentCache
import audio.TCPReceiver
import audio.UDPReceiver
@@ -7,6 +8,7 @@ import barix.TCP_Barix_Command_Server
import codes.Somecodes
import codes.configFile
import codes.configKeys
+import com.sun.jna.Native
import com.sun.jna.Platform
import commandServer.TCP_Android_Command_Server
import content.Category
@@ -24,10 +26,12 @@ import org.tinylog.provider.ProviderRegistry
import oshi.util.GlobalConfig
import securedonglex.DongleChecker
import web.WebApp
+import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.concurrent.fixedRateTimer
import kotlin.io.path.absolutePathString
+import kotlin.io.path.exists
import kotlin.system.exitProcess
lateinit var db: MariaDB
@@ -35,7 +39,7 @@ lateinit var audioPlayer: AudioPlayer
val StreamerOutputs: MutableMap = HashMap()
lateinit var udpreceiver: UDPReceiver
lateinit var tcpreceiver: TCPReceiver
-const val version = "0.0.17 (26/01/2026)"
+const val version = "0.0.23 (29/01/2026)"
// AAS 64 channels
const val max_channel = 64
@@ -73,45 +77,55 @@ fun folder_preparation(){
}
+private fun Extract_Libraries() {
+ // extract from source root folder to current user dir
+ val libs = listOf("bass", "bassenc", "bassenc_mp3","bassenc_ogg","bassenc_opus","bassmix","bassopus","sdx")
+ try{
+ val targetfolder = File(Somecodes.current_directory)
+ Logger.info {"target to extract libraries : $targetfolder"}
+ libs.forEach { ff ->
+
+ val x = Native.extractFromResourcePath(ff)
+ val y = System.mapLibraryName(ff)
+ val z = x.copyTo(targetfolder.resolve(y),overwrite = true)
+ Logger.info {"Extracted libraries : $z"}
+ }
+ } catch (e : Exception){
+ Logger.error { "Error extracting libraries, msg : ${e.message}" }
+ }
+}
+
/**
* Extract necessary wav files from classpath to soundbank directory
* and Load them
*/
fun files_preparation(){
val list = listOf("chimeup.wav", "chimedown.wav", "silence1s.wav", "silencehalf.wav")
- list.forEach {
- Somecodes.ExtractFilesFromClassPath("/$it", Somecodes.Soundbank_directory)
- val pp = Somecodes.Soundbank_directory.resolve(it)
- if (Files.isRegularFile(pp)){
- val afi = audioPlayer.LoadAudioFile(pp.absolutePathString())
+ list.forEach { ff ->
+ Somecodes.extractWav(ff)
+ val fd = Somecodes.Soundbank_directory.resolve(ff)
+ if (fd.exists()){
+ Logger.info{"File ${fd.absolutePathString()} found, processing to content cache" }
+ val afi = audioPlayer.LoadAudioFile(fd.absolutePathString())
if (afi.isValid()){
- Logger.info { "Common audio $it loaded from ${pp.toAbsolutePath()}" }
- val key = it.substring(0, it.length - 4) // buang .wav
- contentCache.addAudioFile(key, afi)
+ val key = Somecodes.FilenameWithoutExtension(fd.toFile())
+ contentCache.addAudioFile(Somecodes.FilenameWithoutExtension(fd.toFile()), afi)
+ Logger.info{"Loaded file ${fd.absolutePathString()} to content cache as $key" }
} else {
- Logger.error { "Failed to load common audio $it from ${pp.toAbsolutePath()}" }
+ Logger.error{"Failed to load file ${fd.absolutePathString()} to content cache" }
}
} else {
- Logger.error { "Common audio $it not found at ${pp.toAbsolutePath()}" }
+ Logger.error{"File ${fd.absolutePathString()} not found after extraction" }
}
}
}
lateinit var config : configFile
-val sdx = DongleChecker()
+//val sdx = DongleChecker()
// Application start here
fun main() {
- if (!sdx.CheckDongle()){
- Logger.error { "Dongle check failed. Application will exit." }
- exitProcess(1)
- } else {
- sdx.startChecking {
- Logger.error { "Dongle removed. Application will exit." }
- exitProcess(1)
- sdx.stopChecking()
- }
- }
+
@@ -124,6 +138,17 @@ fun main() {
config = configFile()
folder_preparation()
+ Extract_Libraries()
+
+// if (!sdx.CheckDongle()){
+// Logger.error { "Dongle check failed. Application will exit." }
+// exitProcess(1)
+// } else {
+// sdx.startChecking {
+// Logger.error { "Dongle removed. Application will exit." }
+// exitProcess(1)
+// }
+// }
audioPlayer = AudioPlayer(44100) // 44100 Hz sampling rate
audioPlayer.InitAudio(1)
@@ -262,7 +287,7 @@ fun main() {
StreamerOutputs.values.forEach { it.close() }
audioPlayer.Close()
db.close()
- sdx.stopChecking()
+ //sdx.stopChecking()
Logger.info { "All services stopped, exiting application." }
ProviderRegistry.getLoggingProvider().shutdown()
diff --git a/src/MainExtension01.kt b/src/MainExtension01.kt
index 38219d4..d016f2b 100644
--- a/src/MainExtension01.kt
+++ b/src/MainExtension01.kt
@@ -99,7 +99,7 @@ class MainExtension01 {
*/
fun Get_Barix_Connection_by_ZoneName(zonename: String) : BarixConnection? {
if (ValidString(zonename)){
- val bz = db.broadcastDB.List.find{ it.description == zonename }
+ val bz = db.broadcastDB.List.find{ it.description.equals(zonename,true) }
val sc = if (bz!=null) db.soundchannelDB.List.find { it.channel == bz.SoundChannel } else null
val ip = sc?.ip ?: ""
if (ValidIPV4(ip)){
@@ -165,7 +165,7 @@ class MainExtension01 {
match.forEach {
mm ->
if (IsNumber(mm.value)) {
- val num =sb.firstOrNull { s1 -> s1.Category == Category.AlphabetNumeric.name && s1.TAG == "N${mm.value}" }
+ val num =sb.firstOrNull { s1 -> s1.Category.equals(Category.AlphabetNumeric.name, true) && s1.TAG.equals("N${mm.value}", true) }
if (num!=null){
if (ValidFile(num.Path)){
result.add(num.Path)
@@ -173,7 +173,7 @@ class MainExtension01 {
}
} else if (IsAlphabethic(mm.value)) {
val alp =
- sb.firstOrNull { s1 -> s1.Category == Category.AlphabetNumeric.name && s1.TAG == mm.value }
+ sb.firstOrNull { s1 -> s1.Category.equals(Category.AlphabetNumeric.name, true) && s1.TAG.equals(mm.value,true) }
if (alp != null) {
if (ValidFile(alp.Path)) {
result.add(alp.Path)
@@ -191,7 +191,7 @@ class MainExtension01 {
fun Get_Soundbank_Hour_Minute(sb: List, value: Int) : String {
if (value in 0..59){
val tag = if (value<10) "N0${value}" else "N${value}"
- val hm = sb.firstOrNull { it.Category == Category.AlphabetNumeric.name && it.TAG == tag }
+ val hm = sb.firstOrNull { it.Category.equals(Category.AlphabetNumeric.name,true) && it.TAG.equals(tag, true) }
if (hm!=null){
if (ValidFile(hm.Path)) return hm.Path
}
@@ -265,7 +265,7 @@ class MainExtension01 {
val value = variables["AL"].orEmpty()
if (ValidString(value)) {
val airplane =
- sb.firstOrNull { it.Category == Category.Airplane_Name.name && it.TAG == value }
+ sb.firstOrNull { it.Category.equals(Category.Airplane_Name.name,true) && it.TAG.equals(value,true) }
if (airplane != null) {
if (ValidFile(airplane.Path)) {
files.add(airplane.Path)
@@ -288,7 +288,7 @@ class MainExtension01 {
val alcode = variables["AL"].orEmpty()
val fncode = variables["FLNUM"].orEmpty()
if (ValidString(alcode) && ValidString(fncode)) {
- val val1 = sb.firstOrNull { it.Category == Category.Airline_Code.name && it.TAG == alcode }
+ val val1 = sb.firstOrNull { it.Category.equals(Category.Airline_Code.name,true) && it.TAG.equals(alcode, true) }
val val2 = Get_Soundbank_AlpabethNumeric(sb, fncode)
if (val1 != null) {
if (ValidFile(val1.Path)) {
@@ -360,7 +360,7 @@ class MainExtension01 {
val values = variables["CITY"].orEmpty().split(";").map { it.trim() }.filter { ValidString(it) }
if (values.isNotEmpty()) {
values.forEach { vv ->
- val city = sb.firstOrNull { it.Category == Category.City.name && it.TAG == vv }
+ val city = sb.firstOrNull { it.Category.equals(Category.City.name,true) && it.TAG.equals(vv,true) }
if (city != null) {
if (ValidFile(city.Path)) {
files.add(city.Path)
@@ -380,7 +380,7 @@ class MainExtension01 {
"[PLACES]" -> {
val value = variables["PLACES"].orEmpty()
if (ValidString(value)) {
- val places = sb.firstOrNull { it.Category == Category.Places.name && it.TAG == value }
+ val places = sb.firstOrNull { it.Category.equals(Category.Places.name,true) && it.TAG.equals(value,true) }
if (places != null) {
if (ValidFile(places.Path)) {
files.add(places.Path)
@@ -434,7 +434,7 @@ class MainExtension01 {
"[SHALAT]" -> {
val value = variables["SHALAT"].orEmpty()
if (ValidString(value)) {
- val shalat = sb.firstOrNull { it.Category == Category.Shalat.name && it.TAG == value }
+ val shalat = sb.firstOrNull { it.Category.equals(Category.Shalat.name,true) && it.TAG.equals(value,true) }
if (shalat != null) {
if (ValidFile(shalat.Path)) {
files.add(shalat.Path)
@@ -496,7 +496,7 @@ class MainExtension01 {
"[REASON]" -> {
val value = variables["REASON"].orEmpty()
if (ValidString(value)) {
- val reason = sb.firstOrNull { it.Category == Category.Reason.name && it.TAG == value }
+ val reason = sb.firstOrNull { it.Category.equals(Category.Reason.name,true) && it.TAG.equals(value,true) }
if (reason != null) {
if (ValidFile(reason.Path)) {
files.add(reason.Path)
@@ -518,7 +518,7 @@ class MainExtension01 {
"[PROCEDURE]" -> {
val value = variables["PROCEDURE"].orEmpty()
if (ValidString(value)) {
- val procedure = sb.firstOrNull { it.Category == Category.Procedure.name && it.TAG == value }
+ val procedure = sb.firstOrNull { it.Category.equals(Category.Procedure.name, true) && it.TAG.equals(value, true) }
if (procedure != null) {
if (ValidFile(procedure.Path)) {
files.add(procedure.Path)
@@ -539,7 +539,7 @@ class MainExtension01 {
else -> {
// Phrase
- val phrase = sb.firstOrNull { it.Category == Category.Phrase.name && it.TAG == _tag }
+ val phrase = sb.firstOrNull { it.Category.equals(Category.Phrase.name,true) && it.TAG.equals(_tag, true) }
if (phrase != null) {
if (ValidFile(phrase.Path)) {
files.add(phrase.Path)
@@ -563,7 +563,7 @@ class MainExtension01 {
fun Read_Queue_Paging() : Boolean{
db.queuepagingDB.Get()
val list = db.queuepagingDB.List
- .filter { it.Type=="PAGING" }
+ .filter { it.Type.equals("PAGING",true) }
list.forEach { qp ->
//println("Processing $qp")
@@ -633,7 +633,7 @@ class MainExtension01 {
fun Read_Queue_Shalat() : Boolean{
db.queuepagingDB.Get()
val list = db.queuepagingDB.List
- .filter { it.Type=="SHALAT" }
+ .filter { it.Type.equals("SHALAT",true) }
list.forEach { qp ->
//println("Processing $qp")
if (qp.BroadcastZones.isNotBlank()){
@@ -747,7 +747,7 @@ class MainExtension01 {
fun Read_Queue_Timer() : Boolean{
db.queuetableDB.Get()
- val list = db.queuetableDB.List.filter { it.Type=="TIMER" }
+ val list = db.queuetableDB.List.filter { it.Type.equals("TIMER",true) }
list.forEach { qa ->
//println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()){
@@ -852,7 +852,7 @@ class MainExtension01 {
fun Activate_Relays(zz: List){
zz.forEach { zonename ->
- val bz = db.broadcastDB.List.find { it.description == zonename }
+ val bz = db.broadcastDB.List.find { it.description.equals(zonename,true) }
if (bz!=null){
val bc = Get_Barix_Connection_by_ZoneName(zonename)
if (bc!=null){
@@ -872,7 +872,7 @@ class MainExtension01 {
fun Deactivate_Relays(zz: List){
zz.forEach { zonename ->
- val bz = db.broadcastDB.List.find { it.description == zonename }
+ val bz = db.broadcastDB.List.find { it.description.equals(zonename,true) }
if (bz!=null){
val bc = Get_Barix_Connection_by_ZoneName(zonename)
bc?.DeactivateRelay()
@@ -886,7 +886,7 @@ class MainExtension01 {
*/
fun Read_Queue_Soundbank() : Boolean{
db.queuetableDB.Get()
- val list = db.queuetableDB.List.filter { it.Type=="SOUNDBANK" }
+ val list = db.queuetableDB.List.filter { it.Type.equals("SOUNDBANK",true) }
list.forEach { qa ->
//println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()){
@@ -1045,7 +1045,7 @@ class MainExtension01 {
if (localtime.second != 0) return
val timestring = timeformat2.format(localtime)
val sch = db.scheduleDB.List.filter {
- it.Time == timestring && it.Enable
+ it.Time.equals(timestring,true) && it.Enable
}
// tidak ada schedule dengan time sekarang dan enable=true
if (sch.isEmpty()) return
@@ -1054,7 +1054,7 @@ class MainExtension01 {
val ddmmyyyy = dateformat1.format(localdate)
// check special date dulu
val specialdate = sch.find {
- it.Day == ddmmyyyy
+ it.Day.equals(ddmmyyyy,true)
}
if (specialdate != null) {
val qt = QueueTable(
diff --git a/src/audio/Bass.java b/src/audio/Bass.java
index da058b8..80bc805 100644
--- a/src/audio/Bass.java
+++ b/src/audio/Bass.java
@@ -1,13 +1,15 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.*;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface Bass extends Library {
- Bass Instance = (Bass) Native.load("bass", Bass.class);
+
+ Bass Instance = (Bass) Native.load(Somecodes.Companion.LibraryFullPath("bass"), Bass.class);
int BASSVERSION = 0x204; // API version
String BASSVERSIONTEXT = "2.4";
diff --git a/src/audio/BassEnc.java b/src/audio/BassEnc.java
index 266c9b4..541cc44 100644
--- a/src/audio/BassEnc.java
+++ b/src/audio/BassEnc.java
@@ -1,11 +1,12 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.*;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface BassEnc extends Library {
- BassEnc Instance = (BassEnc) Native.load("bassenc", BassEnc.class);
+ BassEnc Instance = (BassEnc) Native.load(Somecodes.Companion.LibraryFullPath("bassenc"), BassEnc.class);
// Additional error codes returned by BASS_ErrorGetCode
int BASS_ERROR_CAST_DENIED = 2100; // access denied (invalid password)
diff --git a/src/audio/BassEncMP3.java b/src/audio/BassEncMP3.java
index ab561af..aeae393 100644
--- a/src/audio/BassEncMP3.java
+++ b/src/audio/BassEncMP3.java
@@ -1,11 +1,13 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.Library;
+import com.sun.jna.Native;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface BassEncMP3 extends Library {
- BassEncMP3 Instance = (BassEncMP3) com.sun.jna.Native.load("bassenc_mp3", BassEncMP3.class);
+ BassEncMP3 Instance = (BassEncMP3) Native.load(Somecodes.Companion.LibraryFullPath("bassenc_mp3"), BassEncMP3.class);
int BASS_Encode_MP3_GetVersion();
int BASS_Encode_MP3_Start(int handle, String options, int flags, BassEnc.ENCODEPROCEX proc, Object user);
int BASS_Encode_MP3_StartFile(int handle, String options, int flags, String filename);
diff --git a/src/audio/BassEncOGG.java b/src/audio/BassEncOGG.java
index 194ccfc..1132e04 100644
--- a/src/audio/BassEncOGG.java
+++ b/src/audio/BassEncOGG.java
@@ -1,11 +1,13 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.Library;
+import com.sun.jna.Native;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface BassEncOGG extends Library {
- BassEncOGG Instance = (BassEncOGG) com.sun.jna.Native.load("bassenc_ogg", BassEncOGG.class);
+ BassEncOGG Instance = (BassEncOGG) Native.load(Somecodes.Companion.LibraryFullPath("bassenc_ogg"), BassEncOGG.class);
int BASS_ENCODE_OGG_RESET = 0x1000000;
int BASS_Encode_OGG_GetVersion();
int BASS_Encode_OGG_Start(int handle, String options, int flags, BassEnc.ENCODEPROC proc, Object user);
diff --git a/src/audio/BassEncOpus.java b/src/audio/BassEncOpus.java
index 75686a0..ff89571 100644
--- a/src/audio/BassEncOpus.java
+++ b/src/audio/BassEncOpus.java
@@ -1,10 +1,12 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.Library;
+import com.sun.jna.Native;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface BassEncOpus extends Library {
- BassEncOpus Instance = (BassEncOpus) com.sun.jna.Native.load("bassenc_opus", BassEncOpus.class);
+ BassEncOpus Instance = (BassEncOpus) Native.load(Somecodes.Companion.LibraryFullPath("bassenc_opus"), BassEncOpus.class);
int BASS_ENCODE_OPUS_RESET = 0x1000000;
int BASS_ENCODE_OPUS_CTLONLY = 0x2000000;
diff --git a/src/audio/BassMix.java b/src/audio/BassMix.java
index 8900339..c07c43a 100644
--- a/src/audio/BassMix.java
+++ b/src/audio/BassMix.java
@@ -1,13 +1,14 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface BassMix extends Library {
- BassMix Instance = (BassMix) Native.load("bassmix", BassMix.class);
+ BassMix Instance = (BassMix) Native.load(Somecodes.Companion.LibraryFullPath("bassmix"), BassMix.class);
// Envelope node
class BASS_MIXER_NODE {
diff --git a/src/audio/BassOpus.java b/src/audio/BassOpus.java
index 1be5d5b..571f958 100644
--- a/src/audio/BassOpus.java
+++ b/src/audio/BassOpus.java
@@ -1,12 +1,13 @@
package audio;
+import codes.Somecodes;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused"})
public interface BassOpus extends Library {
- BassOpus Instance = (BassOpus) Native.load("bassopus", BassOpus.class);
+ BassOpus Instance = (BassOpus) Native.load(Somecodes.Companion.LibraryFullPath("bassopus"), BassOpus.class);
// BASS_CHANNELINFO type
int BASS_CTYPE_STREAM_OPUS = 0x11200;
diff --git a/src/codes/Somecodes.kt b/src/codes/Somecodes.kt
index 7264fec..9f903e9 100644
--- a/src/codes/Somecodes.kt
+++ b/src/codes/Somecodes.kt
@@ -18,12 +18,15 @@ import oshi.hardware.GlobalMemory
import oshi.hardware.NetworkIF
import oshi.hardware.Sensors
import oshi.software.os.OperatingSystem
+import java.io.File
import java.nio.file.Files
import java.nio.file.Path
+import java.nio.file.StandardCopyOption
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.function.BiConsumer
import java.util.function.Consumer
+import kotlin.io.path.exists
import kotlin.io.path.name
@@ -193,6 +196,35 @@ class Somecodes {
return byteArray
}
+ fun LibraryFullPath(libname: String) : String{
+ val ff = File(current_directory, System.mapLibraryName(libname))
+ return if (ff.isFile) ff.absolutePath else ""
+ }
+
+ fun extractWav(filename: String) : Boolean {
+ val resourcePath = "/$filename"
+ try{
+ val input = object {}.javaClass.getResourceAsStream(resourcePath)
+ ?: error("Resource not found: $resourcePath")
+
+ val target = Soundbank_directory.resolve(filename) // current working directory
+
+ if (target.exists()) {
+ Logger.info {"File $filename already exists as $target, skipping extraction." }
+ return true
+ }
+ input.use {
+ Files.copy(it, target, StandardCopyOption.REPLACE_EXISTING)
+ }
+ Logger.info {"File $filename extracted as $target"}
+ return true
+ } catch (e : Exception){
+ Logger.error { "Error copying file $filename: ${e.message}" }
+ return false
+ }
+
+ }
+
fun ExtractFilesFromClassPath(resourcePath: String, outputDir: Path) {
try {
val resource = Somecodes::class.java.getResource(resourcePath)
@@ -466,6 +498,16 @@ class Somecodes {
return false
}
+ fun FilenameWithoutExtension(ff : File) : String{
+ val name = ff.name
+ val lastDotIndex = name.lastIndexOf('.')
+ return if (lastDotIndex != -1) {
+ name.substring(0, lastDotIndex)
+ } else {
+ name
+ }
+ }
+
/**
* Check if a string is a valid file path and the file exists.
* @param value The string to check.
@@ -473,7 +515,8 @@ class Somecodes {
*/
fun ValidFile(value : String) : Boolean {
if (value.isNotBlank()){
- return ValidFile(Path.of(value))
+ val ff = File(value)
+ return ff.isFile
}
return false
}
diff --git a/src/web/WebApp.kt b/src/web/WebApp.kt
index 48432b9..b0ba078 100644
--- a/src/web/WebApp.kt
+++ b/src/web/WebApp.kt
@@ -86,6 +86,9 @@ class WebApp(val listenPort: Int, var userlist: List>, val
config.staticFiles.add("/webpage")
config.jsonMapper(JavalinJackson(jacksonObjectMapper()))
config.router.apiBuilder {
+ before {
+ //Logger.info {"${it.ip()} connecting ${it.method()} to ${it.path()}"}
+ }
path("/") {
get { ctx ->
// Serve the main page
@@ -2302,6 +2305,7 @@ class WebApp(val listenPort: Int, var userlist: List>, val
}
}
}.start(listenPort)
+
}
private fun Start_SemiAutoServer() {
@@ -2311,6 +2315,9 @@ class WebApp(val listenPort: Int, var userlist: List>, val
config.staticFiles.add("/semiauto")
config.jsonMapper(JavalinJackson(jacksonObjectMapper()))
config.router.apiBuilder {
+ before{
+ //Logger.info{"${it.ip()} method ${it.method()} connect to ${it.path()}"}
+ }
path("/") {
get {
it.cookie("semiauto-user", "")