Compare commits

..

2 Commits

Author SHA1 Message Date
db91775a5d vers 2.1.1 2026-01-28 19:01:04 +01:00
6b15afb9da vers. 2.1.1 2026-01-28 18:59:25 +01:00
95 changed files with 1101 additions and 1579 deletions

6
.gitignore vendored
View File

@@ -1,5 +1 @@
*:Zone.Identifier
*Zone.Identifier
*.old
/api/*
.htaccess
*:Zone.Identifier

77
.htaccess Normal file
View File

@@ -0,0 +1,77 @@
# Abilita il rewrite engine
RewriteEngine On
# Imposta la directory base (modifica se necessario)
# Se l'app è in una sottocartella, usa: RewriteBase /nome_cartella/
RewriteBase /newapp.rpigroup.it/
# Reindirizza richieste HTTP a HTTPS (opzionale, decommentare se necessario)
# RewriteCond %{HTTPS} off
# RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Non reindirizzare file e cartelle esistenti
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Escludi file statici dal rewriting
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|jpeg|png|gif|svg|ico|xml|json|woff|woff2|ttf|eot)$ [NC]
# Reindirizza tutto a index.php mantenendo il path
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
# Impedisci l'accesso diretto a file sensibili
<FilesMatch "^(config|\.htaccess|\.env)">
Order Allow,Deny
Deny from all
</FilesMatch>
# Gestione MIME types
<IfModule mod_mime.c>
AddType application/javascript js
AddType text/css css
AddType image/svg+xml svg
AddType application/vnd.ms-fontobject eot
AddType font/ttf ttf
AddType font/otf otf
AddType font/woff woff
AddType font/woff2 woff2
</IfModule>
# Abilita compressione GZIP (opzionale)
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
</IfModule>
# Cache control (opzionale - commentato perché hai lo script no-cache)
# <IfModule mod_expires.c>
# ExpiresActive On
# ExpiresByType image/jpg "access plus 1 month"
# ExpiresByType image/jpeg "access plus 1 month"
# ExpiresByType image/gif "access plus 1 month"
# ExpiresByType image/png "access plus 1 month"
# ExpiresByType image/svg+xml "access plus 1 month"
# ExpiresByType text/css "access plus 1 week"
# ExpiresByType application/javascript "access plus 1 week"
# </IfModule>
# Header no-cache per sviluppo (rimuovi in produzione se usi la cache)
<IfModule mod_headers.c>
<FilesMatch "\.(html|php)$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"
</FilesMatch>
</IfModule>
# Sicurezza aggiuntiva
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
</IfModule>
# Disabilita directory listing
Options -Indexes
# Abilita follow symlinks (necessario per RewriteRule)
Options +FollowSymLinks

BIN
.htaccess:Zone.Identifier Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,76 +3,8 @@
======================================== */
/* ========================================
LOADING OVERLAY
======================================== */
/* Overlay di caricamento a schermo intero */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(16, 25, 75, 0.95);
backdrop-filter: blur(8px);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
/* Quando l'overlay è attivo */
.loading-overlay.active {
opacity: 1;
visibility: visible;
}
/* Contenuto dell'overlay */
.loading-content {
text-align: center;
color: white;
}
/* Spinner grande per il loading overlay */
.spinner-large {
width: 60px;
height: 60px;
border: 5px solid rgba(255, 255, 255, 0.2);
border-top-color: #f7b835;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin: 0 auto 20px;
}
/* Testo di caricamento */
.loading-text {
font-size: 1.1rem;
font-weight: 500;
color: white;
margin: 0;
animation: pulse 1.5s ease-in-out infinite;
}
/* Animazione pulse per il testo */
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
/* Transizione per i link di navigazione */
/* .navLink,
.navLink,
.nav-link,
.station-link,
.linkBox {
@@ -81,7 +13,7 @@
}
/* Effetto hover sui link */
/* .navLink:hover,
.navLink:hover,
.nav-link:hover,
.station-link:hover,
.linkBox:hover {
@@ -93,13 +25,10 @@
@keyframes pulseActive {
0%,
100% {
0%, 100% {
opacity: 1;
transform: translateX(-50%) scale(1);
}
50% {
opacity: 0.6;
transform: translateX(-50%) scale(1.2);
@@ -107,7 +36,7 @@
}
/* Effetto click/tap */
/* .navLink:active,
.navLink:active,
.nav-link:active,
.station-link:active,
.linkBox:active {
@@ -116,7 +45,7 @@
}
/* Transizione per le card delle stazioni */
/*.station-card {
.station-card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
@@ -126,7 +55,7 @@
}
/* Transizione per i clickBox della home */
/* .clickBox {
.clickBox {
transition: all 0.3s ease;
}
@@ -171,7 +100,7 @@
}
/* Transizione per elementi che appaiono */
/*.content-page,
.content-page,
.station-list,
.player-container {
animation: fadeInContent 0.5s ease-out;
@@ -187,7 +116,7 @@
}
/* Transizione per le immagini */
/* .station-logo,
.station-logo,
.station-logo-large {
transition: transform 0.3s ease, filter 0.3s ease;
}
@@ -199,7 +128,7 @@
}
/* Transizione per i pulsanti */
/* button,
button,
.submit-btn,
.play-pause-btn {
transition: all 0.3s ease;
@@ -219,7 +148,7 @@ button:active,
}
/* Transizione smooth per tutti gli elementi interattivi */
/* a, button, input, textarea, select {
a, button, input, textarea, select {
transition: all 0.2s ease;
}
@@ -227,7 +156,7 @@ button:active,
/* Non ci sono più after pseudo-elementi per le underline */
/* Transizione per il back-link */
/* .back-link a {
.back-link a {
transition: all 0.3s ease;
display: inline-block;
}
@@ -238,7 +167,7 @@ button:active,
}
/* Animazione per le liste */
/* .stations-container {
.stations-container {
display: grid;
gap: 1rem;
}
@@ -265,7 +194,7 @@ button:active,
}
/* Transizione per i form */
/* .form-group input,
.form-group input,
.form-group textarea,
.form-group select {
transition: border-color 0.3s ease, box-shadow 0.3s ease;
@@ -279,7 +208,7 @@ button:active,
}
/* Animazione per i messaggi di risposta */
/* .form-response {
.form-response {
animation: slideInDown 0.4s ease-out;
}
@@ -295,7 +224,7 @@ button:active,
}
/* Transizione per video e iframe */
/* video,
video,
iframe {
transition: opacity 0.3s ease;
}
@@ -306,17 +235,17 @@ iframe:hover {
}
/* Performance optimization */
/** {
* {
-webkit-tap-highlight-color: transparent;
}
/* Smooth scrolling */
/* html {
html {
scroll-behavior: smooth;
}
/* Riduzione movimento per chi ha impostato preferenze di accessibilità */
/*@media (prefers-reduced-motion: reduce) {
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,421 +1,400 @@
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Black.ttf') format('truetype');
font-weight: 900;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-BlackItalic.ttf') format('truetype');
font-weight: 900;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Bold.ttf') format('truetype');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-BoldItalic.ttf') format('truetype');
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-MediumItalic.ttf') format('truetype');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Italic.ttf') format('truetype');
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-LightItalic.ttf') format('truetype');
font-weight: 300;
font-style: italic;
}
body {
font-family: 'Poppins', sans-serif !important;
}
* {
margin: 0;
padding: 0;
user-select: none;
}
html,
body {
overscroll-behavior: none;
}
body {
font-family: "Poppins", sans-serif;
height: 100vh;
overflow: hidden;
}
/* DESKTOP SECTION */
body.desktopBody {
background: #2a377e;
color: white;
}
div.dbox,
div.dbox_mobile {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #4358ca8f;
padding: 25px;
border-radius: 50px;
text-align: center;
width: 500px;
}
div.dbox_mobile {
width: 90%;
max-width: 750px;
color: white;
border-radius: 10px;
max-height: 475px;
overflow: auto;
}
div.dbox>h1.title,
div.dbox_mobile>h1.title {
margin-bottom: 0px;
}
div.dbox>hr,
div.dbox_mobile>hr {
margin: 2rem 0;
}
div.dbox>.dbtn,
div.dbox_mobile>.dbtn {
border: none;
border-radius: 50px;
padding: 10px 20px;
background: #f0f0f0;
color: black;
text-decoration: none;
font-weight: 600;
-webkit-appearance: button;
}
div.dbox>.dbtn:hover {
background: #e0e0e0;
cursor: pointer;
}
div.dfooter {
position: fixed;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: #ffffff90;
font-size: 13px;
width: 100%;
}
/* MOBILE SECTION */
.appBody {
background-color: #10194b;
max-width: 750px;
min-width: 330px;
margin: auto;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header>.logo-section,
.header>.menu-section {
text-align: center;
}
.header>.logo-section,
.footer>.copyright-section {
background-color: #2a377e;
padding: 15px 0;
}
.header>.menu-section {
background-color: #3849a8;
padding: 13px 0;
}
.header>.logo-section>img {
width: 250px;
}
.header>.menu-section>.navLink {
color: white;
text-decoration: none;
margin: 0 15px;
}
.header>.menu-section>.navLink.active {
color: #2a377e;
margin: 0;
padding: 3px 15px;
background: white;
border-radius: 50px;
font-weight: 500;
}
main {
background-color: white;
flex: 1;
overflow: auto;
}
.titlePage {
text-align: center;
font-weight: 600;
margin: 15px 0 20px;
}
.subtitlePage {
text-align: center;
font-weight: 500;
margin: -15px 0 20px;
}
.linkBox {
text-decoration: none;
color: black;
}
.clickBox {
width: 100%;
border: 2px solid #2a377e;
text-align: center;
border-radius: 20px;
font-weight: 500;
/* margin-bottom: 10px; */
padding: 4px;
}
.clickBox.Squared {
font-weight: 600;
border: solid 4px #2a377e;
}
.clickBox>img {
width: 80%;
}
.changelogTitle {
font-weight: 600;
padding: 0 13px;
margin: 0 0 15px;
}
.changelogList,
.tec,
.stationList {
padding: 0 13px;
margin: 0 0 10px;
text-align: justify;
hyphens: auto;
}
.stationList {
text-align: center;
}
.stationCard>a.stationLink {
padding: 0;
}
.stationCard>a.stationLink>img {
width: 100%;
border-radius: 20px;
}
/* .stationCard>.thematicBadge {
position: relative;
background: #f7b835;
padding: 1px 5px;
font-size: 0.8rem;
border-radius: 27px;
font-style: italic;
font-weight: 600;
top: 31px;
left: 35px;
margin: 0;
} */
.stationCard.isthematic {
text-align: right;
margin-top: -24px;
}
.stationCard.isthematic:before {
content: "Tematica";
position: relative;
background: #f7b835;
padding: 1px 5px;
font-size: 0.8rem;
border-radius: 27px;
font-style: italic;
font-weight: 600;
top: 30px;
right: 7px;
margin: 0;
}
iframe.contentplayer {
height: calc(100vh - 393px);
width: 100%;
max-width: 750px;
}
.footer_player {
background: #f7b835;
color: #2a377d;
z-index: 90;
width: 100%;
max-width: 750px;
height: 100px;
padding: 20px;
border-top: 1px solid #eee;
flex: 1;
align-content: end;
}
.footer_player>.row>.col-2>img {
border-radius: 5px;
}
button#playPauseBtn,
button#formatToggleBtn {
background: none;
border: none;
}
.footer,
.header {
z-index: 10000;
}
.footer>.menu-section {
background: #3849a8;
font-size: 0.7rem;
padding: 7px 0;
text-align: center;
}
.footer>.menu-section>a {
color: white;
text-decoration: none;
margin: 0 5px;
}
.footer>.copyright-section {
color: white;
font-size: 0.8rem;
text-align: center;
padding: 10px;
font-weight: 500;
}
@media (max-width: 450px) {
.appBody {
background-color: #2a377e;
}
}
/* Loading spinner */
.loading {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top-color: #3498db;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Forza orientamento portrait - nasconde contenuto in landscape */
@media screen and (orientation: landscape) and (max-height: 450px) {
body.appBody::after {
content: "Ruota il dispositivo in verticale";
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #2a377e;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
font-weight: 600;
z-index: 9999;
text-align: center;
padding: 20px;
}
body.appBody>* {
display: none !important;
}
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Black.ttf') format('truetype');
font-weight: 900;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-BlackItalic.ttf') format('truetype');
font-weight: 900;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Bold.ttf') format('truetype');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-BoldItalic.ttf') format('truetype');
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-MediumItalic.ttf') format('truetype');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Italic.ttf') format('truetype');
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-Light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Poppins';
src: url('fonts/Poppins-LightItalic.ttf') format('truetype');
font-weight: 300;
font-style: italic;
}
body {
font-family: 'Poppins', sans-serif !important;
}
* {
margin: 0;
padding: 0;
user-select: none;
}
html,
body {
overscroll-behavior: none;
}
body {
font-family: "Poppins", sans-serif;
height: 100vh;
overflow: hidden;
}
/* DESKTOP SECTION */
body.desktopBody {
background: #2a377e;
color: white;
}
div.dbox,
div.dbox_mobile {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #4358ca8f;
padding: 25px;
border-radius: 50px;
text-align: center;
width: 500px;
}
div.dbox_mobile {
width: 90%;
max-width: 450px;
color: white;
border-radius: 10px;
max-height: 475px;
overflow: auto;
}
div.dbox>h1.title,
div.dbox_mobile>h1.title {
margin-bottom: 0px;
}
div.dbox>hr,
div.dbox_mobile>hr {
margin: 2rem 0;
}
div.dbox>.dbtn,
div.dbox_mobile>.dbtn {
border: none;
border-radius: 50px;
padding: 10px 20px;
background: #f0f0f0;
color: black;
text-decoration: none;
font-weight: 600;
-webkit-appearance: button;
}
div.dbox>.dbtn:hover {
background: #e0e0e0;
cursor: pointer;
}
div.dfooter {
position: fixed;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: #ffffff90;
font-size: 13px;
width: 100%;
}
/* MOBILE SECTION */
.appBody {
background-color: #10194b;
max-width: 450px;
min-width: 330px;
margin: auto;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header>.logo-section,
.header>.menu-section {
text-align: center;
}
.header>.logo-section,
.footer>.copyright-section {
background-color: #2a377e;
padding: 15px 0;
}
.header>.menu-section {
background-color: #3849a8;
padding: 13px 0;
}
.header>.logo-section>img {
width: 250px;
}
.header>.menu-section>.navLink {
color: white;
text-decoration: none;
margin: 0 15px;
}
.header>.menu-section>.navLink.active {
color: #2a377e;
margin: 0;
padding: 3px 15px;
background: white;
border-radius: 50px;
font-weight: 500;
}
main {
background-color: white;
flex: 1;
overflow: auto;
}
.titlePage {
text-align: center;
font-weight: 600;
margin: 15px 0 20px;
}
.subtitlePage {
text-align: center;
font-weight: 500;
margin: -15px 0 20px;
}
.linkBox {
text-decoration: none;
color: black;
}
.clickBox {
width: 100%;
border: 2px solid #2a377e;
text-align: center;
border-radius: 20px;
font-weight: 500;
/* margin-bottom: 10px; */
padding: 4px;
}
.clickBox.Squared {
font-weight: 600;
border: solid 4px #2a377e;
}
.clickBox>img {
width: 80%;
}
.changelogTitle {
font-weight: 600;
padding: 0 13px;
margin: 0 0 15px;
}
.changelogList,
.tec,
.stationList {
padding: 0 13px;
margin: 0 0 7px;
text-align: justify;
hyphens: auto;
}
.stationList {
text-align: center;
}
.stationCard>a.stationLink {
padding: 0;
}
.stationCard>a.stationLink>img {
width: 100%;
border-radius: 20px;
}
/* .stationCard>.thematicBadge {
position: relative;
background: #f7b835;
padding: 1px 5px;
font-size: 0.8rem;
border-radius: 27px;
font-style: italic;
font-weight: 600;
top: 31px;
left: 35px;
margin: 0;
} */
.stationCard.isthematic{
text-align: right;
margin-top: -24px;
}
.stationCard.isthematic:before{
content: "Tematica";
position: relative;
background: #f7b835;
padding: 1px 5px;
font-size: 0.8rem;
border-radius: 27px;
font-style: italic;
font-weight: 600;
top: 30px;
right: 7px;
margin: 0;
}
iframe.contentplayer{
position: absolute;
left: 50%;
height: calc(100vh - 312px);
width: 100%;
max-width: 450px;
transform: translateX(-50%);
}
.footer_player{
background: #f7b835;
color: #2a377d;
position: fixed;
z-index: 90;
bottom: 70px;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 450px;
height: 100px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
padding: 20px;
}
.footer_player > .row > .col-2 > img{
border-radius: 5px;
}
button#playPauseBtn{
background: none;
border: none;
}
.footer{
z-index: 1;
}
.footer>.menu-section {
background: #3849a8;
font-size: 0.7rem;
padding: 7px 0;
text-align: center;
}
.footer>.menu-section>a {
color: white;
text-decoration: none;
margin: 0 5px;
}
.footer>.copyright-section {
color: white;
font-size: 0.8rem;
text-align: center;
padding: 10px;
font-weight: 500;
}
@media (max-width: 450px) {
.appBody {
background-color: #2a377e;
}
}
/* Loading spinner */
.loading {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top-color: #3498db;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}

Binary file not shown.

View File

@@ -1,385 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?>
<changelog>
<version>
<number>2.4.2</number>
<logs>
<log>Aggiornata la grandezza della finestra dell'applicazione da desktop.</log>
<log>Inserito il link della repository su ASV Git all'interno della pagina del changelog.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.4.1</number>
<logs>
<log>Aggiornata la pagiana del player audio, per renderla più coerente con le altre pagine dell'applicazione.</log>
<log>Aggiunta la visualizzazione dell'artista e del brano in riproduzione.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.4.0</number>
<logs>
<log>Implementato il player video dedicato per la riproduzione dei canali visivi.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.3.0</number>
<logs>
<log>Ottimizzata la risoluzione dell'applicazione su dispositivi larghi (tablet, iPad e computer).</log>
<log>Implementato lo switch tra il player audio in HLS e il player audio in MP3/AAC.</log>
<log>Rimosso l'avviso per i dispositivi iOS.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.2.0</number>
<logs>
<log>E' stato reintrodotto la schermata di caricamento ad ogni selezione di ogni pagina dell'applicazione.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.1.4</number>
<logs>
<log>Corretto la visione verticale sui dispositivi mobili.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.1.3</number>
<logs>
<log>Implementato il nuovo player audio per la riproduzione dei flussi audio in HLS per il bitrate adattivo.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.1.2</number>
<logs>
<log>Implementazione del sistema di qualità adattiva (ABR) per il player audio.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.1.1</number>
<logs>
<log>Corretti alcuni bug che impedivano l'accesso al player dal link esterno.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.1.0</number>
<logs>
<log>Risoluzione dei problemi minori presenti nel codice, che causava problemi nella navigazione in app.</log>
<log>Risoluzione dei problemi minori presenti nel codice, che causava problemi di riproduzione audio al player.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.4</number>
<logs>
<log>Blocco rotazione: è stato risolto il problema della rotazione schermo dell'applicazione. Ora rimane fissa in verticale.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.3</number>
<logs>
<log>Corretta la visualizzazione dei contenuti forniti dalle emittenti all'interno del player.</log>
<log>Corretta la visualizzazione del player audio.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.2</number>
<logs>
<log>Inserita la pagina statica per le emittenti tematiche.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.1</number>
<logs>
<log>Aggiunta la Visual Radio dell'emittente "Radio Città 105".</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.0</number>
<logs>
<log>Nuova UI/UX: RPIGroup aggiorna la veste grafica della sua applicazione, rendendola più "fumettosa" e "giocattolosa". Un'estetica completamente diversa da tutte le altre varie app radiofoniche.</log>
<log>Nuova Engine: Nuovo motore e struttura dell'applicazione. Lato backend è cambiato completamente rispetto alla versione 1.</log>
<log>Nuovo Player Audio/Video: Player più semplice, ma conserva le caratteristiche della precedente versione.</log>
<log>Termini e Condizioni: inserimento per obblighi di legge dei corrispettivi "Termini e Condizioni"</log>
<log>Policy Privacy: inserimento per obblighi di legge dei corrispettivi "Policy Privacy"</log>
<log>Dalla versione 2 e successive, è stata rimossa la dicitura "stable" in quanto non esistono più varie versioni dell'applicazione.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.2.1 Stable</number>
<logs>
<log>Aggiunta la pagina sul chiarimento dei "Diritti d'Autore".</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.2.0 Stable</number>
<logs>
<log>Implementato il "Media Sessions" che permette di visualizzare la radio in riproduzione nel centro notifiche su iOS e Android.</log>
<log>Preparazione dell'ottimizzazione del software in occasione della terza versione dell'app.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.1.1 Stable</number>
<logs>
<log>Correzione bug che impediva il caricamento del logo nell'icona dell'app sui smartphone.</log>
<log>Risolto il problema dell'overscrolling su smartphone.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.1.0 Stable</number>
<logs>
<log>Aggiunta la nuova stazione radio tematica "RDL Revival 70-80-90".</log>
<log>Migliorata la visualizzazione del selettore radio della pagina home.</log>
<log>Implementato nel player la visualizzazione della pagina statica per le radio tematiche.</log>
<log>Correzione e bugfix di problematiche varie causate dall'ultima versione "Beta".</log>
</logs>
</version>
<version>
<number>1.0.0 Stable</number>
<logs>
<log>Passaggio alla versione "Stable" dell'applicazione.</log>
<log>Verifica di ulteriori correzioni dal passaggio della versione stabile.</log>
<log>Leggerimento dell'applicazione a livello backend.</log>
<log>Ulteriori analisi di stabilità dal momento del passaggio alla versione stabile.</log>
<log>Correzione e bugfix di problematiche varie causate dall'ultima versione "Beta".</log>
</logs>
</version>
<version>
<number>0.24.0 Beta</number>
<logs>
<log>Aggiormaneto player audio - Riproduzione dei flussi audio in HLS per il bitrate adattivo. Le radio iscritte devono supportare il protocollo HLS.</log>
<log>Supporto all'interscambio della connessione - Al cambiare di tipologia (Wifi o Rete Cellulare), il flusso audio non si interrompe.</log>
<log>Preparazione del codice alla versione "1.0.0 Stable"</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.3 Beta</number>
<logs>
<log>Inserimento del nuovo flusso video per il canale "RC105 TV".</log>
<log>Aggiornamento player video - Inserita l'anteprima del flusso video</log>
<log>Correzione accesso al player video con l'inserimento automatico dell'anteprima e flusso video del canale selezionato</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.2 Beta</number>
<logs>
<log>Inizializzazione cambio interfaccia e modernamento.</log>
<log>Reinserimento della schermata di caricamento nel player.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.1 Beta</number>
<logs>
<log>Rimozione del logo al caricamento di ogni singola pagina (tranne all'avvio dell'app).</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.0 Beta</number>
<logs>
<log>Rilasciato il nuovo player video.</log>
<log>Inserimento dell'emittente RC105TV nella lista delle WebTV.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.4 Beta</number>
<logs>
<log>Correzione errori minimi nel sistema.</log>
<log>Aggiunta indicatore della versione app nella schermata desktop.</log>
<log>Preparazione player video - Correzioni minimi player e aggiunta di pagine mancanti.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.3 Beta</number>
<logs>
<log>Migliorati i tempi di caricamento dei player.</log>
<log>Aggiunta nuovi file di Configurazione.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.2 Beta</number>
<logs>
<log>Corretto la visualizzazione del player da desktop.</log>
<log>Corretto la visualizzazione del font scelto per la webapp "Rubik".</log>
<log>Varie ottimizzazioni per la valutazione finale di Google Page Speed.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.1 Beta</number>
<logs>
<log>Corretto il bug del logo all'interno dell'homepage.</log>
<log>Corretto la riproduzione audio dell'emittente Radio Città 105.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.0 Beta</number>
<logs>
<log>Cambiata la struttura interna dell'app, con unificazione della visualizzazione mobile con quella desktop.</log>
<log>Cambiata la configurazione dell'app. Ottimizzata per ridurre i tempi di attesa e output della pagina.</log>
<log>Le emittenti registrate sono inserite all'interno di un file XML apposito.</log>
<log>Aggiornato il player interattivo. Ora disponibile di default per tutte le emittenti.</log>
<log>Ottimizzata la homescreen con correzioni di vari bug.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.21.0 Beta</number>
<logs>
<log>Realizzazione del nuovo player interattivo. Disponibile per smartphone e desktop (Al momento, è disponibile solo per l'emittente RDL).</log>
<log>Disattivato il precedente player mobile. Verrà riattivato esclusivamente per "emittenti" sprovviste di pagine dinamiche.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.20.0 Beta</number>
<logs>
<log>L'app entra ufficialmente nello stato di Beta-testing.</log>
<log>Cambiata la modalità di indicazione della versione, non più basata sulla data di aggiornamento, ma sul numero di update dell'app.</log>
<log>Avviata ufficialmente la "Roadmap" sulla Versione 1.0.0 (indicata a fine pagina CHANGELOG).</log>
<log>Aggiunto script per iOS e iPadOS sul rilevamento uso browser/app.</log>
<log>Correzione e bugfix script rilevamento app Android.</log>
</logs>
</version>
<version>
<number>0.12.6 Alpha (Last Release)</number>
<logs>
<log>Aggiornata la lista emittenti nel menu in alto sinistra.</log>
<log>Aggiornate le pagine "Cosa è RPIGRPUP PLAY", "COME FUNZIONA L'APP" e "HAI BISOGNO DI AIUTO".</log>
<log>Corretto bug inizializzazione app per iOS e iPadOS.</log>
<log>Aggiunto script di controllo gestione app per iOS e iPadOS.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.12.5 Aplha</number>
<logs>
<log>Realizzazione file XML per il Changelog.</log>
<log>Aggiunto pulsante per la visualizzazione del Changelog.</log>
<log>Correzione pagina About per la visualizzazione del Changelog.</log>
<log>Correzione visualizzazione del Home Page.</log>
<log>Reso automatico il cambio di versione dell'app in base all'ultima versione disponibile e dichiarata all'intero del Changelog.</log>
</logs>
</version>
<version>
<number>0.12.2 Alpha</number>
<logs>
<log>Corretto il problema del caricamento del "Player Mobile" su iOS e derivati.</log>
<log>Corretto e aggiunto nuovi script del "Player Mobile"</log>
<log>Aggiornato slogan dell'emittente "RDL XMAS"</log>
<log>Aggiunto il Changelog</log>
</logs>
</version>
<version>
<number>0.11.30 Alpha</number>
<logs>
<log>Corretto la visualizzazione del "Player Mobile"</log>
<log>Aggiornata la lista emittenti nel menu in alto sinistra</log>
<log>Rimosse momentaneamente le WebTV nel menu in alto sinistra</log>
</logs>
</version>
<version>
<number>0.11.29 Alpha</number>
<logs>
<log>Aggiunta nuova emittente "RDL XMAS"</log>
<log>Corretta la visualizzazione del "PLAYER DESKTOP"</log>
<log>Corretta la visualizzazione della lista emittenti in "Home Desktop" e "Home Mobile"</log>
<log>Abilitato il "Player Mobile" anche in ambiente Desktop</log>
<log>Aggiornato script che impedisce il refresh della pagina da Mobile</log>
</logs>
</version>
<version>
<number>0.9.26 Alpha</number>
<logs>
<log>Cambiata l'URL del flusso audio di RDL e RC105</log>
<log>Correzione e bugfix all'interno dello stile dell'app</log>
<log>Correzione e bugfix all'interno dei metatag</log>
<log>Aggiunto script di disabilitazione pulsante F5 da tastiera</log>
</logs>
</version>
<version>
<number>0.9.24 Alpha</number>
<logs>
<log>Correzione e bugfix player video</log>
</logs>
</version>
<version>
<number>0.9.23 Alpha</number>
<logs>
<log>Aggiunto player video</log>
<log>Aggiunto collegamenti dei canali video delle emittenti</log>
<log>Aggiunto in configurazione gli URL dei canali video delle emittenti</log>
</logs>
</version>
<version>
<number>0.7.31 Alpha</number>
<logs>
<log>Correzione e bugfix all'interno della configurazione dell'app</log>
<log>Rimozione dello script per lo "scroll to update page" da smartphone</log>
<log>Aggiunti i metodi di contatto in About</log>
</logs>
</version>
<?xml version="1.0" encoding="UTF-8"?>
<changelog>
<version>
<number>2.1.1</number>
<logs>
<log>Corretti alcuni bug che impedivano l'accesso al player dal link esterno</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.1.0</number>
<logs>
<log>Risoluzione dei problemi minori presenti nel codice, che causava problemi nella navigazione in app</log>
<log>Risoluzione dei problemi minori presenti nel codice, che causava problemi di riproduzione audio al player</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.4</number>
<logs>
<log>Blocco rotazione: è stato risolto il problema della rotazione schermo dell'applicazione. Ora rimane fissa in verticale.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.3</number>
<logs>
<log>Corretta la visualizzazione dei contenuti forniti dalle emittenti all'interno del player</log>
<log>Corretta la visualizzazione del player audio</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.2</number>
<logs>
<log>Inserita la pagina statica per le emittenti tematiche</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.1</number>
<logs>
<log>Aggiunta la Visual Radio dell'emittente "Radio Città 105</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>2.0.0</number>
<logs>
<log>Nuova UI/UX: RPIGroup aggiorna la veste grafica della sua applicazione, rendendola più "fumettosa" e "giocattolosa". Un'estetica completamente diversa da tutte le altre varie app radiofoniche</log>
<log>Nuova Engine: Nuovo motore e struttura dell'applicazione. Lato backend è cambiato completamente rispetto alla versione 1.</log>
<log>Nuovo Player Audio/Video: Player più semplice, ma conserva le caratteristiche della precedente versione.</log>
<log>Termini e Condizioni: inserimento per obblighi di legge dei corrispettivi "Termini e Condizioni"</log>
<log>Policy Privacy: inserimento per obblighi di legge dei corrispettivi "Policy Privacy"</log>
<log>Dalla versione 2 e successive, è stata rimossa la dicitura "stable" in quanto non esistono più varie versioni dell'applicazione.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.2.1 Stable</number>
<logs>
<log>Aggiunta la pagina sul chiarimento dei "Diritti d'Autore".</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.2.0 Stable</number>
<logs>
<log>Implementato il "Media Sessions" che permette di visualizzare la radio in riproduzione nel centro notifiche su iOS e Android</log>
<log>Preparazione dell'ottimizzazione del software in occasione della terza versione dell'app.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.1.1 Stable</number>
<logs>
<log>Correzione bug che impediva il caricamento del logo nell'icona dell'app sui smartphone.</log>
<log>Risolto il problema dell'overscrolling su smartphone.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>1.1.0 Stable</number>
<logs>
<log>Aggiunta la nuova stazione radio tematica "RDL Revival 70-80-90"</log>
<log>Migliorata la visualizzazione del selettore radio della pagina home</log>
<log>Implementato nel player la visualizzazione della pagina statica per le radio tematiche</log>
<log>Correzione e bugfix di problematiche varie causate dall'ultima versione "Beta".</log>
</logs>
</version>
<version>
<number>1.0.0 Stable</number>
<logs>
<log>Passaggio alla versione "Stable" dell'applicazione</log>
<log>Verifica di ulteriori correzioni dal passaggio della versione stabile</log>
<log>Leggerimento dell'applicazione a livello backend</log>
<log>Ulteriori analisi di stabilità dal momento del passaggio alla versione stabile</log>
<log>Correzione e bugfix di problematiche varie causate dall'ultima versione "Beta".</log>
</logs>
</version>
<version>
<number>0.24.0 Beta</number>
<logs>
<log>Aggiormaneto player audio - Riproduzione dei flussi audio in HLS per il bitrate adattivo. Le radio iscritte devono supportare il protocollo HLS.</log>
<log>Supporto all'interscambio della connessione - Al cambiare di tipologia (Wifi o Rete Cellulare), il flusso audio non si interrompe.</log>
<log>Preparazione del codice alla versione "1.0.0 Stable"</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.3 Beta</number>
<logs>
<log>Inserimento del nuovo flusso video per il canale "RC105 TV".</log>
<log>Aggiornamento player video - Inserita l'anteprima del flusso video</log>
<log>Correzione accesso al player video con l'inserimento automatico dell'anteprima e flusso video del canale selezionato</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.2 Beta</number>
<logs>
<log>Inizializzazione cambio interfaccia e modernamento.</log>
<log>Reinserimento della schermata di caricamento nel player.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.1 Beta</number>
<logs>
<log>Rimozione del logo al caricamento di ogni singola pagina (tranne all'avvio dell'app)</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.23.0 Beta</number>
<logs>
<log>Rilasciato il nuovo player video</log>
<log>Inserimento dell'emittente RC105TV nella lista delle WebTV</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.4 Beta</number>
<logs>
<log>Correzione errori minimi nel sistema</log>
<log>Aggiunta indicatore della versione app nella schermata desktop</log>
<log>Preparazione player video - Correzioni minimi player e aggiunta di pagine mancanti</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.3 Beta</number>
<logs>
<log>Migliorati i tempi di caricamento dei player</log>
<log>Aggiunta nuovi file di Configurazione</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.2 Beta</number>
<logs>
<log>Corretto la visualizzazione del player da desktop.</log>
<log>Corretto la visualizzazione del font scelto per la webapp "Rubik".</log>
<log>Varie ottimizzazioni per la valutazione finale di Google Page Speed.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.1 Beta</number>
<logs>
<log>Corretto il bug del logo all'interno dell'homepage</log>
<log>Corretto la riproduzione audio dell'emittente Radio Città 105</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.22.0 Beta</number>
<logs>
<log>Cambiata la struttura interna dell'app, con unificazione della visualizzazione mobile con quella desktop.</log>
<log>Cambiata la configurazione dell'app. Ottimizzata per ridurre i tempi di attesa e output della pagina.</log>
<log>Le emittenti registrate sono inserite all'interno di un file XML apposito.</log>
<log>Aggiornato il player interattivo. Ora disponibile di default per tutte le emittenti.</log>
<log>Ottimizzata la homescreen con correzioni di vari bug.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.21.0 Beta</number>
<logs>
<log>Realizzazione del nuovo player interattivo. Disponibile per smartphone e desktop (Al momento, è disponibile solo per l'emittente RDL).</log>
<log>Disattivato il precedente player mobile. Verrà riattivato esclusivamente per "emittenti" sprovviste di pagine dinamiche.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.20.0 Beta</number>
<logs>
<log>L'app entra ufficialmente nello stato di Beta-testing.</log>
<log>Cambiata la modalità di indicazione della versione, non più basata sulla data di aggiornamento, ma sul numero di update dell'app.</log>
<log>Avviata ufficialmente la "Roadmap" sulla Versione 1.0.0 (indicata a fine pagina CHANGELOG).</log>
<log>Aggiunto script per iOS e iPadOS sul rilevamento uso browser/app.</log>
<log>Correzione e bugfix script rilevamento app Android.</log>
</logs>
</version>
<version>
<number>0.12.6 Alpha (Last Release)</number>
<logs>
<log>Aggiornata la lista emittenti nel menu in alto sinistra.</log>
<log>Aggiornate le pagine "Cosa è RPIGRPUP PLAY", "COME FUNZIONA L'APP" e "HAI BISOGNO DI AIUTO".</log>
<log>Corretto bug inizializzazione app per iOS e iPadOS.</log>
<log>Aggiunto script di controllo gestione app per iOS e iPadOS.</log>
<log>Correzione e bugfix di problematiche varie.</log>
</logs>
</version>
<version>
<number>0.12.5 Aplha</number>
<logs>
<log>Realizzazione file XML per il Changelog.</log>
<log>Aggiunto pulsante per la visualizzazione del Changelog.</log>
<log>Correzione pagina About per la visualizzazione del Changelog.</log>
<log>Correzione visualizzazione del Home Page.</log>
<log>Reso automatico il cambio di versione dell'app in base all'ultima versione disponibile e dichiarata all'intero del Changelog.</log>
</logs>
</version>
<version>
<number>0.12.2 Alpha</number>
<logs>
<log>Corretto il problema del caricamento del "Player Mobile" su iOS e derivati.</log>
<log>Corretto e aggiunto nuovi script del "Player Mobile"</log>
<log>Aggiornato slogan dell'emittente "RDL XMAS"</log>
<log>Aggiunto il Changelog</log>
</logs>
</version>
<version>
<number>0.11.30 Alpha</number>
<logs>
<log>Corretto la visualizzazione del "Player Mobile"</log>
<log>Aggiornata la lista emittenti nel menu in alto sinistra</log>
<log>Rimosse momentaneamente le WebTV nel menu in alto sinistra</log>
</logs>
</version>
<version>
<number>0.11.29 Alpha</number>
<logs>
<log>Aggiunta nuova emittente "RDL XMAS"</log>
<log>Corretta la visualizzazione del "PLAYER DESKTOP"</log>
<log>Corretta la visualizzazione della lista emittenti in "Home Desktop" e "Home Mobile"</log>
<log>Abilitato il "Player Mobile" anche in ambiente Desktop</log>
<log>Aggiornato script che impedisce il refresh della pagina da Mobile</log>
</logs>
</version>
<version>
<number>0.9.26 Alpha</number>
<logs>
<log>Cambiata l'URL del flusso audio di RDL e RC105</log>
<log>Correzione e bugfix all'interno dello stile dell'app</log>
<log>Correzione e bugfix all'interno dei metatag</log>
<log>Aggiunto script di disabilitazione pulsante F5 da tastiera</log>
</logs>
</version>
<version>
<number>0.9.24 Alpha</number>
<logs>
<log>Correzione e bugfix player video</log>
</logs>
</version>
<version>
<number>0.9.23 Alpha</number>
<logs>
<log>Aggiunto player video</log>
<log>Aggiunto collegamenti dei canali video delle emittenti</log>
<log>Aggiunto in configurazione gli URL dei canali video delle emittenti</log>
</logs>
</version>
<version>
<number>0.7.31 Alpha</number>
<logs>
<log>Correzione e bugfix all'interno della configurazione dell'app</log>
<log>Rimozione dello script per lo "scroll to update page" da smartphone</log>
<log>Aggiunti i metodi di contatto in About</log>
</logs>
</version>
</changelog>

Binary file not shown.

View File

@@ -8,10 +8,9 @@
<slogan>O Sei Fuori, O Sei Dei Nostri</slogan>
<thematic>false</thematic>
<logo>https://i0.wp.com/www.radiodiffusionelibera.com/wp-content/uploads/2017/01/RDL-Facebook.png</logo>
<stream>https://asvradiostream.asvstudios.it/radio/8000/radio.aac</stream>
<stream>https://asvradiostream.asvstudios.it/radio/8000/radio.mp3</stream>
<streamhls>https://srvone.radio.asvhosting.com/hls/rdlradio/live.m3u8</streamhls>
<contentplayer>https://www.radiodiffusionelibera.com/contentrpigplay</contentplayer>
<apiradio>https://srvone.radio.asvhosting.com/api/nowplaying/2</apiradio>
</station>
<station>
@@ -23,10 +22,9 @@
<stream>https://asvradiostream.asvstudios.it/radio/8020/auto.aac</stream>
<streamhls>https://srvone.radio.asvhosting.com/hls/radiocitta105/live.m3u8</streamhls>
<contentplayer>https://www.radiocitta105.it/contentrpigplay</contentplayer>
<apiradio>https://srvone.radio.asvhosting.com/api/nowplaying/1</apiradio>
</station>
<!-- <station>
<station>
<id>3</id>
<name>RadioAI</name>
<slogan>Solo musica AI - Powered by RDL </slogan>
@@ -35,7 +33,7 @@
<stream>https://srvone.radio.asvhosting.com/listen/radioai/radio.mp3</stream>
<streamhls>https://srvone.radio.asvhosting.com/hls/radioai/live.m3u8</streamhls>
<contentplayer></contentplayer>
</station> -->
</station>
<!-- <station>
<id>4</id>
@@ -48,7 +46,7 @@
<contentplayer></contentplayer>
</station> -->
<!-- <station>
<station>
<id>5</id>
<name>Radio People Italy</name>
<slogan>La radio della Gente</slogan>
@@ -57,6 +55,6 @@
<stream></stream>
<streamhls></streamhls>
<contentplayer>https://www.rpigroup.it/radiopeopleitaly_contentrpigroup/</contentplayer>
</station> -->
</station>
</radio>

Binary file not shown.

View File

@@ -14,8 +14,8 @@
<id>1</id>
<name>Rc105 TV</name>
<logo>https://www.radiocitta105.it/wp-content/uploads/2020/06/26168468_1590103344416186_7025872599153073152_n-1.png</logo>
<stream>https://tv.rpigroup.net/memfs/a9699134-efb3-4932-b8db-5a49ae214031.m3u8</stream>
<poster>https://tv.rpigroup.net/memfs/a9699134-efb3-4932-b8db-5a49ae214031.jpg</poster>
<stream>https://webtv.rpigroup.it/e1e55a4b-abec-4043-8f08-e2105b48b59b.m3u8</stream>
<poster>https://webtv.rpigroup.it/memfs/e1e55a4b-abec-4043-8f08-e2105b48b59b.jpg</poster>
</station>
</tv>

BIN
data/tv.xml:Zone.Identifier Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
img/tv.png:Zone.Identifier Normal file

Binary file not shown.

View File

@@ -5,9 +5,6 @@
# ---------------------------------------------------------------
# Author: A.S.V. Studios APPS
# Website: https://app.rpigroup.net
# Copyright (c) 2025-202 A.S.V. Studios APPS
# ---------------------------------------------------------------
# Questa app è disponibile all'interno della repository pubblica di RPIGroup Play.
# ---------------------------------------------------------------
# All Rights is reserved by A.S.V. Studios APPS.
#

BIN
index.php:Zone.Identifier Normal file

Binary file not shown.

554
js/app.js
View File

@@ -6,8 +6,6 @@ document.addEventListener('DOMContentLoaded', function () {
let hlsInstance = null;
let currentXHR = null;
let isLoading = false;
let loadingOverlay = null;
let metadataInterval = null;
// WeakMap per tracciare i listener degli elementi
const linkListeners = new WeakMap();
@@ -57,12 +55,6 @@ document.addEventListener('DOMContentLoaded', function () {
function cleanupPlayer() {
console.log('Pulizia player audio...');
// Stop metadata updates
if (metadataInterval) {
clearInterval(metadataInterval);
metadataInterval = null;
}
// Distruggi istanza HLS
if (hlsInstance) {
try {
@@ -102,27 +94,6 @@ document.addEventListener('DOMContentLoaded', function () {
}
}
/**
* Mostra l'overlay di caricamento
*/
function showLoadingOverlay() {
if (!loadingOverlay) {
loadingOverlay = document.getElementById('loadingOverlay');
}
if (loadingOverlay) {
loadingOverlay.classList.add('active');
}
}
/**
* Nasconde l'overlay di caricamento
*/
function hideLoadingOverlay() {
if (loadingOverlay) {
loadingOverlay.classList.remove('active');
}
}
/**
* Caricamento pagina con protezione da race condition
*/
@@ -149,9 +120,6 @@ document.addEventListener('DOMContentLoaded', function () {
return;
}
// Mostra l'overlay di caricamento
showLoadingOverlay();
// Animazione fade out
contentContainer.classList.remove('fade-in');
contentContainer.classList.add('fade-out');
@@ -170,9 +138,6 @@ document.addEventListener('DOMContentLoaded', function () {
if (this.status === 200) {
contentContainer.innerHTML = this.responseText;
// Nascondi overlay di caricamento
hideLoadingOverlay();
// Animazione fade in
contentContainer.classList.remove('fade-out');
contentContainer.classList.add('fade-in');
@@ -210,7 +175,6 @@ document.addEventListener('DOMContentLoaded', function () {
console.log('Pagina caricata:', page);
} else {
hideLoadingOverlay();
contentContainer.innerHTML = '<div class="content-page"><h2>Errore</h2><p>Impossibile caricare la pagina. Codice errore: ' + this.status + '</p></div>';
contentContainer.classList.remove('fade-out');
contentContainer.classList.add('fade-in');
@@ -221,7 +185,6 @@ document.addEventListener('DOMContentLoaded', function () {
currentXHR.onerror = function () {
isLoading = false;
currentXHR = null;
hideLoadingOverlay();
contentContainer.innerHTML = '<div class="content-page"><h2>Errore di connessione</h2><p>Controlla la tua connessione internet e riprova.</p></div>';
contentContainer.classList.remove('fade-out');
contentContainer.classList.add('fade-in');
@@ -231,7 +194,6 @@ document.addEventListener('DOMContentLoaded', function () {
currentXHR.onabort = function () {
isLoading = false;
currentXHR = null;
hideLoadingOverlay();
console.log('Richiesta XHR annullata');
};
@@ -347,304 +309,228 @@ document.addEventListener('DOMContentLoaded', function () {
*/
function initializePlayer() {
console.log('Inizializzazione player audio (v2.1 - Format Toggle)...');
console.log('Inizializzazione player audio...');
const playPauseBtn = document.getElementById('playPauseBtn');
const playIcon = document.querySelector('.play-icon');
const pauseIcon = document.querySelector('.pause-icon');
const playerStatus = document.getElementById('playerStatus');
const formatToggleBtn = document.getElementById('formatToggleBtn');
const formatLabel = document.getElementById('formatLabel');
const artistElement = document.getElementById('artist');
if (!playPauseBtn) return;
if (!playPauseBtn) {
console.error('Pulsante play/pause non trovato');
return;
}
// 1. Cleanup Preventivo
// Pulisci il player precedente
cleanupPlayer();
// 2. Setup Elementi
// Ottieni il nuovo audio player dal DOM
audioPlayer = document.getElementById('hlsAudioPlayer');
if (!audioPlayer) return;
if (!audioPlayer) {
console.error('Elemento audio non trovato');
return;
}
const streamHLS = playPauseBtn.getAttribute('data-stream-hls');
const streamFallback = playPauseBtn.getAttribute('data-stream-fallback');
const stationName = playPauseBtn.getAttribute('data-station-name');
const stationSlogan = playPauseBtn.getAttribute('data-station-slogan');
const stationLogo = playPauseBtn.getAttribute('data-station-logo');
console.log('Stream HLS:', streamHLS);
console.log('Stream Fallback:', streamFallback);
console.log('Stazione:', stationName);
// Stato formato audio (preferenza salvata in localStorage)
const storageKey = 'audioFormat_' + stationName;
let currentFormat = localStorage.getItem(storageKey) || 'hls'; // 'hls' o 'direct'
let isPlaying = false;
// Aggiorna label del formato
function updateFormatLabel() {
if (formatLabel) {
formatLabel.textContent = currentFormat === 'hls' ? 'HLS' : 'MP3';
}
}
updateFormatLabel();
// Configurazione HLS.js Ottimizzata per Qualità
const hlsConfig = {
debug: false,
enableWorker: true,
lowLatencyMode: false, // Disabilitato per stabilità e buffer migliore
backBufferLength: 90,
maxBufferLength: 30, // Aumentato buffer (default 30s)
startLevel: -1, // Auto start
xhrSetup: function (xhr, url) {
xhr.withCredentials = false; // Fix CORS issues sometimes
}
};
let streamType = 'hls'; // 'hls' o 'direct'
/**
* Logica di Selezione Player
* Priorità: HLS.js (PC/Android) > Nativo (iOS) > Fallback (Direct Stream)
* Inizializza HLS stream
*/
function initStream(forceFormat = null) {
const preferredFormat = forceFormat || currentFormat;
// Se l'utente ha scelto formato diretto, usa subito MP3/AAC
if (preferredFormat === 'direct') {
console.log('User preference: Direct stream (MP3/AAC)');
useDirectStream();
return;
function initHLSStream() {
if (!window.Hls) {
console.error('HLS.js non caricato');
return false;
}
// STRATEGIA 1: HLS.js (Preferita per PC e Android)
if (Hls.isSupported()) {
console.log('Strategy: HLS.js (High Quality Control)');
console.log('HLS supportato - uso HLS.js');
hlsInstance = new Hls({
debug: false,
enableWorker: true,
lowLatencyMode: true,
backBufferLength: 90
});
hlsInstance = new Hls(hlsConfig);
hlsInstance.loadSource(streamHLS);
hlsInstance.attachMedia(audioPlayer);
hlsInstance.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
console.log(`HLS Manifest Loaded. Levels: ${data.levels.length}`);
// Log dettagliato di tutti i livelli disponibili per debug
data.levels.forEach((level, index) => {
console.log(`Level ${index}: ${level.bitrate} bps (${(level.bitrate / 1000).toFixed(0)} kbps)`);
hlsInstance.on(Hls.Events.MANIFEST_PARSED, function () {
console.log('Manifest HLS caricato');
audioPlayer.play().then(() => {
console.log('Riproduzione HLS avviata');
updatePlayState(true);
}).catch(err => {
console.error('Errore avvio riproduzione HLS:', err);
tryFallbackStream();
});
// CRITICAL: Forza partenza dal livello massimo per garantire qualità alta
if (data.levels.length > 1) {
const maxLevel = data.levels.length - 1;
hlsInstance.startLevel = maxLevel;
console.log(`✓ Forced START level to MAX: ${maxLevel} (${(data.levels[maxLevel].bitrate / 1000).toFixed(0)} kbps)`);
}
attemptPlay();
});
// Track quality switches per debug
hlsInstance.on(Hls.Events.LEVEL_SWITCHING, function (event, data) {
console.log(`→ Switching to level ${data.level}...`);
});
hlsInstance.on(Hls.Events.LEVEL_SWITCHED, function (event, data) {
const currentLevel = hlsInstance.levels[data.level];
console.log(`✓ Switched to level ${data.level}: ${(currentLevel.bitrate / 1000).toFixed(0)} kbps`);
});
hlsInstance.on(Hls.Events.ERROR, function (event, data) {
console.error('Errore HLS:', data.type, data.details);
if (data.fatal) {
console.warn('HLS Fatal Error:', data.type);
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hlsInstance.startLoad();
console.log('Errore di rete, tentativo fallback...');
tryFallbackStream();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('Errore media, tentativo recupero...');
hlsInstance.recoverMediaError();
break;
default:
useDirectStream();
console.log('Errore fatale, tentativo fallback...');
tryFallbackStream();
break;
}
}
});
return;
}
// STRATEGIA 2: Nativo (Obbligatorio per iOS)
if (audioPlayer.canPlayType('application/vnd.apple.mpegurl')) {
console.log('Strategy: Native HLS (iOS/Safari)');
return true;
} else if (audioPlayer.canPlayType('application/vnd.apple.mpegurl')) {
console.log('HLS nativo supportato');
audioPlayer.src = streamHLS;
audioPlayer.preload = 'auto'; // Suggerisce al browser di caricare dati
// Hack per iOS: Alcune volte serve un tocco utente, gestito dal click play
attemptPlay();
return;
audioPlayer.play().then(() => {
console.log('Riproduzione HLS nativa avviata');
updatePlayState(true);
}).catch(err => {
console.error('Errore HLS nativo:', err);
tryFallbackStream();
});
return true;
}
// STRATEGIA 3: Fallback (Stream MP3 diretto)
console.log('Strategy: Direct Fallback');
useDirectStream();
return false;
}
function useDirectStream() {
/**
* Usa stream diretto come fallback
*/
function tryFallbackStream() {
console.log('Tentativo stream fallback:', streamFallback);
if (hlsInstance) {
hlsInstance.destroy();
hlsInstance = null;
}
console.log('Using direct stream:', streamFallback);
streamType = 'direct';
audioPlayer.src = streamFallback;
attemptPlay();
audioPlayer.load();
audioPlayer.play().then(() => {
console.log('Riproduzione stream diretto avviata');
updatePlayState(true);
}).catch(err => {
console.error('Errore stream diretto:', err);
updatePlayState(false);
if (playerStatus) {
playerStatus.textContent = 'Errore di riproduzione';
}
});
}
// Funzione per cambiare formato
function toggleFormat() {
const wasPlaying = !audioPlayer.paused;
/**
* Aggiorna stato visuale play/pause
*/
function updatePlayState(playing) {
isPlaying = playing;
// Cambia formato
currentFormat = currentFormat === 'hls' ? 'direct' : 'hls';
localStorage.setItem(storageKey, currentFormat);
console.log('Switching to format:', currentFormat);
// Aggiorna label
updateFormatLabel();
// Ferma riproduzione corrente
if (audioPlayer) {
audioPlayer.pause();
}
// Pulisci player precedente
if (hlsInstance) {
hlsInstance.destroy();
hlsInstance = null;
}
audioPlayer.src = '';
// Reinizializza con nuovo formato
initStream(currentFormat);
// Riprendi riproduzione se era in corso
if (wasPlaying) {
setTimeout(() => {
togglePlay();
}, 100);
}
}
function attemptPlay() {
// Nota: chiamare .play() senza interazione utente fallirà.
// Questa funzione prepara lo stato. Il vero play avviene al click.
if (playerStatus) playerStatus.textContent = 'Pronto alla riproduzione';
}
function togglePlay() {
if (audioPlayer.paused) {
const playPromise = audioPlayer.play();
if (playPromise !== undefined) {
playPromise.then(() => {
updateUI(true);
}).catch(error => {
console.error('Play prevented:', error);
// Se HLS fallisce al play (es. stale manifest), prova fallback
if (!audioPlayer.src.includes(streamFallback) && !hlsInstance) {
fallbackToDirectStream();
audioPlayer.play().catch(e => console.error('Fallback failed:', e));
}
});
if (playing) {
playIcon.style.display = 'none';
pauseIcon.style.display = 'inline-block';
if (playerStatus) {
playerStatus.textContent = 'In riproduzione...';
}
} else {
playIcon.style.display = 'inline-block';
pauseIcon.style.display = 'none';
if (playerStatus) {
playerStatus.textContent = stationSlogan || 'In pausa';
}
}
}
/**
* Gestione click play/pause
*/
playPauseBtn.addEventListener('click', function () {
if (!audioPlayer) return;
if (isPlaying) {
// Pausa
audioPlayer.pause();
updateUI(false);
}
}
function updateUI(playing) {
isPlaying = playing;
playIcon.style.display = playing ? 'none' : 'block';
pauseIcon.style.display = playing ? 'block' : 'none';
if (playerStatus) {
playerStatus.textContent = playing ? 'In riproduzione' : 'In pausa';
}
}
// Listeners
playPauseBtn.onclick = (e) => {
e.preventDefault();
// Se non inizializzato (primo click), avvia stream
if (!audioPlayer.src && !hlsInstance) {
initStream();
// Piccolo timeout per dare tempo al setup prima del play effettivo
setTimeout(togglePlay, 50);
updatePlayState(false);
console.log('Riproduzione in pausa');
} else {
togglePlay();
// Play
if (!audioPlayer.src && !hlsInstance) {
// Prima riproduzione - inizializza lo stream
if (streamHLS && !initHLSStream()) {
// Se HLS fallisce, usa direttamente il fallback
tryFallbackStream();
}
} else {
// Riprendi riproduzione
audioPlayer.play().then(() => {
updatePlayState(true);
console.log('Riproduzione ripresa');
}).catch(err => {
console.error('Errore ripresa riproduzione:', err);
updatePlayState(false);
});
}
}
};
});
audioPlayer.onplay = () => updateUI(true);
audioPlayer.onpause = () => updateUI(false);
/**
* Event listeners audio player
*/
audioPlayer.addEventListener('play', function () {
updatePlayState(true);
});
audioPlayer.onerror = (e) => {
console.error('Audio Error:', audioPlayer.error);
if (playerStatus) playerStatus.textContent = 'Errore riproduzione';
updateUI(false);
};
audioPlayer.addEventListener('pause', function () {
updatePlayState(false);
});
// Format toggle button listener
if (formatToggleBtn) {
formatToggleBtn.onclick = (e) => {
e.preventDefault();
toggleFormat();
};
}
audioPlayer.addEventListener('error', function (e) {
console.error('Errore audio player:', e);
updatePlayState(false);
if (playerStatus) {
playerStatus.textContent = 'Errore di riproduzione';
}
});
audioPlayer.addEventListener('waiting', function () {
if (playerStatus) {
playerStatus.textContent = 'Buffering...';
}
});
audioPlayer.addEventListener('playing', function () {
if (playerStatus) {
playerStatus.textContent = 'In riproduzione...';
}
});
// Setup Media Session
setupMediaSession(stationName, playPauseBtn.getAttribute('data-station-slogan'), playPauseBtn.getAttribute('data-station-logo'), playIcon, pauseIcon);
setupMediaSession(stationName, stationSlogan, stationLogo, playIcon, pauseIcon);
// --- GESTIONE METADATI (Now Playing) ---
const apiUrl = playPauseBtn.getAttribute('data-api-url');
if (apiUrl) {
console.log('Starting metadata polling for:', apiUrl);
function updateMetadata() {
fetch(apiUrl)
.then(response => response.json())
.then(data => {
if (data.now_playing && data.now_playing.song) {
const song = data.now_playing.song;
// Aggiorna DOM
const songsEl = document.getElementById('songs');
const artistEl = document.getElementById('artist');
const albumArtEl = document.getElementById('albumsong');
if (songsEl) songsEl.textContent = song.title;
if (artistEl) artistEl.textContent = song.artist;
if (albumArtEl && song.art) {
// Evita refresh se l'immagine è la stessa
if (albumArtEl.src !== song.art) {
albumArtEl.src = song.art;
}
}
// Aggiorna Media Session
if ('mediaSession' in navigator) {
navigator.mediaSession.metadata = new MediaMetadata({
title: song.title,
artist: song.artist,
album: stationName,
artwork: [
{ src: song.art || playPauseBtn.getAttribute('data-station-logo'), sizes: '512x512', type: 'image/png' }
]
});
}
}
})
.catch(err => console.error('Error fetching metadata:', err));
}
// Chiamata immediata
updateMetadata();
// Polling ogni 10 secondi
metadataInterval = setInterval(updateMetadata, 10000);
}
console.log('Player System Ready with format toggle.');
console.log('Player audio inizializzato');
}
/**
@@ -652,127 +538,7 @@ document.addEventListener('DOMContentLoaded', function () {
*/
function initializeTVPlayer() {
console.log('TV Player inizializzato');
const video = document.getElementById('tvVideoPlayer');
if (!video) {
console.log('Elemento video TV non trovato');
return;
}
// Cleanup istanza precedente se esiste
if (video.hlsInstance) {
video.hlsInstance.destroy();
delete video.hlsInstance;
}
const videoSrc = video.getAttribute('data-src');
console.log('Video Source:', videoSrc);
if (!videoSrc) {
console.error('Nessuna sorgente video specificata in data-src');
return;
}
// Creazione elemento per errori se non esiste già
let errorDisplay = video.parentNode.querySelector('.tv-error-display');
if (!errorDisplay) {
errorDisplay = document.createElement('div');
errorDisplay.className = 'tv-error-display';
errorDisplay.style.display = 'none';
errorDisplay.style.position = 'absolute';
errorDisplay.style.top = '50%';
errorDisplay.style.left = '50%';
errorDisplay.style.transform = 'translate(-50%, -50%)';
errorDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
errorDisplay.style.color = '#fff';
errorDisplay.style.padding = '20px';
errorDisplay.style.borderRadius = '8px';
errorDisplay.style.textAlign = 'center';
errorDisplay.style.zIndex = '2000';
errorDisplay.style.maxWidth = '90%';
if (video.parentNode) {
video.parentNode.appendChild(errorDisplay);
// Assicurati che il parent sia relative per il posizionamento absolute
if (getComputedStyle(video.parentNode).position === 'static') {
video.parentNode.style.position = 'relative';
}
}
}
function showError(msg, details) {
console.error(msg, details);
errorDisplay.innerHTML = '<strong>Errore:</strong><br>' + msg + (details ? '<br><small>' + details + '</small>' : '');
errorDisplay.style.display = 'block';
}
// Controllo libreria HLS
if (typeof Hls === 'undefined') {
// Riprova tra poco se magari sta ancora caricando
setTimeout(() => {
if (typeof Hls === 'undefined') {
showError('Libreria HLS non caricata correttamente.');
} else {
initializeTVPlayer(); // Riprova inizializzazione
}
}, 500);
return;
}
if (Hls.isSupported()) {
console.log('HLS Supported - Loading stream');
var hls = new Hls({
debug: false,
enableWorker: true
});
hls.loadSource(videoSrc);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
console.log('TV Manifest Parsed - Ready to play');
var playPromise = video.play();
if (playPromise !== undefined) {
playPromise.catch(error => {
console.log('Autoplay blocked or failed:', error);
});
}
});
// Gestione errori estesa
hls.on(Hls.Events.ERROR, function (event, data) {
console.warn('HLS Error:', data);
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('Network error, recovering...');
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('Media error, recovering...');
hls.recoverMediaError();
break;
default:
showError('Errore fatale riproduzione.', data.type);
hls.destroy();
break;
}
}
});
video.hlsInstance = hls;
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
console.log('Native HLS Supported (Safari/iOS)');
video.src = videoSrc;
video.addEventListener('loadedmetadata', function () {
video.play().catch(e => console.log("Autoplay iOS prevented"));
});
video.addEventListener('error', function (e) {
showError('Errore riproduzione nativa.', e.message);
});
} else {
showError('Il tuo browser non supporta HLS.');
}
// Implementare logica specifica per TV se necessario
}
/**
@@ -910,8 +676,8 @@ document.addEventListener('DOMContentLoaded', function () {
const pathWithoutBase = currentPath.replace(BASE_PATH, '').replace(/^\//, '');
const redirectParam = pathWithoutBase ? '&redirect=' + encodeURIComponent(pathWithoutBase) : '';
const width = 400;
const height = 840;
const width = 375;
const height = 667;
const left = (window.screen.width / 2) - (width / 2);
const top = (window.screen.height / 2) - (height / 2);
@@ -947,7 +713,7 @@ document.addEventListener('DOMContentLoaded', function () {
* Setup modalità standalone (PWA)
*/
function setupStandaloneMode() {
const appContainer = document.querySelector('.container') || document.querySelector('.container-fluid');
const appContainer = document.querySelector('.container');
if (!appContainer) return;
if (window.opener && !window.opener.closed) {
@@ -990,7 +756,7 @@ document.addEventListener('DOMContentLoaded', function () {
setupOpenAppButton();
if (document.querySelector('.container') || document.querySelector('.container-fluid')) {
if (document.querySelector('.container')) {
setupStandaloneMode();
attachLinkListeners();
setupHistoryNavigation();

BIN
js/app.js:Zone.Identifier Normal file

Binary file not shown.

7
js/bootstrap.js vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@@ -15,7 +15,7 @@
</div>
</div>
<main class="container-fluid" id="content">
<main class="container" id="content">
<?php
// Carica il contenuto iniziale in base all'URL
switch ($page) {
@@ -93,14 +93,6 @@
?>
</main>
<!-- Loading Overlay -->
<div id="loadingOverlay" class="loading-overlay">
<div class="loading-content">
<div class="spinner-large"></div>
<p class="loading-text">Caricamento...</p>
</div>
</div>
<div class="footer">
<div class="menu-section">
<a href="<?php echo $base_path; ?>/page/termini-condizioni" data-page="page/termini-condizioni" class="navLink">Termini e Condizioni</a> •

Binary file not shown.

Binary file not shown.

View File

@@ -5,29 +5,7 @@
<hr>
<div class="tec">
<p>RPIGroup Play è l'applicazione che permette di ascoltare le radio e le webtv preferite in un unico luogo.</p>
<p>Per utilizzare l'applicazione, basta semplicemente entrare nell'applicazione dal link app.rpigroup.it, selezionare la sezione Radio o TV e scegliere la radio o la webtv che desideri ascoltare.</p>
<br>
<p>
<b>Come installare l'app?</b></br>
Per installare l'applicazione, basta semplicemente entrare nell'applicazione dal link app.rpigroup.it e cliccare sull'icona "Aggiungi all'Home". Oppure, per gli utenti iOS, entrando da safari dal link app.rpigroup.it, cliccare sull'icona "Convididi", scendere alla voce "Aggiungi all'Home" e cliccare su "Aggiungi all'Home".
</p>
<br>
<br><br>
<h2 class="text-center titlePage">F.A.Q.</h2>
<hr>
<p>
<b>Posso scaricarla da Google Play Store e Apple App Store?</b></br>
Non è possibile al momento scaricare l'applicazione da Google Play Store e Apple App Store.
</p>
<p>
<b>Posso utilizzare l'applicazione su un computer?</b></br>
Sì, dal tuo browser preferito, visita la pagina app.rpigroup.it. L'applicazione è anche installabile, cliccando sulla icona dedicata all'installazione della PWA.
</p>
<p>
<b>Posso aggiungere la mia stazione radio preferita?</b></br>
Sì, cliccando sul pulsante "Aggiungi Radio" nella sezione Radio, potrai aggiungere la tua stazione radio preferita compilando il form dedicato.
</p>
<p>La pagina è in fase di realizzazione... Attendi il prossimo aggiornamento per leggere le nostre istruzioni d'uso!</p>
</div>
<a href="<?php echo $base_path; ?>/home" data-page="home" class="linkBox mt-3">

Binary file not shown.

Binary file not shown.

View File

@@ -2,7 +2,6 @@
<h1 class="titlePage">Changelog</h1>
<p class="subtitlePage">Visualizza tutti gli aggiornamenti ricevuti</p>
<p class="text-center mb-4" style="font-size: 0.9rem; font-weight: 300;">Codice dell'app visionabile su <a href="https://git.asv.ovh/asvstudiosapps/rpigroupplay" target="_blank" style="font-weight: 500;">ASV Git</a></p>
<?php
// Verifica che $changelog sia stato caricato correttamente in getStation.inc.php

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -22,38 +22,6 @@
</div>
</div>
<style>
.content-adv{
text-align: center;
background: #3849a8;
padding: 20px;
border-radius: 20px;
}
.content-adv:before{
content: "ADV";
position: relative;
background: #f7b835;
padding: 3px 10px;
font-size: 0.8rem;
border-radius: 27px;
font-style: italic;
font-weight: 600;
top: -10px;
margin: 0;
}
.content-adv img{
max-width: 100%;
border-radius: 10px;
margin-top: -20px;
}
</style>
<div class="content-adv mb-4">
<a href="https://www.worldradioday.it" target="_blank" class="">
<img src="https://www.radiodiffusionelibera.com/wp-content/uploads/2026/01/banner300x250.jpg" alt="adv">
</a>
</div>
<div class="row g-2 mb-4">
<div class="col-12">
<a href="https://www.co-municare.it" target="_blank" class="">
@@ -72,7 +40,7 @@
<div class="col-4">
<a href="<?php echo $base_path; ?>/page/about" data-page="page/about" class="linkBox">
<div class="clickBox">
Come<br>funziona?
Come funziona?
</div>
</a>
</div>
@@ -90,14 +58,4 @@
</div>
</a>
</div>
</div>
<div class="row g-2 mb-4">
<div class="col-12">
<a href="https://drive.asv.ovh/apps/forms/s/Zfk8cJk3oCz2Y2dHyWdEcgL7" target="_blank" class="linkBox">
<div class="clickBox p-2">
Lascia un feedback
</div>
</a>
</div>
</div>

Binary file not shown.

View File

@@ -1,102 +1,62 @@
<?php
$station_id = (string)$station->id;
$station_name = (string)$station->name;
$station_slogan = (string)$station->slogan;
$station_logo = (string)$station->logo;
$station_stream = (string)$station->stream;
$station_streamhls = (string)$station->streamhls;
$station_contentplayer = (string)$station->contentplayer;
$station_apiradio = (string)$station->apiradio;
<?php
if($station->contentplayer == ""){
?>
<style>
.staticpage{
background: linear-gradient(45deg, #3849a8, #f7b835);
padding: 22px 35px 10px 35px;
display: block;
z-index: 1;
position: absolute;
height: calc(100vh - 312px);
color: white;
text-align: center;
width: 100%;
max-width: 450px;
left: 50%;
transform: translateX(-50%);
}
.staticpage > .logo{
width: 200px;
border-radius: 15px;
margin-bottom: 20px;
}
.staticpage > p{
margin: 0;
}
.staticpage > p.titleRadio{
font-weight: 600;
}
</style>
<div class="staticpage">
<img src="<?php echo $station->logo; ?>" class="logo" alt="logo radio">
<p class="titleRadio"><?php echo $station->name; ?></p>
<p class="subtitleRadio"><?php echo $station->slogan; ?></p>
</div>
<?php
}else{
?>
<iframe src="<?php echo $station->contentplayer; ?>" class="contentplayer" frameborder="0"></iframe>
<?php
}
?>
<div class="radio-player-container" style="background-color: #ffffff;height: calc(100% - <?php if($is_mobile){ echo "232px"; }else{ echo "217px"; } ?>);position: absolute;left: calc(50%);display: flex;flex-direction: column;max-width: 750px;transform: translateX(-50%);width: 100%;">
<div class="radio-header" style="padding: 20px; border-bottom: 1px solid #eee; display: flex; align-items: center; justify-content: space-between;">
<div class="left-controls" style="display: flex; align-items: center;">
<a href="<?php echo $base_path; ?>/radio" data-page="radio" class="linkBox" style="color: #333; display: flex; align-items: center; text-decoration: none;">
<span class="material-icons" style="font-size: 28px;">arrow_back</span>
</a>
<span style="font-size: 18px; font-weight: 600; color: #333; margin-left: 15px;"><?php echo $station_name; ?></span>
<div class="footer_player" <?php if($is_mobile){ ?> style="bottom: 84px;" <? } ?>>
<div class="row align-items-center">
<div class="col-2" style="width: 70px;">
<img src="<?php echo $station->logo; ?>" alt="<?php echo $station->name; ?>" style="width: 60px;">
</div>
<?php if(!empty($station_logo)): ?>
<div class="right-controls">
<img src="<?php echo $station_logo; ?>" alt="Logo" style="height: 30px; width: auto;">
<div class="col">
<div id="artist" style="font-weight: 700; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;"><?php echo $station->name; ?></div>
<div id="playerStatus" style="text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical ;overflow: hidden;"><?php echo $station->slogan; ?></div>
</div>
<?php endif; ?>
</div>
<?php
if($station->contentplayer == ""){
?>
<style>
.staticpage{
background: linear-gradient(45deg, #3849a8, #f7b835);
padding: 22px 35px 10px 35px;
display: block;
z-index: 1;
height: calc(100vh - 393px);
color: white;
text-align: center;
width: 100%;
max-width: 750px;
}
.staticpage > .logo{
width: 200px;
border-radius: 15px;
margin-bottom: 20px;
}
.staticpage > p{
margin: 0;
}
.staticpage > p.titleRadio{
font-weight: 600;
}
</style>
<div class="staticpage">
<img src="<?php echo $station->logo; ?>" class="logo" alt="logo radio">
<p class="titleRadio"><?php echo $station->name; ?></p>
<p class="subtitleRadio"><?php echo $station->slogan; ?></p>
</div>
<?php
}else{
?>
<iframe src="<?=$station_contentplayer?>" class="contentplayer" frameborder="0"></iframe>
<?php
}
?>
<div class="footer_player">
<div class="row align-items-center">
<div class="col-2" style="width: 70px;">
<img id="albumsong" src="<?php echo $station->logo; ?>" alt="<?php echo $station->name; ?>" style="width: 60px;height: 60px;">
</div>
<div class="col">
<div id="songs" style="font-weight: 700; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;"><?php echo $station->name; ?></div>
<div id="artist" style="text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical ;overflow: hidden;"><?php echo $station->slogan; ?></div>
</div>
<div class="col-auto" style="text-align: center; margin-top: 1px; padding-right: 0;">
<button id="formatToggleBtn" title="Cambia formato audio">
<span id="formatLabel" style="font-size: 12px;font-weight: 600;border-radius: 6px;border: 2px solid #ffffff;padding: 4px 6px;background: rgba(247, 184, 53, 0.3);color: #2a377e;">HLS</span>
</button>
</div>
<div class="col-2" style="text-align: center; margin-top: 1px; margin-right: 5px; width: 67px;">
<button id="playPauseBtn"
data-stream-hls="<?php echo $station->streamhls; ?>"
data-stream-fallback="<?php echo $station->stream; ?>"
data-station-name="<?php echo htmlspecialchars($station->name); ?>"
data-station-logo="<?php echo $station->logo; ?>"
data-station-slogan="<?php echo htmlspecialchars($station->slogan); ?>"
data-api-url="<?php echo $station_apiradio; ?>">
<i class="material-icons play-icon" id="play-pause" style="font-size: 35px; border-radius: 10px; border: 2px solid #ffffff; padding: 4px 5px 4px 4px; margin-top: -2px; background: #f7b835; color: #2a377e;">play_arrow</i>
<i class="material-icons pause-icon" id="play-pause" style="display:none; font-size: 35px; border-radius: 10px; border: 2px solid #ffffff; padding: 4px 5px 4px 4px; margin-top: -2px; background: #f7b835; color: #2a377e;">pause</i>
</button>
</div>
<div class="col-2" style="text-align: center; margin-top: 1px; margin-right: 5px; width: 67px;">
<button id="playPauseBtn" data-stream-hls="<?php echo $station->streamhls; ?>" data-stream-fallback="<?php echo $station->stream; ?>" data-station-name="<?php echo htmlspecialchars($station->name); ?>" data-station-logo="<?php echo $station->logo; ?>" data-station-slogan="<?php echo htmlspecialchars($station->slogan); ?>">
<i class="material-icons play-icon" id="play-pause" style="font-size: 35px; border-radius: 10px; border: 2px solid #ffffff; padding: 4px 5px 4px 4px; margin-top: -2px; background: #f7b835; color: #2a377e;">play_arrow</i>
<i class="material-icons pause-icon" id="play-pause" style="display:none; font-size: 35px; border-radius: 10px; border: 2px solid #ffffff; padding: 4px 5px 4px 4px; margin-top: -2px; background: #f7b835; color: #2a377e;">pause</i>
</button>
</div>
</div>
</div>
<audio id="hlsAudioPlayer" preload="none"></audio>

Binary file not shown.

View File

@@ -1,50 +0,0 @@
<?php
// Assicurati che $station sia definito (dovrebbe essere passato da mobile.php)
if (!isset($station) || empty($station)) {
echo '<div class="alert alert-danger">Errore: Stazione TV non trovata.</div>';
return;
}
$station_id = (string)$station->id;
$station_name = (string)$station->name;
$station_logo = (string)$station->logo;
$station_stream = (string)$station->stream;
$station_poster = isset($station->poster) ? (string)$station->poster : '';
?>
<!-- Container player con sfondo bianco -->
<div class="tv-player-container" style="background-color: #ffffff;height: calc(100% - <?php if($is_mobile){ echo "232px"; }else{ echo "217px"; } ?>);position: absolute;left: calc(50%);display: flex;flex-direction: column;max-width: 750px;transform: translateX(-50%);width: 100%;">
<!-- Header semplice con pulsante indietro e nome -->
<div class="tv-header" style="padding: 20px; border-bottom: 1px solid #eee; display: flex; align-items: center; justify-content: space-between;">
<div class="left-controls" style="display: flex; align-items: center;">
<a href="<?php echo $base_path; ?>/tv" data-page="tv" class="linkBox" style="color: #333; display: flex; align-items: center; text-decoration: none;">
<span class="material-icons" style="font-size: 28px;">arrow_back</span>
</a>
<span style="font-size: 18px; font-weight: 600; color: #333; margin-left: 15px;"><?php echo $station_name; ?></span>
</div>
<?php if(!empty($station_logo)): ?>
<div class="right-controls">
<img src="<?php echo $station_logo; ?>" alt="Logo" style="height: 30px; width: auto;">
</div>
<?php endif; ?>
</div>
<!-- Area Video -->
<div class="video-wrapper" style="flex: 1; display: flex; align-items: center; justify-content: center; background-color: #000;">
<video id="tvVideoPlayer"
class="video-js"
controls
playsinline
data-src="<?php echo $station_stream; ?>"
poster="<?php echo $station_poster; ?>"
style="width: 100%; max-width: 100%; max-height: 100vh; aspect-ratio: 16/9;">
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
</p>
</video>
</div>
</div>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,27 +1,12 @@
<?php header('Content-Type: text/html; charset=UTF-8'); ?>
<?php
// views/home.php - Vista della pagina principale
$stations = loadTvStations();
?>
<h1 class="titlePage">TV</h1>
<p class="subtitlePage">Seleziona la webtv che vuoi guardare</p>
<p class="subtitlePage">Guarda in streaming <b>RC105 TV</b></p>
<hr>
<div class="stationList">
<div class="row g-2">
<?php foreach ($stations as $station): ?>
<div class="col-6">
<div class="stationCard <?php if((string)$station->thematic === 'true'){echo "isthematic";} ?>" data-id="<?php echo $station->id; ?>">
<a href="<?php echo $base_path; ?>/playtv/<?php echo $station->id; ?>" data-page="playtv/<?php echo $station->id; ?>" class="nav-link stationLink">
<img src="<?php echo $station->logo; ?>" alt="<?php echo $station->name; ?>" class="stationLogo">
</a>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="tec">
<iframe src="https://tv.rpigroup.net/a9699134-efb3-4932-b8db-5a49ae214031.html" style="width:100%; height: 225px;" frameborder="no" scrolling="no" allowfullscreen="true"></iframe>
</div>
<a href="<?php echo $base_path; ?>/home" data-page="home" class="linkBox mt-3">

Binary file not shown.

59
process_contact.php.old Normal file
View File

@@ -0,0 +1,59 @@
<?php
// File: process_contact.php
// Imposta header per JSON
header('Content-Type: application/json');
// Verifica se il modulo è stato inviato
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// Raccolta e pulizia dei dati
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$subject = filter_input(INPUT_POST, 'subject', FILTER_SANITIZE_STRING);
$message = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING);
// Validazione dei dati
$errors = [];
if (empty($name)) {
$errors[] = "Il nome è richiesto";
}
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Email non valida";
}
if (empty($subject)) {
$errors[] = "L'oggetto è richiesto";
}
if (empty($message)) {
$errors[] = "Il messaggio è richiesto";
}
// Se non ci sono errori, procedi con l'invio della mail
if (empty($errors)) {
// Destinatario
$to = "info@tuoaggregatore.it";
// Intestazioni
$headers = "From: $name <$email>" . "\r\n";
$headers .= "Reply-To: $email" . "\r\n";
$headers .= "X-Mailer: PHP/" . phpversion();
// Prova a inviare l'email
$success = mail($to, $subject, $message, $headers);
if ($success) {
echo json_encode(['success' => true, 'message' => 'Messaggio inviato con successo']);
} else {
echo json_encode(['success' => false, 'message' => 'Impossibile inviare il messaggio']);
}
} else {
// Restituisci errori di validazione
echo json_encode(['success' => false, 'message' => implode(', ', $errors)]);
}
} else {
// Se qualcuno prova ad accedere direttamente a questa pagina
echo json_encode(['success' => false, 'message' => 'Metodo non consentito']);
}

Binary file not shown.

View File

@@ -1,6 +1,2 @@
# RPIGroup Play
Il player ufficiale del gruppo RPIGroup
---
Questa repository è connessa al dominio APP.RPIGROUP.IT, ed è modificabile solo dagli utenti autorizzati

BIN
readme.md:Zone.Identifier Normal file

Binary file not shown.

BIN
robots.txt:Zone.Identifier Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -32,40 +32,17 @@ header('Referrer-Policy: strict-origin-when-cross-origin');
<meta name="screen-orientation" content="portrait">
<meta name="x5-orientation" content="portrait">
<meta name="x5-fullscreen" content="true">
<meta name="apple-mobile-web-app-orientations" content="portrait">
<meta name="browsermode" content="application">
<link rel="manifest" href="<?=$base_path?>/manifest.json?v=<?=$version_app?>">
<link rel="stylesheet" href="<?=$base_path?>/css/bootstrap.css">
<link rel="stylesheet" href="<?=$base_path?>/css/style.css?v=<?=$version_app?>">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="<?=$base_path?>/css/animation.css?v=<?=$version_app?>">
<script src="https://code.jquery.com/jquery-2.2.4.js?v=<?=$version_app?>"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="<?=$base_path?>/js/bootstrap.js?v=<?=$version_app?>"></script>
<!-- <link rel="stylesheet" href="<?=$base_path?>/css/animation.css?v=<?=$version_app?>">
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="<?=$base_path?>/js/bootstrap.js"></script> -->
<script>
// Passa il percorso base a JavaScript
var BASE_PATH = "<?=$base_path?>";
// Forza l'orientamento portrait
if (window.screen && window.screen.orientation) {
// Tenta di bloccare l'orientamento in portrait
window.addEventListener('load', function() {
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock('portrait').catch(function(error) {
console.log('Orientation lock not supported or failed:', error);
});
}
});
}
// Fallback per dispositivi che non supportano l'API
// Mostra un avviso se l'utente ruota il dispositivo
window.addEventListener('orientationchange', function() {
if (window.orientation !== 0 && window.orientation !== 180) {
// Il dispositivo è in landscape, ma non possiamo forzarlo
console.log('Si prega di tenere il dispositivo in posizione verticale');
}
});
</script>
</head>
<body class="<?php echo $show_app ? 'appBody' : 'desktopBody'; ?>">

Binary file not shown.