Compare commits

...

15 Commits

Author SHA1 Message Date
cdcb02e976 commit 18/10/2025 sync changes from master 2025-10-20 08:53:20 +07:00
17b4485e69 commit 17/10/2025 Add few logs 2025-10-17 17:15:00 +07:00
4d02ab6d07 commit 17/10/2025 Add few logs 2025-10-17 16:55:57 +07:00
8bd57f216a commit 14/10/2025 WebApp fix ScheduleBank ADD & send message 2025-10-17 09:42:50 +07:00
8978a0986d Merge remote-tracking branch 'origin/master' into feature-webapp 2025-10-17 09:12:01 +07:00
e5d8d8059e Merge branch 'master' of https://gitea.rdkartono.my.id/rdkartono/AAS_NewGeneration into feature-webapp 2025-10-16 15:42:24 +07:00
1b84ec133b commit 14/10/2025 WebApp Add send language for ScheduleBank 2025-10-16 15:26:59 +07:00
4da5a2fb05 Merge branch 'master' of https://gitea.rdkartono.my.id/rdkartono/AAS_NewGeneration into feature-webapp 2025-10-15 16:17:05 +07:00
1563e233d6 commit 14/10/2025 WebApp Add send language for ScheduleBank 2025-10-15 13:32:08 +07:00
a53270aaed commit 14/10/2025 WebApp Add send language for ScheduleBank 2025-10-14 16:26:14 +07:00
d2a2626fd5 Merge remote-tracking branch 'origin/master' into feature-webapp 2025-10-14 14:20:08 +07:00
8c49bb827f Merge remote-tracking branch 'origin/master' into feature-webapp
# Conflicts:
#	src/web/WebApp.kt
2025-10-14 09:11:36 +07:00
b15470845e Merge remote-tracking branch 'origin/master' into feature-webapp
# Conflicts:
#	src/web/WebApp.kt
2025-10-14 09:07:17 +07:00
e426522380 commit 08/10/2025 WebApp 2025-10-13 16:16:15 +07:00
470f61c79d Merge branch 'master' of https://gitea.rdkartono.my.id/rdkartono/AAS_NewGeneration into feature-webapp
# Conflicts:
#	src/web/WebApp.kt
2025-10-13 10:52:21 +07:00
19 changed files with 798 additions and 206 deletions

View File

@@ -37,3 +37,52 @@
--bs-btn-disabled-border-color: #0d6efd; --bs-btn-disabled-border-color: #0d6efd;
} }
.my-4 {
margin-top: 1.5rem!important;
margin-bottom: 1.5rem!important;
}
.mt-0 {
margin-top: 0!important;
}
.me-2 {
margin-right: .5rem!important;
}
.mb-2 {
margin-bottom: .5rem!important;
}
.mb-3 {
margin-bottom: 1rem!important;
}
.mb-4 {
margin-bottom: 1.5rem!important;
}
.mb-5 {
margin-bottom: 3rem!important;
}
.mb-7 {
margin-bottom: 6rem !important;
}
.mb-auto {
margin-bottom: auto!important;
}
@media (min-width:768px) {
.me-md-auto {
margin-right: auto!important;
}
}
@media (min-width:768px) {
.mb-md-0 {
margin-bottom: 0!important;
}
}

View File

@@ -104,7 +104,7 @@ body {
} }
.btn-login { .btn-login {
border-radius: 20px; border-radius: 8px;
box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px; box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
--bs-btn-hover-bg: #5780f2; --bs-btn-hover-bg: #5780f2;
background-color: #5278e1; background-color: #5278e1;
@@ -277,3 +277,44 @@ table {
border-radius: 0 !important; border-radius: 0 !important;
} }
.p-login {
text-align: left;
font-weight: 600;
margin-bottom: 0;
color: #3E4C66;
}
.h-login {
font-weight: 600;
color: #2E3A59;
}
#file-input {
display: none;
}
.card-setting {
border-radius: 8px;
border: white solid 3px;
}
#drop-area {
border: 2px dashed #ccc;
border-radius: 20px;
width: 400px;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
font-family: sans-serif;
color: #666;
cursor: pointer;
transition: background 0.2s, border-color 0.2s;
}
#drop-area.highlight {
background: #f0f8ff;
border-color: #0d6efd;
color: #0d6efd;
}

31
html/webpage/assets/js/dragdrop.js vendored Normal file
View File

@@ -0,0 +1,31 @@
const dropArea = document.getElementById("drop-area");
const fileInput = document.getElementById("file-input");
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, e => e.preventDefault());
dropArea.addEventListener(eventName, e => e.stopPropagation());
});
['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, () => dropArea.classList.add('highlight'));
});
['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, () => dropArea.classList.remove('highlight'));
});
dropArea.addEventListener('click', () => fileInput.click());
dropArea.addEventListener('drop', e => {
const files = e.dataTransfer.files;
handleFiles(files);
});
fileInput.addEventListener('change', e => {
handleFiles(e.target.files);
});
function handleFiles(files) {
console.log("file dropped");
}

View File

