From b90982366dcc938c811a9b756e43219524241df5 Mon Sep 17 00:00:00 2001 From: rdkartono Date: Thu, 29 Jan 2026 22:58:20 +0700 Subject: [PATCH] commit 29/01/2026 --- .gitignore | 6 +- .idea/artifacts/AAS_NewGen_jar.xml | 115 ++++++++++++++++++++++ html/webpage/assets/css/bss-overrides.css | 8 ++ html/webpage/assets/js/log.js | 4 + html/webpage/assets/js/overview.js | 110 ++++++++++++--------- html/webpage/assets/js/usermanagement.js | 32 ++++++ html/webpage/usermanagement.html | 52 ++++++++-- libs/META-INF/MANIFEST.MF | 3 + src/Main.kt | 71 ++++++++----- src/MainExtension01.kt | 40 ++++---- src/audio/Bass.java | 6 +- src/audio/BassEnc.java | 5 +- src/audio/BassEncMP3.java | 6 +- src/audio/BassEncOGG.java | 6 +- src/audio/BassEncOpus.java | 6 +- src/audio/BassMix.java | 5 +- src/audio/BassOpus.java | 5 +- src/codes/Somecodes.kt | 45 ++++++++- src/web/WebApp.kt | 7 ++ 19 files changed, 421 insertions(+), 111 deletions(-) create mode 100644 .idea/artifacts/AAS_NewGen_jar.xml create mode 100644 libs/META-INF/MANIFEST.MF 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 @@ 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", "")