@@ -101,28 +101,30 @@ $(document).ready(function () {
let $schedulehour = $schedulemodal.find('#schedulehour'); let $schedulehour = $schedulemodal.find('#schedulehour');
// number input 0-59 // number input 0-59
let $scheduleminute = $schedulemodal.find('#scheduleminute'); let $scheduleminute = $schedulemodal.find('#scheduleminute');
// text input // select2 for message
let $schedulesoundpath = $schedulemodal.find('#schedulesoundpath'); let $schedulemessage = $schedulemodal.find('#schedulemessage');
$schedulemessage.select2({});
// number input 0-5 // number input 0-5
let $schedulerepeat = $schedulemodal.find('#schedulerepeat'); let $schedulerepeat = $schedulemodal.find('#schedulerepeat');
// checkbox // checkbox
let $scheduleenable = $schedulemodal.find('#scheduleenable'); let $scheduleenable = $schedulemodal.find('#scheduleenable');
// div for list of checkboxes // select2 for broadcastzones
let $schedulezones = $schedulemodal.find('#schedulezones'); let $schedulezones = $schedulemodal.find('#schedulezones');
$schedulezones.select2({});
// radio button for everyday // radio button for everyday
let $scheduleeveryday = $schedulemodal.find('#scheduleeveryday'); let $scheduleeveryday = $schedulemodal.find('#scheduleeveryday');
// radio button for weekdays // radio button for weekly
let $schedulesunday = $schedulemodal.find('#schedulesunday'); let $scheduleweekly = $schedulemodal.find('#scheduleweekly');
let $schedulemonday = $schedulemodal.find('#schedulemonday'); // select2 for weekly selection
let $scheduletuesday = $schedulemodal.find('#scheduletuesday'); let $weeklyselect = $schedulemodal.find('#weeklyselect');
let $schedulewednesday = $schedulemodal.find('#schedulewednesday'); $weeklyselect.select2({});
let $schedulethursday = $schedulemodal.find('#schedulethursday');
let $schedulefriday = $schedulemodal.find('#schedulefriday');
let $schedulesaturday = $schedulemodal.find('#schedulesaturday');
// radio button for specific date // radio button for specific date
let $schedulespecialdate = $schedulemodal.find('#schedulespecialdate'); let $schedulespecialdate = $schedulemodal.find('#schedulespecialdate');
// date input // date input
let $scheduledate = $schedulemodal.find('#scheduledate'); let $scheduledate = $schedulemodal.find('#scheduledate');
// select2 for language
let $languageselect = $schedulemodal.find('#languageselect');
$languageselect.select2({});
$schedulespecialdate.on('change', function () { $schedulespecialdate.on('change', function () {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
@@ -137,17 +139,10 @@ $(document).ready(function () {
$scheduledescription.val(''); $scheduledescription.val('');
$schedulehour.val('0'); $schedulehour.val('0');
$scheduleminute.val('0'); $scheduleminute.val('0');
$schedulesoundpath.val('');
$schedulerepeat.val('0'); $schedulerepeat.val('0');
$scheduleenable.prop('checked', true); $scheduleenable.prop('checked', true);
$scheduleeveryday.prop('checked', false); $scheduleeveryday.prop('checked', false);
$schedulesunday.prop('checked', false);
$schedulemonday.prop('checked', false);
$scheduletuesday.prop('checked', false);
$schedulewednesday.prop('checked', false);
$schedulethursday.prop('checked', false);
$schedulefriday.prop('checked', false);
$schedulesaturday.prop('checked', false);
$schedulespecialdate.prop('checked', false); $schedulespecialdate.prop('checked', false);
$scheduledate.prop('disabled', true).val(''); $scheduledate.prop('disabled', true).val('');

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -195,9 +195,9 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th class="col-sm-3">Description</th> <th class="class75">Description</th>
<th class="col">IP Address</th> <th class="class20">IP Address</th>
</tr> </tr>
</thead> </thead>
<tbody id="soundchanneltablebody"></tbody> <tbody id="soundchanneltablebody"></tbody>
@@ -236,11 +236,11 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th class="col-sm-2">Description</th> <th class="class40">Description</th>
<th class="col-sm-2">SoundChannel</th> <th class="class20">SoundChannel</th>
<th class="col-sm-2">ID</th> <th class="class05">ID</th>
<th class="col">BP</th> <th class="class30">BP</th>
</tr> </tr>
</thead> </thead>
<tbody id="broadcastzonetablebody"></tbody> <tbody id="broadcastzonetablebody"></tbody>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -42,9 +42,9 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th class="col-sm-2">TAG</th> <th class="class20">TAG</th>
<th class="col">Languages</th> <th class="class75">Languages</th>
</tr> </tr>
</thead> </thead>
<tbody id="languagebanktablebody"></tbody> <tbody id="languagebanktablebody"></tbody>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -39,11 +39,11 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-1 col-md-1">No</th> <th class="class10">No</th>
<th class="col-2 col-md-2 col-lg-2">Date</th> <th class="class15">Date</th>
<th class="col-2 col-md-2 col-lg-2">Time</th> <th class="class15">Time</th>
<th class="col-2 col-md-2 col-lg-2">Machine</th> <th class="class15">Machine</th>
<th>Description</th> <th class="class45">Description</th>
</tr> </tr>
</thead> </thead>
<tbody id="logtablebody"></tbody> <tbody id="logtablebody"></tbody>

View File

@@ -14,22 +14,21 @@
<body> <body>
<section class="position-relative py-4 py-xl-5"> <section class="position-relative py-4 py-xl-5">
<div class="container"> <div class="container">
<div class="row mb-5"> <div class="row mb-4"></div>
<div class="col-md-8 col-xl-6 text-center mx-auto"> <div class="row d-flex justify-content-center mb-7">
<h2>Sign In</h2>
</div>
</div>
<div class="row d-flex justify-content-center">
<div class="col-md-6 col-xl-4"> <div class="col-md-6 col-xl-4">
<div class="card mb-5 card-login"> <div class="card mb-5 card-login">
<div class="card-body d-flex flex-column align-items-center"> <div class="card-body d-flex flex-column align-items-center">
<div class="bs-icon-xl bs-icon-circle bs-icon-primary my-4 bs-icon"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-person bg-icon-login"> <div class="bs-icon-xl bs-icon-circle bs-icon-primary my-4 bs-icon bg-icon-login"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-person bg-icon-login">
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664z"></path> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664z"></path>
</svg></div> </svg></div>
<form class="text-center" method="post"> <h2 class="mb-3 h-login">Login</h2>
<div class="mb-3"><input class="form-control input-login" type="text" name="username" placeholder="Username"></div> <form class="text-center py-2 bottom-signin" method="post">
<div class="mb-3"><input class="form-control input-login" type="password" name="password" placeholder="Password"></div> <p class="p-login">Username</p>
<div class="mb-3"><button class="btn btn-primary d-block w-100 btn-login" type="submit">Sign In</button></div> <div class="mb-3"><input class="form-control input-login" type="text" name="username" placeholder="Enter your username"></div>
<p class="p-login">Password</p>
<div class="mb-3"><input class="form-control input-login" type="password" name="password" placeholder="Enter your password"></div>
<div class="mb-3 py-2"><button class="btn btn-primary d-block w-100 btn-login" type="submit">Login</button></div>
</form> </form>
</div> </div>
</div> </div>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -42,13 +42,13 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th class="col-sm-2">Description</th> <th class="class15">Description</th>
<th class="col-sm-1">Language</th> <th class="class10">Language</th>
<th class="col-sm-1">ANN ID</th> <th class="class10">ANN ID</th>
<th class="col-sm-1">Type</th> <th class="class10">Type</th>
<th class="col-sm-3">Message Details</th> <th class="class35">Message Details</th>
<th class="col-sm-3">Message Tags</th> <th class="class15">Message Tags</th>
</tr> </tr>
</thead> </thead>
<tbody id="messagebanktablebody"></tbody> <tbody id="messagebanktablebody"></tbody>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -19,8 +19,8 @@
</div> </div>
<div class="accordion" role="tablist" id="accordion-1"> <div class="accordion" role="tablist" id="accordion-1">
<div class="accordion-item pad-accordion"> <div class="accordion-item pad-accordion">
<h2 class="accordion-header" role="tab"><button class="accordion-button collapsed bg-heading1" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-1 .item-1" aria-expanded="false" aria-controls="accordion-1 .item-1">Channel Status</button></h2> <h2 class="accordion-header" role="tab"><button class="accordion-button bg-heading1" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-1 .item-1" aria-expanded="true" aria-controls="accordion-1 .item-1">Channel Status</button></h2>
<div class="accordion-collapse collapse item-1 bg-accordion" role="tabpanel" data-bs-parent="#accordion-1"> <div class="accordion-collapse collapse show item-1 bg-accordion" role="tabpanel" data-bs-parent="#accordion-1">
<div class="accordion-body"> <div class="accordion-body">
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card">
@@ -102,7 +102,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card">
<div class="card" id="streamercard-4"> <div class="card card-channel" id="streamercard-4">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle05">Channel 05</h4> <h4 class="card-title" id="streamertitle05">Channel 05</h4>
<div class="row"> <div class="row">
@@ -121,7 +121,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card">
<div class="card" id="streamercard-5"> <div class="card card-channel" id="streamercard-5">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle06">Channel 06</h4> <h4 class="card-title" id="streamertitle06">Channel 06</h4>
<div class="row"> <div class="row">
@@ -140,7 +140,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card">
<div class="card" id="streamercard-6"> <div class="card card-channel" id="streamercard-6">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle07">Channel 07</h4> <h4 class="card-title" id="streamertitle07">Channel 07</h4>
<div class="row"> <div class="row">
@@ -159,7 +159,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 pad-card">
<div class="card" id="streamercard-7"> <div class="card card-channel" id="streamercard-7">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle08">Channel 08</h4> <h4 class="card-title" id="streamertitle08">Channel 08</h4>
<div class="row"> <div class="row">
@@ -180,7 +180,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-8"> <div class="card card-channel" id="streamercard-8">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle09">Channel 09</h4> <h4 class="card-title" id="streamertitle09">Channel 09</h4>
<div class="row"> <div class="row">
@@ -199,7 +199,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-9"> <div class="card card-channel" id="streamercard-9">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle10">Channel 10</h4> <h4 class="card-title" id="streamertitle10">Channel 10</h4>
<div class="row"> <div class="row">
@@ -218,7 +218,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-10"> <div class="card card-channel" id="streamercard-10">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle11">Channel 11</h4> <h4 class="card-title" id="streamertitle11">Channel 11</h4>
<div class="row"> <div class="row">
@@ -237,7 +237,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-11"> <div class="card card-channel" id="streamercard-11">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle12">Channel 12</h4> <h4 class="card-title" id="streamertitle12">Channel 12</h4>
<div class="row"> <div class="row">
@@ -258,7 +258,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-12"> <div class="card card-channel" id="streamercard-12">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle13">Channel 13</h4> <h4 class="card-title" id="streamertitle13">Channel 13</h4>
<div class="row"> <div class="row">
@@ -277,7 +277,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-13"> <div class="card card-channel" id="streamercard-13">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle14">Channel 14</h4> <h4 class="card-title" id="streamertitle14">Channel 14</h4>
<div class="row"> <div class="row">
@@ -296,7 +296,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-14"> <div class="card card-channel" id="streamercard-14">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle15">Channel 15</h4> <h4 class="card-title" id="streamertitle15">Channel 15</h4>
<div class="row"> <div class="row">
@@ -315,7 +315,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-15"> <div class="card card-channel" id="streamercard-15">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle16">Channel 16</h4> <h4 class="card-title" id="streamertitle16">Channel 16</h4>
<div class="row"> <div class="row">
@@ -336,7 +336,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-16"> <div class="card card-channel" id="streamercard-16">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle17">Channel 17</h4> <h4 class="card-title" id="streamertitle17">Channel 17</h4>
<div class="row"> <div class="row">
@@ -355,7 +355,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-17"> <div class="card card-channel" id="streamercard-17">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle18">Channel 18</h4> <h4 class="card-title" id="streamertitle18">Channel 18</h4>
<div class="row"> <div class="row">
@@ -374,7 +374,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-18"> <div class="card card-channel" id="streamercard-18">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle19">Channel 19</h4> <h4 class="card-title" id="streamertitle19">Channel 19</h4>
<div class="row"> <div class="row">
@@ -393,7 +393,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-19"> <div class="card card-channel" id="streamercard-19">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle20">Channel 20</h4> <h4 class="card-title" id="streamertitle20">Channel 20</h4>
<div class="row"> <div class="row">
@@ -414,7 +414,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-20"> <div class="card card-channel" id="streamercard-20">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle21">Channel 21</h4> <h4 class="card-title" id="streamertitle21">Channel 21</h4>
<div class="row"> <div class="row">
@@ -433,7 +433,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-21"> <div class="card card-channel" id="streamercard-21">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle22">Channel 22</h4> <h4 class="card-title" id="streamertitle22">Channel 22</h4>
<div class="row"> <div class="row">
@@ -452,7 +452,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-22"> <div class="card card-channel" id="streamercard-22">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle23">Channel 23</h4> <h4 class="card-title" id="streamertitle23">Channel 23</h4>
<div class="row"> <div class="row">
@@ -471,7 +471,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-23"> <div class="card card-channel" id="streamercard-23">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle24">Channel 24</h4> <h4 class="card-title" id="streamertitle24">Channel 24</h4>
<div class="row"> <div class="row">
@@ -492,7 +492,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-24"> <div class="card card-channel" id="streamercard-24">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle25">Channel 25</h4> <h4 class="card-title" id="streamertitle25">Channel 25</h4>
<div class="row"> <div class="row">
@@ -511,7 +511,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-25"> <div class="card card-channel" id="streamercard-25">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle26">Channel 26</h4> <h4 class="card-title" id="streamertitle26">Channel 26</h4>
<div class="row"> <div class="row">
@@ -530,7 +530,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-26"> <div class="card card-channel" id="streamercard-26">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle27">Channel 27</h4> <h4 class="card-title" id="streamertitle27">Channel 27</h4>
<div class="row"> <div class="row">
@@ -549,7 +549,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-27"> <div class="card card-channel" id="streamercard-27">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle28">Channel 28</h4> <h4 class="card-title" id="streamertitle28">Channel 28</h4>
<div class="row"> <div class="row">
@@ -570,7 +570,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-28"> <div class="card card-channel" id="streamercard-28">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle29">Channel 29</h4> <h4 class="card-title" id="streamertitle29">Channel 29</h4>
<div class="row"> <div class="row">
@@ -589,7 +589,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-29"> <div class="card card-channel" id="streamercard-29">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle30">Channel 30</h4> <h4 class="card-title" id="streamertitle30">Channel 30</h4>
<div class="row"> <div class="row">
@@ -608,7 +608,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-30"> <div class="card card-channel" id="streamercard-30">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle31">Channel 31</h4> <h4 class="card-title" id="streamertitle31">Channel 31</h4>
<div class="row"> <div class="row">
@@ -627,7 +627,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-31"> <div class="card card-channel" id="streamercard-31">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle32">Channel 32</h4> <h4 class="card-title" id="streamertitle32">Channel 32</h4>
<div class="row"> <div class="row">
@@ -648,7 +648,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-32"> <div class="card card-channel" id="streamercard-32">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle33">Channel 33</h4> <h4 class="card-title" id="streamertitle33">Channel 33</h4>
<div class="row"> <div class="row">
@@ -667,7 +667,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-33"> <div class="card card-channel" id="streamercard-33">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle34">Channel 34</h4> <h4 class="card-title" id="streamertitle34">Channel 34</h4>
<div class="row"> <div class="row">
@@ -686,7 +686,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-34"> <div class="card card-channel" id="streamercard-34">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle35">Channel 35</h4> <h4 class="card-title" id="streamertitle35">Channel 35</h4>
<div class="row"> <div class="row">
@@ -705,7 +705,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-35"> <div class="card card-channel" id="streamercard-35">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle36">Channel 36</h4> <h4 class="card-title" id="streamertitle36">Channel 36</h4>
<div class="row"> <div class="row">
@@ -726,7 +726,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-36"> <div class="card card-channel" id="streamercard-36">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle37">Channel 37</h4> <h4 class="card-title" id="streamertitle37">Channel 37</h4>
<div class="row"> <div class="row">
@@ -745,7 +745,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-37"> <div class="card card-channel" id="streamercard-37">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle38">Channel 38</h4> <h4 class="card-title" id="streamertitle38">Channel 38</h4>
<div class="row"> <div class="row">
@@ -764,7 +764,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-38"> <div class="card card-channel" id="streamercard-38">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle39">Channel 39</h4> <h4 class="card-title" id="streamertitle39">Channel 39</h4>
<div class="row"> <div class="row">
@@ -783,7 +783,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-39"> <div class="card card-channel" id="streamercard-39">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle40">Channel 40</h4> <h4 class="card-title" id="streamertitle40">Channel 40</h4>
<div class="row"> <div class="row">
@@ -804,7 +804,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-40"> <div class="card card-channel" id="streamercard-40">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle41">Channel 41</h4> <h4 class="card-title" id="streamertitle41">Channel 41</h4>
<div class="row"> <div class="row">
@@ -823,7 +823,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-41"> <div class="card card-channel" id="streamercard-41">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle42">Channel 42</h4> <h4 class="card-title" id="streamertitle42">Channel 42</h4>
<div class="row"> <div class="row">
@@ -842,7 +842,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-42"> <div class="card card-channel" id="streamercard-42">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle43">Channel 43</h4> <h4 class="card-title" id="streamertitle43">Channel 43</h4>
<div class="row"> <div class="row">
@@ -861,7 +861,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-43"> <div class="card card-channel" id="streamercard-43">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle44">Channel 44</h4> <h4 class="card-title" id="streamertitle44">Channel 44</h4>
<div class="row"> <div class="row">
@@ -882,7 +882,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-44"> <div class="card card-channel" id="streamercard-44">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle-44">Channel 45</h4> <h4 class="card-title" id="streamertitle-44">Channel 45</h4>
<div class="row"> <div class="row">
@@ -901,7 +901,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-45"> <div class="card card-channel" id="streamercard-45">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle46">Channel 46</h4> <h4 class="card-title" id="streamertitle46">Channel 46</h4>
<div class="row"> <div class="row">
@@ -920,7 +920,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-46"> <div class="card card-channel" id="streamercard-46">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle47">Channel 47</h4> <h4 class="card-title" id="streamertitle47">Channel 47</h4>
<div class="row"> <div class="row">
@@ -939,7 +939,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-47"> <div class="card card-channel" id="streamercard-47">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle48">Channel 48</h4> <h4 class="card-title" id="streamertitle48">Channel 48</h4>
<div class="row"> <div class="row">
@@ -960,7 +960,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-48"> <div class="card card-channel" id="streamercard-48">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle49">Channel 49</h4> <h4 class="card-title" id="streamertitle49">Channel 49</h4>
<div class="row"> <div class="row">
@@ -979,7 +979,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-49"> <div class="card card-channel" id="streamercard-49">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle50">Channel 50</h4> <h4 class="card-title" id="streamertitle50">Channel 50</h4>
<div class="row"> <div class="row">
@@ -998,7 +998,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-50"> <div class="card card-channel" id="streamercard-50">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle51">Channel 51</h4> <h4 class="card-title" id="streamertitle51">Channel 51</h4>
<div class="row"> <div class="row">
@@ -1017,7 +1017,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-51"> <div class="card card-channel" id="streamercard-51">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle52">Channel 52</h4> <h4 class="card-title" id="streamertitle52">Channel 52</h4>
<div class="row"> <div class="row">
@@ -1038,7 +1038,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-52"> <div class="card card-channel" id="streamercard-52">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle53">Channel 53</h4> <h4 class="card-title" id="streamertitle53">Channel 53</h4>
<div class="row"> <div class="row">
@@ -1057,7 +1057,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-53"> <div class="card card-channel" id="streamercard-53">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle54">Channel 54</h4> <h4 class="card-title" id="streamertitle54">Channel 54</h4>
<div class="row"> <div class="row">
@@ -1076,7 +1076,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-54"> <div class="card card-channel" id="streamercard-54">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle55">Channel 55</h4> <h4 class="card-title" id="streamertitle55">Channel 55</h4>
<div class="row"> <div class="row">
@@ -1095,7 +1095,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-55"> <div class="card card-channel" id="streamercard-55">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle56">Channel 56</h4> <h4 class="card-title" id="streamertitle56">Channel 56</h4>
<div class="row"> <div class="row">
@@ -1116,7 +1116,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-56"> <div class="card card-channel" id="streamercard-56">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle57">Channel 57</h4> <h4 class="card-title" id="streamertitle57">Channel 57</h4>
<div class="row"> <div class="row">
@@ -1135,7 +1135,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-57"> <div class="card card-channel" id="streamercard-57">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle58">Channel 58</h4> <h4 class="card-title" id="streamertitle58">Channel 58</h4>
<div class="row"> <div class="row">
@@ -1154,7 +1154,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-58"> <div class="card card-channel" id="streamercard-58">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle59">Channel 59</h4> <h4 class="card-title" id="streamertitle59">Channel 59</h4>
<div class="row"> <div class="row">
@@ -1173,7 +1173,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-59"> <div class="card card-channel" id="streamercard-59">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle60">Channel 60</h4> <h4 class="card-title" id="streamertitle60">Channel 60</h4>
<div class="row"> <div class="row">
@@ -1194,7 +1194,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-60"> <div class="card card-channel" id="streamercard-60">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle61">Channel 61</h4> <h4 class="card-title" id="streamertitle61">Channel 61</h4>
<div class="row"> <div class="row">
@@ -1213,7 +1213,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-61"> <div class="card card-channel" id="streamercard-61">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle62">Channel 62</h4> <h4 class="card-title" id="streamertitle62">Channel 62</h4>
<div class="row"> <div class="row">
@@ -1232,7 +1232,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-62"> <div class="card card-channel" id="streamercard-62">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle63">Channel 63</h4> <h4 class="card-title" id="streamertitle63">Channel 63</h4>
<div class="row"> <div class="row">
@@ -1251,7 +1251,7 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card"> <div class="col-12 col-sm-6 col-md-3 col-lg-3 col-xl-3 col-xxl-3 pad-card">
<div class="card" id="streamercard-63"> <div class="card card-channel" id="streamercard-63">
<div class="card-body"> <div class="card-body">
<h4 class="card-title" id="streamertitle64">Channel 64</h4> <h4 class="card-title" id="streamertitle64">Channel 64</h4>
<div class="row"> <div class="row">
@@ -1274,20 +1274,20 @@
</div> </div>
</div> </div>
<div class="accordion-item pad-accordion pad-2"> <div class="accordion-item pad-accordion pad-2">
<h2 class="accordion-header" role="tab"><button class="accordion-button bg-heading2" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-1 .item-2" aria-expanded="true" aria-controls="accordion-1 .item-2">Paging Queue</button></h2> <h2 class="accordion-header" role="tab"><button class="accordion-button collapsed bg-heading2" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-1 .item-2" aria-expanded="false" aria-controls="accordion-1 .item-2">Paging Queue</button></h2>
<div class="accordion-collapse collapse show item-2 pad-2" role="tabpanel" data-bs-parent="#accordion-1"> <div class="accordion-collapse collapse item-2 pad-2" role="tabpanel" data-bs-parent="#accordion-1">
<div class="accordion-body"> <div class="accordion-body">
<div class="row"> <div class="row">
<div class="table-responsive"> <div class="table-responsive">
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">Index</th> <th class="class05">Index</th>
<th class="col-sm-2">Date Time</th> <th class="class10">Date Time</th>
<th class="col-sm-1">Source</th> <th class="class15">Source</th>
<th class="col-sm-1">Type</th> <th class="class10">Type</th>
<th class="col-sm-3">Message</th> <th class="class30">Message</th>
<th class="col-sm-4">Broadcast Zones</th> <th class="class30">Broadcast Zones</th>
</tr> </tr>
</thead> </thead>
<tbody id="pagingqueuetable"></tbody> <tbody id="pagingqueuetable"></tbody>
@@ -1310,12 +1310,12 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">Index</th> <th class="class05">Index</th>
<th class="col-sm-2">Date Time</th> <th class="class10">Date Time</th>
<th class="col-sm-1">Source</th> <th class="class15">Source</th>
<th class="col-sm-1">Type</th> <th class="class10">Type</th>
<th class="col-sm-3">Message</th> <th class="class30">Message</th>
<th class="col-sm-4">Broadcast Zones</th> <th class="class30">Broadcast Zones</th>
</tr> </tr>
</thead> </thead>
<tbody id="automaticqueuetable"></tbody> <tbody id="automaticqueuetable"></tbody>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -17,8 +17,70 @@
<h2 style="text-align: center;">Setting</h2> <h2 style="text-align: center;">Setting</h2>
</div> </div>
</div> </div>
<div class="row">
<div class="col">
<div class="card card-setting">
<div class="card-body">
<h4 class="card-title"><strong>Upload Soundbank</strong></h4>
<hr>
<div class="row">
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">Path</label></div>
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"><input class="w-100 form-control" type="text" id="setting_path"></div>
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-add" id="save_directory" type="button">Save Directory</button></div>
</div>
<div class="row">
<div class="col-6 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">Category</label></div>
<div class="col-6 col-sm-10 col-md-2 col-lg-2 col-xl-2"><select id="setting_category" class="input-add form-select"></select></div>
<div class="col-6 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">Language</label></div>
<div class="col-6 col-sm-10 col-md-2 col-lg-2 col-xl-2"><select id="setting_language" class="input-add form-select"></select></div>
<div class="col-6 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">Voice</label></div>
<div class="col-6 col-sm-10 col-md-2 col-lg-2 col-xl-2"><select id="setting_voice" class="input-add form-select"></select></div>
</div>
<div class="row">
<div class="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
<div class="bg-white w-100" id="drop-area" multiple=""><input type="file" id="file-input"><label class="form-label d">Drop files here or click to select</label></div>
</div>
<div class="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
<div class="row"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row py-5">
<div class="col">
<div class="card card-setting">
<div class="card-body pad-accordion">
<h4 class="card-title"><strong>FIS CODE</strong></h4>
<hr>
<div class="row">
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">GOP</label></div>
<div class="col-10 col-sm-10 col-md-10 col-lg-10 col-xl-10"><select id="input_GOP" class="input-add form-select"></select></div>
</div>
<div class="row">
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">GBP</label></div>
<div class="col-10 col-sm-10 col-md-10 col-lg-10 col-xl-10"><select id="input_GBP" class="input-add form-select"></select></div>
</div>
<div class="row">
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">GFC</label></div>
<div class="col-10 col-sm-10 col-md-10 col-lg-10 col-xl-10"><select id="input_GFC" class="input-add form-select"></select></div>
</div>
<div class="row">
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label">FLD</label></div>
<div class="col-10 col-sm-10 col-md-10 col-lg-10 col-xl-10"><select id="input_FLD" class="input-add form-select"></select></div>
</div>
<div class="row">
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2"><label class="col-form-label"></label></div>
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-add" type="button">Save</button></div>
</div>
</div>
</div>
</div>
</div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/dragdrop.js"></script>
</body> </body>
</html> </html>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -42,13 +42,13 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th>Description</th> <th class="class20">Description</th>
<th class="col-sm-1">TAG</th> <th class="class10">TAG</th>
<th class="col-sm-1">Category</th> <th class="class15">Category</th>
<th class="col-sm-1">Language</th> <th class="class15">Language</th>
<th class="col-sm-1">Type</th> <th class="class10">Type</th>
<th class="col-sm-3">Filename</th> <th class="class25">Filename</th>
</tr> </tr>
</thead> </thead>
<tbody id="soundbanktablebody"></tbody> <tbody id="soundbanktablebody"></tbody>
@@ -102,7 +102,7 @@
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"> <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4">
<p class="text-add">Path</p> <p class="text-add">Path</p>
</div> </div>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-8"><select id="modalpath" class="input-add form-select" name="modalpath" data-control="select2"></select></div> <div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-8"><select id="modalpath" class="input-add form-select cw-100" name="modalpath" data-control="select2"></select></div>
</div> </div>
</div> </div>
<div class="modal-footer"><button class="btn btn-round-basic color-edit class25" id="soundbankclose" type="button" data-bs-dismiss="modal">Close</button><button class="btn btn-round-basic color-add class25" id="soundbanksave" type="button">Save</button></div> <div class="modal-footer"><button class="btn btn-round-basic color-edit class25" id="soundbankclose" type="button" data-bs-dismiss="modal">Close</button><button class="btn btn-round-basic color-add class25" id="soundbanksave" type="button">Save</button></div>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -42,14 +42,15 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th class="col-sm-2">Description</th> <th class="class15">Description</th>
<th class="col-sm-1">Day</th> <th class="class15">Day</th>
<th class="col-sm-1">Time</th> <th class="class10">Time</th>
<th class="col-sm-2">Sound Path</th> <th class="class15">Sound Path</th>
<th class="col-sm-1">Repeat</th> <th class="class10">Repeat</th>
<th class="col-sm-1">Enable</th> <th class="class05">Enable</th>
<th>Broadcast Zones</th> <th class="class15">Broadcast Zones</th>
<th class="class10">Language</th>
</tr> </tr>
</thead> </thead>
<tbody id="schedulebanktablebody"></tbody> <tbody id="schedulebanktablebody"></tbody>
@@ -87,37 +88,13 @@
</div> </div>
<div class="row pad-day"> <div class="row pad-day">
<div class="col"> <div class="col">
<div class="form-check"><input class="form-check-input" type="radio" id="schedulesunday" name="dayselection" value="Sunday"><label class="form-check-label" for="formCheck-8">Sunday</label></div> <div class="form-check"><input class="form-check-input" type="radio" id="scheduleweekly"><label class="form-check-label" for="formCheck-1">Weekly</label></div><select class="w-100 input-add form-select" id="weeklyselect">
</div> <optgroup label="This is a group">
</div> <option value="12" selected="">This is item 1</option>
<div class="row pad-day"> <option value="13">This is item 2</option>
<div class="col"> <option value="14">This is item 3</option>
<div class="form-check"><input class="form-check-input" type="radio" id="schedulemonday" name="dayselection" value="Monday"><label class="form-check-label" for="formCheck-7">Monday</label></div> </optgroup>
</div> </select>
</div>
<div class="row pad-day">
<div class="col">
<div class="form-check"><input class="form-check-input" type="radio" id="scheduletuesday" name="dayselection" value="Tuesday"><label class="form-check-label" for="formCheck-6">Tuesday</label></div>
</div>
</div>
<div class="row pad-day">
<div class="col">
<div class="form-check"><input class="form-check-input" type="radio" id="schedulewednesday" name="dayselection" value="Wednesday"><label class="form-check-label" for="formCheck-5">Wednesday</label></div>
</div>
</div>
<div class="row pad-day">
<div class="col">
<div class="form-check"><input class="form-check-input" type="radio" id="schedulethursday" name="dayselection" value="Thursday"><label class="form-check-label" for="formCheck-4">Thursday</label></div>
</div>
</div>
<div class="row pad-day">
<div class="col">
<div class="form-check"><input class="form-check-input" type="radio" id="schedulefriday" name="dayselection" value="Friday"><label class="form-check-label" for="formCheck-3">Friday</label></div>
</div>
</div>
<div class="row pad-day">
<div class="col">
<div class="form-check"><input class="form-check-input" type="radio" id="schedulesaturday" name="dayselection" value="Saturday"><label class="form-check-label" for="formCheck-2">Saturday</label></div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -134,12 +111,12 @@
</div> </div>
<div class="col"> <div class="col">
<div class="row w-100 h-100"> <div class="row w-100 h-100">
<div class="col-4 col-sm-4 col-md-4 col-lg-3 col-xl-3"><input type="number" id="schedulehour" class="input-add form-control class100" value="0" min="0" max="23" step="1"></div> <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"><input type="number" id="schedulehour" class="input-add form-control class100" value="0" min="0" max="23" step="1"></div>
<div class="col-2 col-sm-2 col-md-2 col-lg-3 col-xl-3"> <div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2">
<p class="pad-time">(H)</p> <p class="pad-time">(H)</p>
</div> </div>
<div class="col-4 col-sm-4 col-md-4 col-lg-3 col-xl-3"><input class="w-100 input-add form-control" type="number" id="scheduleminute" value="0" min="0" max="59" step="1"></div> <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"><input class="w-100 input-add form-control" type="number" id="scheduleminute" value="0" min="0" max="59" step="1"></div>
<div class="col-2 col-sm-2 col-md-2 col-lg-3 col-xl-3"> <div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2">
<p class="pad-time">(M)</p> <p class="pad-time">(M)</p>
</div> </div>
</div> </div>
@@ -147,9 +124,25 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"> <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4">
<p class="text-add">Sound Path</p> <p class="text-add">Message</p>
</div>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-8"><select id="schedulemessage" class="input-add form-select"></select></div>
</div>
<div class="row">
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4">
<p class="text-add">Language</p>
</div>
<div class="col">
<div class="row pad-day">
<div class="col"><select class="w-100 input-add form-select" id="languageselect">
<optgroup label="This is a group">
<option value="12" selected="">This is item 1</option>
<option value="13">This is item 2</option>
<option value="14">This is item 3</option>
</optgroup>
</select></div>
</div>
</div> </div>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-8"><input type="text" id="schedulesoundpath" class="input-add form-control"></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"> <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4">
@@ -167,7 +160,13 @@
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4"> <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4">
<p class="text-add">Broadcast Zones</p> <p class="text-add">Broadcast Zones</p>
</div> </div>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-8 border" id="schedulezones"></div> <div class="col-8 col-sm-8 col-md-8 col-lg-9 col-xl-8 border"><select class="w-100 input-add form-select" id="schedulezones">
<optgroup label="This is a group">
<option value="12" selected="">This is item 1</option>
<option value="13">This is item 2</option>
<option value="14">This is item 3</option>
</optgroup>
</select></div>
</div> </div>
</div> </div>
<div class="modal-footer"><button class="btn btn-round-basic color-edit class25" id="scheduleclose" type="button" data-bs-dismiss="modal">Close</button><button class="btn btn-round-basic class25 color-add" id="schedulesave" type="button">Save</button></div> <div class="modal-footer"><button class="btn btn-round-basic color-edit class25" id="scheduleclose" type="button" data-bs-dismiss="modal">Close</button><button class="btn btn-round-basic class25 color-add" id="schedulesave" type="button">Save</button></div>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>AAS_NewGen_08OKT25</title> <title>AAS_NewGen_17OKT25</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
@@ -42,13 +42,13 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">No</th> <th class="class05">No</th>
<th class="col-sm-1">Username</th> <th class="class10">Username</th>
<th class="col-sm-1">Location</th> <th class="class15">Location</th>
<th class="col-sm-2">Airline</th> <th class="class15">Airline</th>
<th class="col-sm-2">City</th> <th class="class15">City</th>
<th class="col-sm-2">Messagebank</th> <th class="class20">Messagebank</th>
<th class="col">Broadcast Zones</th> <th class="class20">Broadcast Zones</th>
</tr> </tr>
</thead> </thead>
<tbody id="usertablebody"></tbody> <tbody id="usertablebody"></tbody>

View File

@@ -16,6 +16,8 @@ import oshi.SystemInfo
import oshi.hardware.CentralProcessor import oshi.hardware.CentralProcessor
import oshi.hardware.GlobalMemory import oshi.hardware.GlobalMemory
import oshi.hardware.NetworkIF import oshi.hardware.NetworkIF
import oshi.hardware.Sensors
import oshi.software.os.OperatingSystem
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.time.LocalDateTime import java.time.LocalDateTime
@@ -37,6 +39,8 @@ class Somecodes {
val processor: CentralProcessor = si.hardware.processor val processor: CentralProcessor = si.hardware.processor
val memory : GlobalMemory = si.hardware.memory val memory : GlobalMemory = si.hardware.memory
val NetworkInfoMap = mutableMapOf<String, NetworkInformation>() val NetworkInfoMap = mutableMapOf<String, NetworkInformation>()
val sensor : Sensors = si.hardware.sensors
val os : OperatingSystem = si.operatingSystem
val datetimeformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss") val datetimeformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")
val dateformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy") val dateformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
@@ -492,6 +496,35 @@ class Somecodes {
sb.append(".wav") sb.append(".wav")
return sb.toString() return sb.toString()
} }
/**
* Get sensors information using OSHI library.
* @return A string representing the CPU temperature, fan speeds, and CPU voltage, or an empty string if not available.
*/
fun GetSensorsInfo() : String {
val cputemp = sensor.cpuTemperature
val cpuvolt = sensor.cpuVoltage
val fanspeed = sensor.fanSpeeds
return if (cpuvolt>0 && cputemp > 0 && fanspeed.isNotEmpty()){
String.format("CPU Temp: %.1f °C\nFan Speeds: %s RPM\nCPU Voltage: %.2f V",
sensor.cpuTemperature,
sensor.fanSpeeds.joinToString("/"),
sensor.cpuVoltage
)
} else ""
}
fun GetUptime() : String {
val value = os.systemUptime
return if (value>0){
// number of seconds since system boot
val hours = value / 3600
val minutes = (value % 3600) / 60
val seconds = value % 60
String.format("%02d:%02d:%02d", hours, minutes, seconds)
} else ""
}
} }

266
src/toa/Vx3K.kt Normal file
View File

@@ -0,0 +1,266 @@
package toa
import codes.Somecodes
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.tinylog.Logger
import java.net.Inet4Address
import java.net.InetSocketAddress
import java.net.Socket
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.function.BiConsumer
/**
* VX3K Protocol
* @param ipaddress IP address of the VX3K device, default to 192.168.14.1
* @param port Port number of the VX3K device, from 50050-50053 default to 50053
*/
class Vx3K(val ipaddress : String = "192.168.14.1", val port : Int = 50053) {
private val remotesocket : InetSocketAddress
init{
if (port !in 50050..50053){
throw IllegalArgumentException("Port number must be between 50050 and 50053")
}
try{
val inet = Inet4Address.getByName(ipaddress)
remotesocket = InetSocketAddress(inet, port)
} catch (_ : Exception){
throw IllegalArgumentException("Invalid IP address: $ipaddress")
}
}
/**
* Connect to the VX3K device
* @param timeout Connection timeout in milliseconds, default to 30000 ms
*/
fun Connect(timeout: Int = 30000){
try{
val socket = Socket()
// read timeout 5 seconds
socket.soTimeout = 5000
socket.connect(remotesocket, timeout)
} catch (e : Exception){
Logger.error { "Failed to connect with ${remotesocket.hostName}:${remotesocket.port}, Message: ${e.message}" }
}
}
/**
* Virtual Contact Input (Commmand 0x1001)
* @param ID : Device ID for VX3K, range 0 - 31
* @param CIN : Contact Input Number, range 0 - 15 for normal terminal, 16 for emergency contact input1, 17 for emergency contact input2
* @param isON : true for ON, false for OFF
* @param cb : Callback function with parameters (success: Boolean, message: String)
*/
fun VirtualCIN(ID: Short, CIN: Short, isON: Boolean, cb : BiConsumer<Boolean, String>){
val commandID = 0x1001.toShort()
if (ID !in 0..31){
cb.accept(false, "ID must be between 0 and 31")
return
}
if (CIN !in 0..17){
cb.accept(false, "CIN must be between 0 and 17")
return
}
val payload = ByteBuffer.allocate(6).order(ByteOrder.BIG_ENDIAN)
payload.putShort(ID)
payload.putShort(CIN)
payload.putShort(if (isON) 1 else 0)
val command = Make_Request_Command(commandID, payload.array())
Send_Receive(command,8){
success, reply ->
if (success){
val bb = ByteBuffer.wrap(reply).order(ByteOrder.BIG_ENDIAN)
val resp_commandID = bb.short
val resp_code = bb.short
if (resp_commandID==commandID){
if (resp_code.toInt() == 0){
cb.accept(true, "Virtual CIN command sent successfully to ${remotesocket.hostName}:${remotesocket.port}")
} else {
cb.accept(false, "Virtual CIN command failed with response code $resp_code from ${remotesocket.hostName}:${remotesocket.port}")
}
} else {
cb.accept(false, "Invalid response command ID $resp_commandID from ${remotesocket.hostName}:${remotesocket.port}")
}
} else {
cb.accept(false, "Failed to send Virtual CIN command to ${remotesocket.hostName}:${remotesocket.port}")
}
}
}
/**
* Open / Close Audio Input in Broadcast Pattern (Command 0x1003 for old firmware, 0x1101 for new firmware)
* @param NewFirmware Set to true if using new firmware version
* @param ID Device ID for VX3K, range 0 - 39 for new firmware, 0 - 31 for old firmware
* @param Channel Audio Input Channel, range 0 - 3
* @param BroadcastZones Vx3K_BroadcastZone object with selected broadcast zones
* @param cb Callback function with parameters (success: Boolean, message: String)
*/
fun AudioInput_BroadcastPattern(NewFirmware : Boolean, ID: Short, Channel: Short, BroadcastZones: Vx3K_BroadcastZone, cb: BiConsumer<Boolean, String>){
val CommandID = if (NewFirmware) 0x1101.toShort() else 0x1003.toShort()
if (NewFirmware){
if (ID !in 0..39){
cb.accept(false, "ID must be between 0 and 39")
return
}
} else {
if (ID !in 0..31){
cb.accept(false, "ID must be between 0 and 31")
return
}
}
if (Channel !in 0..3){
cb.accept(false, "Channel must be between 0 and 3")
return
}
val payload = ByteBuffer.allocate(if (NewFirmware) 86 else 70).order(ByteOrder.BIG_ENDIAN)
// Audio Input = 1
payload.putShort(1)
// VX3K ID
payload.putShort(ID)
// Audio Input Channel
payload.putShort(Channel)
// Broadcast Pattern Zones
payload.put(BroadcastZones.payload)
val command = Make_Request_Command(CommandID, payload.array())
Send_Receive(command,8){
success, reply ->
if (success){
val bb = ByteBuffer.wrap(reply).order(ByteOrder.BIG_ENDIAN)
val resp_commandID = bb.short
val resp_code = bb.short
if (resp_commandID==CommandID){
if (resp_code.toInt() == 0){
cb.accept(true, "Open Audio Input Broadcast command sent successfully to ${remotesocket.hostName}:${remotesocket.port}")
} else {
cb.accept(false, "Open Audio Input Broadcast command failed with response code $resp_code from ${remotesocket.hostName}:${remotesocket.port}")
}
} else {
cb.accept(false, "Invalid response command ID $resp_commandID from ${remotesocket.hostName}:${remotesocket.port}")
}
} else {
cb.accept(false, "Failed to send Open Audio Input Broadcast command to ${remotesocket.hostName}:${remotesocket.port}")
}
}
}
/**
* Open / Close Network Broadcast Pattern (Command 0x1102 for old firmware, 0x1104 for new firmware)
* @param NewFirmware Set to true if using new firmware version
* @param multicastIP Multicast IP address in string format, from 224.0.0.0 ~ 239.255.255.255, default to 224.0.0.1
* @param port UDP Port number, port 5000-5255 is invalid, default to 5300
* @param priority Broadcast Priority value, range 1 - 1024, default to 512 (to be checked later)
* @param isBGM true for BGM, false for Paging
* @param SSRC SSRC value, range 1 - 65535, default to 1 (to be checked later)
* @param payloadType RTP Payload Type, range 0 - 127, default to 0 (to be checked later)
* @param payloadSize RTP Payload Size, range 0 - 1500, default to 1000 (to be checked later)
* @param BroadcastZones Vx3K_BroadcastZone object with selected broadcast zones
* @param cb Callback function with parameters (success: Boolean, message: String)
*/
fun Network_BroadcastPattern(NewFirmware: Boolean,multicastIP: String = "224.0.0.1", port: Int = 5300, priority: Int = 512, isBGM: Boolean, SSRC: UShort = 1u, payloadType: Short = 0, payloadSize: Short = 1000, BroadcastZones: Vx3K_BroadcastZone, cb:BiConsumer<Boolean, String>){
val CommandID = if (NewFirmware) 0x1104.toShort() else 0x1102.toShort()
if (Somecodes.ValidIPV4(multicastIP)){
val inet = Inet4Address.getByName(multicastIP)
if (inet.isMulticastAddress){
if (port in 5256..65535){
if (priority in 1..1024){
if (SSRC in 1u..65535u){
if (payloadType in 0..127){
if (payloadSize in 0..1500){
val jitterbuffer = 1000 //TODO 32 signed integer, to be checked later
val payload = ByteBuffer.allocate(if (NewFirmware) 100 else 84)
payload.put(inet.address)
payload.putShort(port.toShort())
payload.putShort(priority.toShort())
payload.putShort(if (isBGM) 1 else 0)
payload.putShort(SSRC.toShort())
payload.putShort(payloadType)
payload.putShort(payloadSize)
payload.putInt(jitterbuffer)
payload.put(BroadcastZones.payload)
val command = Make_Request_Command(CommandID, payload.array())
Send_Receive(command,10){
success, reply ->
if (success){
val bb = ByteBuffer.wrap(reply).order(ByteOrder.BIG_ENDIAN)
val resp_commandID = bb.short
val resp_code = bb.short
// buang 2 short
bb.short
bb.short
val sound_source_number = bb.short
if (resp_commandID==CommandID){
if (resp_code.toInt() == 0){
cb.accept(true, "Open Network Broadcast command sent successfully to ${remotesocket.hostName}:${remotesocket.port}, Sound Source Number: $sound_source_number")
} else {
cb.accept(false, "Open Network Broadcast command failed with response code $resp_code from ${remotesocket.hostName}:${remotesocket.port}")
}
} else {
cb.accept(false, "Invalid response command ID $resp_commandID from ${remotesocket.hostName}:${remotesocket.port}")
}
} else {
cb.accept(false, "Failed to send Open Network Broadcast command to ${remotesocket.hostName}:${remotesocket.port}")
}
}
} else cb.accept(false, "Payload Size must be between 0 and 1500")
} else cb.accept(false, "Payload Type must be between 0 and 127")
} else cb.accept(false, "SSRC must be between 1 and 65535")
} else cb.accept(false, "Priority must be between 1 and 1024")
} else cb.accept(false, "Port must be greater than 5255 and less than 65536")
} else cb.accept(false, "multicastIP must between 224.0.0.0 ~ 239.255.255.255")
} else cb.accept(false, "Multicast IP address invalid")
}
/**
* Send command and receive reply from VX3K device
* @param command Command byte array to send
* @param expectedlength Expected length of the reply byte array
* @param cb Callback function with parameters (success: Boolean, reply: ByteArray)
*/
private fun Send_Receive(command: ByteArray, expectedlength: Int, cb : BiConsumer<Boolean, ByteArray>){
CoroutineScope(Dispatchers.IO).launch {
try{
val tcp = Socket()
tcp.soTimeout = 5000
tcp.connect(remotesocket, 30000)
val outstream = tcp.getOutputStream()
val instream = tcp.getInputStream()
outstream.write(command)
outstream.flush()
val reply = ByteArray(expectedlength)
instream.read(reply)
outstream.close()
instream.close()
tcp.close()
cb.accept(true, reply)
} catch (_: Exception){
cb.accept(false, ByteArray(0))
}
}
}
/**
* Wrap payload into VX3K Request Command format
* @param commandID Command ID
* @param Payload Payload data
* @return ByteArray of the complete command
*/
private fun Make_Request_Command(commandID: Short, Payload: ByteArray) : ByteArray {
val result = ByteBuffer.allocate(8+Payload.size).order(ByteOrder.BIG_ENDIAN)
// command ID (2 bytes)
result.putShort(commandID)
// Response code (2 bytes), set 0 for Request
result.putShort(0)
// command length = command header (8 bytes) + payload size
result.putShort((Payload.size+8).toShort())
// flag and reserver = 0 (2 bytes)
result.putShort(0)
result.put(Payload)
// read to byte array
return result.array()
}
}

View File

@@ -0,0 +1,67 @@
package toa
import kotlin.experimental.and
import kotlin.experimental.or
/**
* VX3K Broadcast Zone Configuration
* Old Firmware: Broadcast Zone 1 - 512
* New Firmware: Broadcast Zone 1 - 640
* @param NewFirmware Set to true if using new firmware version
*/
@Suppress("unused")
class Vx3K_BroadcastZone(val NewFirmware: Boolean = false) {
val payload: ByteArray = if (NewFirmware) ByteArray(80) else ByteArray(64)
/**
* Set a zone as active
* @param zonenumber Zone number to set (1 to 512 for old firmware, 1 to 640 for new firmware)
*/
fun SetZone(zonenumber: Int){
if (zonenumber<1) throw Exception("Minimum zone number is 1")
if (NewFirmware){
if (zonenumber>640) throw Exception("Maximum zone number is 640 for new firmware")
} else {
if (zonenumber>512) throw Exception("Maximum zone number is 512 for old firmware")
}
val byteIndex = (zonenumber - 1) / 8
val bitIndex = (zonenumber - 1) % 8
payload[byteIndex] = payload[byteIndex] or (1 shl bitIndex).toByte()
}
/**
* Clear a zone (set as inactive)
* @param zonenumber Zone number to clear (1 to 512 for old firmware, 1 to 640 for new firmware)
*/
fun ClearZone(zonenumber: Int){
if (zonenumber<1) throw Exception("Minimum zone number is 1")
if (NewFirmware){
if (zonenumber>640) throw Exception("Maximum zone number is 640 for new firmware")
} else {
if (zonenumber>512) throw Exception("Maximum zone number is 512 for old firmware")
}
val byteIndex = (zonenumber - 1) / 8
val bitIndex = (zonenumber - 1) % 8
payload[byteIndex] = payload[byteIndex] and ((1 shl bitIndex).inv().toByte())
}
/**
* Set all zones as active
*/
fun SetAllZones(){
for (i in payload.indices){
payload[i] = 0xFF.toByte()
}
}
/**
* Clear all zones (set all as inactive)
*/
fun ClearAllZones(){
for (i in payload.indices){
payload[i] = 0
}
}
}

View File

@@ -2,6 +2,8 @@ package web
import StreamerOutputs import StreamerOutputs
import codes.Somecodes import codes.Somecodes
import codes.Somecodes.Companion.GetSensorsInfo
import codes.Somecodes.Companion.GetUptime
import codes.Somecodes.Companion.ListAudioFiles import codes.Somecodes.Companion.ListAudioFiles
import codes.Somecodes.Companion.ValiDateForLogHtml import codes.Somecodes.Companion.ValiDateForLogHtml
import codes.Somecodes.Companion.ValidFile import codes.Somecodes.Companion.ValidFile
@@ -104,16 +106,23 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
objectmapper.readValue(wsMessageContext.message(), WebsocketCommand::class.java) objectmapper.readValue(wsMessageContext.message(), WebsocketCommand::class.java)
when (cmd.command) { when (cmd.command) {
"getSystemTime" -> { "getSystemTime" -> {
val systemtime = LocalDateTime.now().format(Somecodes.datetimeformat1)
val uptime = GetUptime()
SendReply( SendReply(
wsMessageContext, wsMessageContext,
cmd.command, cmd.command,
LocalDateTime.now().format(Somecodes.datetimeformat1) if (uptime.isNotEmpty()) "Date & Time : $systemtime\nSystem Uptime : $uptime" else "Date & Time : $systemtime"
) )
} }
"getCPUStatus" -> { "getCPUStatus" -> {
Somecodes.getCPUUsage { vv -> Somecodes.getCPUUsage { vv ->
SendReply(wsMessageContext, cmd.command, vv) val sv = GetSensorsInfo()
if (sv.isNotEmpty()){
SendReply(wsMessageContext, cmd.command, vv+"\n"+sv)
} else {
SendReply(wsMessageContext, cmd.command, vv)
}
} }
} }
@@ -280,6 +289,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.soundDB.Add(addvalue)) { if (db.soundDB.Add(addvalue)) {
db.soundDB.Resort() db.soundDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Added Sound Bank: $addvalue")
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to add soundbank to database"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to add soundbank to database")))
} else it.status(400) } else it.status(400)
@@ -297,6 +307,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.soundDB.Clear()) { if (db.soundDB.Clear()) {
db.soundDB.Get() db.soundDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Sound Bank table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate soundbank table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate soundbank table")))
} }
@@ -310,6 +321,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.soundDB.DeleteByIndex(index.toInt())) { if (db.soundDB.DeleteByIndex(index.toInt())) {
db.soundDB.Resort() db.soundDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted Sound Bank with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index")))
} }
@@ -379,6 +391,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.soundDB.UpdateByIndex(index.toInt(), sb)) { if (db.soundDB.UpdateByIndex(index.toInt(), sb)) {
db.soundDB.Resort() db.soundDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated Soundbank $sb")
} else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to update soundbank with index $index"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to update soundbank with index $index")))
} else it.status(400) } else it.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for soundbank with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for soundbank with index $index")))
@@ -455,6 +468,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.messageDB.Add(mb)){ if (db.messageDB.Add(mb)){
db.messageDB.Resort() db.messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Added Messagebank: $mb")
} else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add messagebank to database"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add messagebank to database")))
} else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Message_TAGS"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Message_TAGS")))
} else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Message_Detail"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Message_Detail")))
@@ -468,6 +482,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.messageDB.Clear()) { if (db.messageDB.Clear()) {
db.messageDB.Get() db.messageDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Message Bank table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate messagebank table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate messagebank table")))
} }
@@ -481,6 +496,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.messageDB.DeleteByIndex(index.toInt())) { if (db.messageDB.DeleteByIndex(index.toInt())) {
db.messageDB.Resort() db.messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted Message Bank with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index")))
} }
@@ -541,6 +557,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.messageDB.UpdateByIndex(index.toInt(), mb)) { if (db.messageDB.UpdateByIndex(index.toInt(), mb)) {
db.messageDB.Resort() db.messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated Messagebank $mb")
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index")))
} else it.status(400) } else it.status(400)
@@ -601,6 +618,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.languageDB.Add(newvalue)){ if (db.languageDB.Add(newvalue)){
db.languageDB.Resort() db.languageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Added Language Link: $newvalue")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add language link to database"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add language link to database")))
//println("Failed to add language link to database") //println("Failed to add language link to database")
@@ -623,6 +641,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.languageDB.Clear()) { if (db.languageDB.Clear()) {
db.languageDB.Resort() db.languageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Language Link table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate language link table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate language link table")))
} }
@@ -636,6 +655,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.languageDB.DeleteByIndex(index.toInt())) { if (db.languageDB.DeleteByIndex(index.toInt())) {
db.languageDB.Resort() db.languageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted Language Link with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index")))
} }
@@ -670,6 +690,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.languageDB.UpdateByIndex(index.toInt(), ll)) { if (db.languageDB.UpdateByIndex(index.toInt(), ll)) {
db.languageDB.Resort() db.languageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated Language Link $ll")
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to update language link with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to update language link with index $index")))
} else it.status(400) } else it.status(400)
@@ -722,6 +743,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.scheduleDB.Clear()) { if (db.scheduleDB.Clear()) {
db.scheduleDB.Get() db.scheduleDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Schedule Bank table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate schedulebank table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate schedulebank table")))
} }
@@ -761,6 +783,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.scheduleDB.Add(newvalue)){ if (db.scheduleDB.Add(newvalue)){
db.scheduleDB.Resort() db.scheduleDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Added Schedule Bank: $newvalue")
} else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add schedule to database"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add schedule to database")))
} else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Language"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Language")))
} else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Contains unsupported BroadcastZones"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Contains unsupported BroadcastZones")))
@@ -780,6 +803,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.scheduleDB.DeleteByIndex(index.toInt())) { if (db.scheduleDB.DeleteByIndex(index.toInt())) {
db.scheduleDB.Resort() db.scheduleDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted Schedule Bank with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index")))
} }
@@ -859,6 +883,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.scheduleDB.UpdateByIndex(index.toInt(), sb)) { if (db.scheduleDB.UpdateByIndex(index.toInt(), sb)) {
db.scheduleDB.Resort() db.scheduleDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated Schedule : $sb")
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to update schedule with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to update schedule with index $index")))
} else it.status(400) } else it.status(400)
@@ -911,6 +936,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.userDB.Clear()) { if (db.userDB.Clear()) {
db.userDB.Get() db.userDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear User Management table")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate user table"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to truncate user table")))
@@ -962,6 +988,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.userDB.Add(newuser)) { if (db.userDB.Add(newuser)) {
db.userDB.Resort() db.userDB.Resort()
ctx.result(objectmapper.writeValueAsString(resultMessage("OK") )) ctx.result(objectmapper.writeValueAsString(resultMessage("OK") ))
db.Add_Log("AAS", "Added User: $newuser")
} else ctx.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add user to database"))) } else ctx.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add user to database")))
} else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Some ANN_ID not found in Messagebank") )) } else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Some ANN_ID not found in Messagebank") ))
} else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Some broadcast zone tags not found in soundbank")) ) } else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Some broadcast zone tags not found in soundbank")) )
@@ -979,6 +1006,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.userDB.DeleteByIndex(index.toInt())) { if (db.userDB.DeleteByIndex(index.toInt())) {
db.userDB.Resort() db.userDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted User with index $index")
} else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete user with index $index"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete user with index $index")))
} }
} }
@@ -1019,7 +1047,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.userDB.UpdateByIndex(index.toInt(), editeduser)){ if (db.userDB.UpdateByIndex(index.toInt(), editeduser)){
db.userDB.Resort() db.userDB.Resort()
ctx.result(objectmapper.writeValueAsString(resultMessage("OK"))) ctx.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated User : $editeduser")
} else ctx.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to update user with index $index"))) } else ctx.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to update user with index $index")))
} else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for user with index $index"))) } else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for user with index $index")))
} else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Some broadcast zone is not found in Broadcast Zone list"))) } else ctx.status(400).result(objectmapper.writeValueAsString(resultMessage("Some broadcast zone is not found in Broadcast Zone list")))
@@ -1072,13 +1100,23 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
//TODO kirim list message dan broadcast zones untuk ADD/Edit schedule //TODO kirim list message dan broadcast zones untuk ADD/Edit schedule
get("GetMessageAndBroadcastZones") { get("GetMessageAndBroadcastZones") {
val result = object { val result = object {
//TODO filter message without input variable
val messages = db.messageDB.List val messages = db.messageDB.List
.filter { mb -> !mb.Message_Detail.contains("[") && !mb.Message_Detail.contains("]")}
.map { mb -> "${mb.Description} [${mb.ANN_ID}]" }
val broadcastzones = db.broadcastDB.List.map { it.description }
val broadcastzones = db.broadcastDB.List
} }
it.result(objectmapper.writeValueAsString(result)) it.result(objectmapper.writeValueAsString(result))
} }
// Kirim list language dari Messagebank berdasarkan ANN_ID
get("GetLanguageList/{ANN_ID}") { get1 ->
//kirim list language dari Messagebank
val langlist = db.messageDB.List
.filter { it.ANN_ID == get1.pathParam("ANN_ID").toInt().toUInt() }
.map { it.Language }.distinct()
get1.result(objectmapper.writeValueAsString(langlist))
}
} }
path("Log") { path("Log") {
get("List") { get1 -> get("List") { get1 ->
@@ -1141,6 +1179,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.broadcastDB.Clear()) { if (db.broadcastDB.Clear()) {
db.broadcastDB.Get() db.broadcastDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Broadcast Zones table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate broadcast zones table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate broadcast zones table")))
} }
@@ -1159,6 +1198,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.broadcastDB.Add(newbp)){ if (db.broadcastDB.Add(newbp)){
db.broadcastDB.Resort() db.broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS","Added Broadcast Zone: $newbp")
} else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add broadcast zone to database"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add broadcast zone to database")))
} else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Relay"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Relay")))
} else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Box"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Box")))
@@ -1174,6 +1214,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.broadcastDB.DeleteByIndex(index.toInt())) { if (db.broadcastDB.DeleteByIndex(index.toInt())) {
db.broadcastDB.Resort() db.broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted Broadcast Zone with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index")))
} }
@@ -1218,6 +1259,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.broadcastDB.UpdateByIndex(index.toInt(), bz)) { if (db.broadcastDB.UpdateByIndex(index.toInt(), bz)) {
db.broadcastDB.Resort() db.broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated Broadcast Zone : $bz")
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to update broadcast zone with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to update broadcast zone with index $index")))
} else it.status(400) } else it.status(400)
@@ -1274,6 +1316,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.soundchannelDB.Clear()) { if (db.soundchannelDB.Clear()) {
db.soundchannelDB.Get() db.soundchannelDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Sound Channel table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate sound channel table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate sound channel table")))
} }
@@ -1315,8 +1358,10 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
val newsc = SoundChannel(0u, _channel, _ip) val newsc = SoundChannel(0u, _channel, _ip)
if (db.soundchannelDB.UpdateByIndex(index.toInt(), newsc)) { if (db.soundchannelDB.UpdateByIndex(index.toInt(), newsc)) {
println("Updated sound channel with index $index") println("Updated sound channel with index $index")
db.soundchannelDB.Resort() db.soundchannelDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Updated Sound Channel : $newsc")
} else { } else {
println("Failed to update sound channel with index $index") println("Failed to update sound channel with index $index")
it.status(500) it.status(500)
@@ -1388,6 +1433,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.queuepagingDB.Clear()) { if (db.queuepagingDB.Clear()) {
db.queuepagingDB.Get() db.queuepagingDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear queue paging table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate queue paging table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate queue paging table")))
} }
@@ -1401,6 +1447,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.queuepagingDB.DeleteByIndex(index.toInt())) { if (db.queuepagingDB.DeleteByIndex(index.toInt())) {
db.queuepagingDB.Resort() db.queuepagingDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted queue paging with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue paging with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue paging with index $index")))
} }
@@ -1420,6 +1467,8 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.queuetableDB.Clear()) { if (db.queuetableDB.Clear()) {
db.queuetableDB.Get() db.queuetableDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Clear Automatic Queue Table")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate queue sound table"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate queue sound table")))
} }
@@ -1433,6 +1482,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
if (db.queuetableDB.DeleteByIndex(index.toInt())) { if (db.queuetableDB.DeleteByIndex(index.toInt())) {
db.queuetableDB.Resort() db.queuetableDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.Add_Log("AAS", "Deleted Automatic Queue Table with index $index")
} else { } else {
it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue sound with index $index"))) it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue sound with index $index")))
} }