From 0fc70b3e1bf1f940928ac7ad08a777404c31e283 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 18:59:12 +0700 Subject: [PATCH 01/88] u --- srv/http/bash/lcdchar.py | 57 ++++++++++++++++++------------------ srv/http/bash/status-push.sh | 11 +++++-- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index ffdab4ad9..b476f88f3 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -129,19 +129,19 @@ def backlightOff(): sys.exit() # -------------------------------------------------------------------- def second2hhmmss( sec ): - hh = math.floor( sec / 3600 ) - mm = math.floor( ( sec % 3600 ) / 60 ) - ss = sec % 60 - HH = hh > 0 and str( hh ) +':' or '' + hh = math.floor( sec / 3600 ) + mm = math.floor( ( sec % 3600 ) / 60 ) + ss = sec % 60 + HH = hh > 0 and str( hh ) +':' or '' mmt = str( mm ) - MM = hh > 0 and ( mm > 9 and mmt +':' or '0'+ mmt +':' ) or ( mm > 0 and mmt +':' or '' ) + MM = hh > 0 and ( mm > 9 and mmt +':' or '0'+ mmt +':' ) or ( mm > 0 and mmt +':' or '' ) sst = str( ss ) - SS = mm > 0 and ( ss > 9 and sst or '0'+ sst ) or sst + SS = mm > 0 and ( ss > 9 and sst or '0'+ sst ) or sst return HH + MM + SS sys.path.append( '/srv/http/data/shm' ) from lcdcharstatus import * -keys = [ 'Album', 'Artist', 'elapsed', 'file', 'station', 'Time', 'Title' ] +keys = [ 'Album', 'Artist', 'elapsed', 'file', 'station', 'Time', 'timestamp', 'Title' ] data = {} if charmap == 'A00': @@ -151,7 +151,7 @@ def normalize( str ): if unicodedata.category( c ) != 'Mn' ) for k in keys: if k in locals(): - if k in [ 'elapsed', 'Time' ]: + if k in [ 'elapsed', 'Time', 'timestamp' ]: data[ k ] = locals()[ k ] else: data[ k ] = normalize( locals()[ k ] ) @@ -161,25 +161,26 @@ def normalize( str ): for k in keys: data[ k ] = k in locals() and locals()[ k ] or '' -Album = data[ 'Album' ][ :cols ] -Artist = data[ 'Artist' ][ :cols ] -file = data[ 'file' ][ :cols ] -station = data[ 'station' ][ :cols ] -Title = data[ 'Title' ][ :cols ] -elapsed = data[ 'elapsed' ] -Time = data[ 'Time' ] +Album = data[ 'Album' ][ :cols ] +Artist = data[ 'Artist' ][ :cols ] +file = data[ 'file' ][ :cols ] +station = data[ 'station' ][ :cols ] +Title = data[ 'Title' ][ :cols ] +elapsed = data[ 'elapsed' ] +Time = data[ 'Time' ] +timestamp = data[ 'timestamp' ] / 1000 if webradio: if state != 'play': Artist = station - Album = file + Album = file else: if not Artist and not Title: Artist = station - if not Album: Album = station or file + if not Album: Album = station or file if not Artist: Artist = DOTS -if not Title: Title = DOTS -if not Album: Album = DOTS +if not Title: Title = DOTS +if not Album: Album = DOTS if rows == 2: if state == 'play': lines = Title @@ -195,11 +196,11 @@ def normalize( str ): else: if elapsed is False: # can be 0 elapsedhhmmss = '' - slash = '' + slash = '' else: - elapsed = round( float( elapsed ) ) + elapsed = int( elapsed ) elapsedhhmmss = second2hhmmss( elapsed ) - slash = cols > 16 and ' / ' or '/' + slash = cols > 16 and ' / ' or '/' if Time: hhmmss = slash + hhmmss progress = ( elapsedhhmmss + hhmmss + ' ' * cols )[ :cols - 4 ] @@ -209,16 +210,16 @@ def normalize( str ): if state != 'play': sys.exit() # -------------------------------------------------------------------- -row = rows - 1 +row = rows - 1 starttime = time.time() -elapsed += round( starttime - timestamp / 1000 ) -PLAY = ICON[ 'play' ] +elapsed += math.ceil( ( starttime - timestamp ) / 1000 ) +PLAY = ICON[ 'play' ] while True: - sl = 1 - ( ( time.time() - starttime ) % 1 ) + sl = 1 - ( ( time.time() - starttime ) % 1 ) lcd.cursor_pos = ( row, 0 ) - elapsedhhmmss = second2hhmmss( elapsed ) + elapsedhhmmss = second2hhmmss( elapsed ) lcd.write_string( PLAY + elapsedhhmmss + hhmmss ) - elapsed += 1 + elapsed += 1 time.sleep( sl ) \ No newline at end of file diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index c417f3ee3..d89f8a1a1 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -10,9 +10,14 @@ echo $$ > $dirshm/pidstatuspush if [[ $1 == statusradio ]]; then # from status-radio.sh state=play else - status=$( $dirbash/status.sh ) - statusnew=$( sed -E -n '/^, "Artist|^, "Album|^, "Composer|^, "elapsed|^, "file| *"player|^, "station"|^, "state|^, "Time|^, "timestamp|^, "Title|^, "webradio"/ {s/^,* *"//; s/" *: */=/; p}' <<< $status ) - echo "$statusnew" > $dirshm/statusnew + status=$( $dirbash/status.sh | jq ) + statusnew=$( sed -E -n \ +'/^ "Artist|^ "Album|^ "Composer|^ "elapsed|^ "file|^ "player|^ "station"|^ "state|^ "Time|^ "timestamp|^ "Title|^ "webradio/ { + s/^ *"|,$//g + s/" *: */=/ + p +}' <<< $status \ +| tee $dirshm/statusnew ) statusprev=$( < $dirshm/status ) compare='^Artist|^Title|^Album' [[ "$( grep -E "$compare" <<< $statusnew | sort )" != "$( grep -E "$compare" <<< $statusprev | sort )" ]] && trackchanged=1 From 0b4cbb817ebbf8489bb4240eda69c50796159757 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 20:28:05 +0700 Subject: [PATCH 02/88] Update status.sh --- srv/http/bash/status.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/status.sh b/srv/http/bash/status.sh index a3c6f3f0f..c2d1d0ebe 100644 --- a/srv/http/bash/status.sh +++ b/srv/http/bash/status.sh @@ -85,7 +85,7 @@ else , "btreceiver" : '$( exists $dirshm/btreceiver )' , "card" : '$card' , "control" : "'$mixer'" -, "counts" : '$( getContent $dirmpd/counts '{}' )' +, "counts" : '$( getContent $dirmpd/counts '{}' )' , "icon" : "'$icon'" , "librandom" : '$( exists $dirsystem/librandom )' , "lyrics" : '$( exists $dirsystem/lyrics )' From 8bdebceb04a2b54d7ad0edd5e24c52cc12ba3a64 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 20:35:34 +0700 Subject: [PATCH 03/88] u --- srv/http/bash/bluealsa-dbus.py | 8 +++--- srv/http/bash/lcdchar.py | 40 ++++++++++++++-------------- srv/http/bash/status-coverartupnp.py | 4 +-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/srv/http/bash/bluealsa-dbus.py b/srv/http/bash/bluealsa-dbus.py index debb64951..c57267b56 100644 --- a/srv/http/bash/bluealsa-dbus.py +++ b/srv/http/bash/bluealsa-dbus.py @@ -14,8 +14,8 @@ from subprocess import Popen AGENT_INTERFACE = 'org.bluez.Agent1' -path = '/test/autoagent' -filesink = '/srv/http/data/shm/bluetoothsink' +path = '/test/autoagent' +filesink = '/srv/http/data/shm/bluetoothsink' def statusPush(): Popen( [ '/srv/http/bash/status-push.sh' ] ) @@ -41,11 +41,11 @@ def property_changed( interface, changed, invalidated, path ): if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop( set_as_default=True ) - bus = dbus.SystemBus() + bus = dbus.SystemBus() bus.add_signal_receiver( property_changed, bus_name='org.bluez', dbus_interface='org.freedesktop.DBus.Properties', signal_name='PropertiesChanged', path_keyword='path' ) mainloop = GLib.MainLoop() - obj = bus.get_object( 'org.bluez', '/org/bluez' ) + obj = bus.get_object( 'org.bluez', '/org/bluez' ) mainloop.run() diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index b476f88f3..018168142 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -5,9 +5,9 @@ with open( '/srv/http/data/system/lcdchar.conf', 'r' ) as f: conf = {} for line in f: - kv = line.split( '=' ) - k = kv[ 0 ] - v = kv[ 1 ].rstrip() + kv = line.split( '=' ) + k = kv[ 0 ] + v = kv[ 1 ].rstrip() if k == 'address' or k == 'cols': v = int( v ) elif k == 'backlight': @@ -15,7 +15,7 @@ conf[ k ] = v locals().update( conf ) # inf, cols, charmap, address, chip, backlight -rows = cols == 16 and 2 or 4 +rows = cols == 16 and 2 or 4 if inf == 'i2c': from RPLCD.i2c import CharLCD @@ -28,7 +28,7 @@ lcd = CharLCD( cols=cols, rows=rows, charmap=charmap , numbering_mode=GPIO.BOARD, pin_rs=pin_rs, pin_rw=pin_rw, pin_e=pin_e, pins_data=pins_data ) -pause = ( +pause = ( 0b00000, 0b11011, 0b11011, @@ -38,7 +38,7 @@ 0b00000, 0b00000, ) -play = ( +play = ( 0b10000, 0b11000, 0b11100, @@ -48,7 +48,7 @@ 0b10000, 0b00000, ) -stop = ( +stop = ( 0b00000, 0b11111, 0b11111, @@ -58,7 +58,7 @@ 0b00000, 0b00000, ) -logol = ( +logol = ( 0b11111, 0b11011, 0b11011, @@ -68,7 +68,7 @@ 0b11111, 0b11111, ) -logor = ( +logor = ( 0b01110, 0b10110, 0b10110, @@ -78,7 +78,7 @@ 0b11010, 0b11100, ) -dot = ( +dot = ( 0b00000, 0b00000, 0b00000, @@ -88,24 +88,24 @@ 0b00000, 0b00000, ) -char = [ pause, play, stop, logol, logor, dot ] +char = [ pause, play, stop, logol, logor, dot ] for i in range( 6 ): lcd.create_char( i, char[ i ] ) -ICON = { +ICON = { 'pause' : '\x00 ' , 'play' : '\x01 ' , 'stop' : '\x02 ' } -RA = '\x03\x04' -DOTS = '\x05 \x05 \x05' -RN = '\r\n' +RA = '\x03\x04' +DOTS = '\x05 \x05 \x05' +RN = '\r\n' SPACES = ' ' * ( ( cols - 6 ) // 2 + 1 ) -LOGO = rows > 2 and RN or '' -LOGO += SPACES + RA + RN + SPACES +'rAudio' +LOGO = rows > 2 and RN or '' +LOGO += SPACES + RA + RN + SPACES +'rAudio' -argvL = len( sys.argv ) +argvL = len( sys.argv ) if argvL == 2: # 1 argument val = sys.argv[ 1 ] if val == 'off': # backlight off @@ -141,8 +141,8 @@ def second2hhmmss( sec ): sys.path.append( '/srv/http/data/shm' ) from lcdcharstatus import * -keys = [ 'Album', 'Artist', 'elapsed', 'file', 'station', 'Time', 'timestamp', 'Title' ] -data = {} +keys = [ 'Album', 'Artist', 'elapsed', 'file', 'station', 'Time', 'timestamp', 'Title' ] +data = {} if charmap == 'A00': import unicodedata diff --git a/srv/http/bash/status-coverartupnp.py b/srv/http/bash/status-coverartupnp.py index e1f50f5f8..d9954a80d 100644 --- a/srv/http/bash/status-coverartupnp.py +++ b/srv/http/bash/status-coverartupnp.py @@ -4,9 +4,9 @@ import upnpp device = socket.gethostname() +'-UPnP/AV' -srv = upnpp.findTypedService( device, 'avtransport', True ) # AVTransport service +srv = upnpp.findTypedService( device, 'avtransport', True ) # AVTransport service if srv: - retdata = upnpp.runaction( srv, 'GetMediaInfo', ['0'] ) + retdata = upnpp.runaction( srv, 'GetMediaInfo', ['0'] ) metadata = retdata[ 'CurrentURIMetaData' ] if metadata: dirc = upnpp.UPnPDirContent() From fb12abb674db9fc6d9d298809bed9e100ae30663 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 21:09:19 +0700 Subject: [PATCH 04/88] u --- srv/http/bash/lcdchar.py | 5 +++++ srv/http/bash/status-push.sh | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index 018168142..cf83273d8 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -189,6 +189,11 @@ def normalize( str ): else: lines = Artist + RN + Title + RN + Album +if webradio and not radioelapsed: + progress = ( ' ' * cols )[ :cols - 4 ] + lcd.write_string( lines + RN + ICON[ state ] + progress + RA ) + sys.exit() +# -------------------------------------------------------------------- hhmmss = Time and second2hhmmss( round( float( Time ) ) ) or '' if state == 'stop': diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index d89f8a1a1..ad238dae6 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -56,7 +56,11 @@ if [[ $clientip ]]; then done fi if [[ -e $dirsystem/lcdchar ]]; then - sed -E 's/(true|false)$/\u\1/' $dirshm/status > $dirshm/lcdcharstatus.py + grep -q radioelapsed.*true $dirsystem/display.json && radioelapsed=True || radioelapsed=False + sed -E -e 's/(true|false)$/\u\1/ +' -e "$ a\ +radioelapsed=$radioelapsed +" $dirshm/status > $dirshm/lcdcharstatus.py systemctl restart lcdchar fi From f63344409481c9b7bf57f19239e707d27d384515 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 21:16:30 +0700 Subject: [PATCH 05/88] Update lcdchar.py --- srv/http/bash/lcdchar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index cf83273d8..e4f04addf 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -213,7 +213,7 @@ def normalize( str ): if backlight and state != 'play': backlightOff() -if state != 'play': sys.exit() +if state != 'play' or elapsed is False: sys.exit() # -------------------------------------------------------------------- row = rows - 1 starttime = time.time() From 1a20561975c30b1551f05a18aa851d465412641b Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 21:26:23 +0700 Subject: [PATCH 06/88] u --- srv/http/bash/lcdchar.py | 5 ----- srv/http/bash/status-push.sh | 8 +++----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index e4f04addf..2fc5a86fb 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -189,11 +189,6 @@ def normalize( str ): else: lines = Artist + RN + Title + RN + Album -if webradio and not radioelapsed: - progress = ( ' ' * cols )[ :cols - 4 ] - lcd.write_string( lines + RN + ICON[ state ] + progress + RA ) - sys.exit() -# -------------------------------------------------------------------- hhmmss = Time and second2hhmmss( round( float( Time ) ) ) or '' if state == 'stop': diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index ad238dae6..e308fc2d2 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -56,11 +56,9 @@ if [[ $clientip ]]; then done fi if [[ -e $dirsystem/lcdchar ]]; then - grep -q radioelapsed.*true $dirsystem/display.json && radioelapsed=True || radioelapsed=False - sed -E -e 's/(true|false)$/\u\1/ -' -e "$ a\ -radioelapsed=$radioelapsed -" $dirshm/status > $dirshm/lcdcharstatus.py + status=$( sed -E -e 's/(true|false)$/\u\1/' $dirshm/status ) + grep -q radioelapsed.*false $dirsystem/display.json && status=$( sed -E 's/^(elapsed=).*/\1False/' <<< $status ) + echo "$status" > $dirshm/lcdcharstatus.py systemctl restart lcdchar fi From 886eb1743aaf8ad10af649689142c8f287974591 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 22:07:11 +0700 Subject: [PATCH 07/88] Update status-push.sh --- srv/http/bash/status-push.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index e308fc2d2..d0916f457 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -56,9 +56,11 @@ if [[ $clientip ]]; then done fi if [[ -e $dirsystem/lcdchar ]]; then - status=$( sed -E -e 's/(true|false)$/\u\1/' $dirshm/status ) - grep -q radioelapsed.*false $dirsystem/display.json && status=$( sed -E 's/^(elapsed=).*/\1False/' <<< $status ) - echo "$status" > $dirshm/lcdcharstatus.py + status=$( < $dirshm/status ) + if [[ $webradio ]]; then + grep -q radioelapsed.*false $dirsystem/display.json && status=$( sed -E 's/^(elapsed=).*/\1false/' <<< $status ) + fi + sed -E 's/(true|false)$/\u\1/' $dirshm/status <<< $status > $dirshm/lcdcharstatus.py systemctl restart lcdchar fi From 38acc2e3975b024b10610e47407b5a5d5ea62f47 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 28 Dec 2024 22:13:27 +0700 Subject: [PATCH 08/88] Update status-push.sh --- srv/http/bash/status-push.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index d0916f457..3ad202888 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -57,10 +57,10 @@ if [[ $clientip ]]; then fi if [[ -e $dirsystem/lcdchar ]]; then status=$( < $dirshm/status ) - if [[ $webradio ]]; then - grep -q radioelapsed.*false $dirsystem/display.json && status=$( sed -E 's/^(elapsed=).*/\1false/' <<< $status ) + if grep -q ^webradio=true <<< $status && grep -q radioelapsed.*false $dirsystem/display.json; then + status=$( sed -E 's/^(elapsed=).*/\1false/' <<< $status ) fi - sed -E 's/(true|false)$/\u\1/' $dirshm/status <<< $status > $dirshm/lcdcharstatus.py + sed -E 's/(true|false)$/\u\1/' <<< $status > $dirshm/lcdcharstatus.py systemctl restart lcdchar fi From c19bc7b6a3af3d1884335f428d5d08c2ae77eee6 Mon Sep 17 00:00:00 2001 From: rern Date: Sun, 29 Dec 2024 09:21:11 +0700 Subject: [PATCH 09/88] u --- srv/http/assets/js/camilla.js | 2 +- srv/http/assets/js/common.js | 21 +++++++++++---------- srv/http/assets/js/main.js | 1 - srv/http/assets/js/networks.js | 2 +- srv/http/assets/js/passive.js | 4 ++-- srv/http/assets/js/player.js | 4 ++-- srv/http/assets/js/settings.js | 6 ++---- srv/http/assets/js/system.js | 2 +- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/srv/http/assets/js/camilla.js b/srv/http/assets/js/camilla.js index 829708cca..bc384da9c 100644 --- a/srv/http/assets/js/camilla.js +++ b/srv/http/assets/js/camilla.js @@ -1,4 +1,4 @@ -ps.volume = data => { +W.volume = data => { if ( V.local ) { V.local = false; return diff --git a/srv/http/assets/js/common.js b/srv/http/assets/js/common.js index 6efe74763..d8d57627a 100644 --- a/srv/http/assets/js/common.js +++ b/srv/http/assets/js/common.js @@ -7,13 +7,9 @@ websocket bash() */ -var page = location.search.replace( /\?p=|&.*/g, '' ); // .../settings.php/p=PAGE&x=XXX... > PAGE -var iconwarning = ico( 'warning yl' ) +' '; -var localhost = [ 'localhost', '127.0.0.1' ].includes( location.hostname ); -var orange = '#de810e'; -var red = '#bb2828'; -var ws; -var ps = { +S = {} // status +V = {} // variable +W = { // ws push bluetooth : () => { if ( page === 'networks' ) { S.listbt = data; @@ -127,7 +123,12 @@ var ps = { } } } - +var page = location.search.replace( /\?p=|&.*/g, '' ); // .../settings.php/p=PAGE&x=XXX... > PAGE +var iconwarning = ico( 'warning yl' ) +' '; +var localhost = [ 'localhost', '127.0.0.1' ].includes( location.hostname ); +var orange = '#de810e'; +var red = '#bb2828'; +var ws; // ---------------------------------------------------------------------- /* $( ELEMENT ).press( DELEGATE, function( e ) { @@ -1441,13 +1442,13 @@ function websocketConnect( ip ) { } }, 100 ); } - ws.onmessage = message => { // ps: push status + ws.onmessage = message => { var data = message.data; if ( data === 'pong' ) { // on pageActive - reload if ws not response V.timeoutreload = false; } else { var json = JSON.parse( data ); - if ( json.channel in ps ) ps[ json.channel ]( json.data ); + if ( json.channel in W ) W[ json.channel ]( json.data ); } } } diff --git a/srv/http/assets/js/main.js b/srv/http/assets/js/main.js index f4cac603b..07e2b1c1d 100644 --- a/srv/http/assets/js/main.js +++ b/srv/http/assets/js/main.js @@ -2,7 +2,6 @@ C = {}; // counts D = {}; // display E = {}; // equalizer O = []; // order -S = {}; // status V = { // var global apikeyfanart : '06f56465de874e4c75a2e9f0cc284fa3' , apikeylastfm : '328f08885c2b5a4d1dbe1496cab60b15' diff --git a/srv/http/assets/js/networks.js b/srv/http/assets/js/networks.js index 11e80d45b..dc3e67e87 100644 --- a/srv/http/assets/js/networks.js +++ b/srv/http/assets/js/networks.js @@ -1,4 +1,4 @@ -ps.wlan = () => { +W.wlan = () => { if ( data && 'reboot' in data ) { info( { icon : 'wifi' diff --git a/srv/http/assets/js/passive.js b/srv/http/assets/js/passive.js index bf86038db..37b29f299 100644 --- a/srv/http/assets/js/passive.js +++ b/srv/http/assets/js/passive.js @@ -1,5 +1,5 @@ -ps = { - ...ps // from common.js +W = { + ...W // from common.js , airplay : data => { statusUpdate( data ); if ( V.playback ) renderPlayback(); diff --git a/srv/http/assets/js/player.js b/srv/http/assets/js/player.js index 6a6201371..7640584e0 100644 --- a/srv/http/assets/js/player.js +++ b/srv/http/assets/js/player.js @@ -1,4 +1,4 @@ -ps.mpdupdate = data => { +W.mpdupdate = data => { if ( 'done' in data ) { $.each( S.counts, ( k, v ) => { S[ k ] = data.done[ k ] } ); S.updatetime = data.updatetime @@ -6,7 +6,7 @@ ps.mpdupdate = data => { util.renderStatus(); } } -ps.volume = data => { +W.volume = data => { if ( ! ( 'db' in data ) ) return S.volume = data.val; diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 503a504e6..7fb1b5f12 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -4,10 +4,8 @@ Naming must be the same for: js - id = icon = NAME, #setting-NAME bash - cmd=NAME, save to NAME.conf */ -S = {} // status -V = {} -ps = { - ...ps // from common.js +W = { + ...W // from common.js , camilla : data => { S.range = data; $( '#volume' ).prop( { min: S.range.VOLUMEMIN, max: S.range.VOLUMEMAX } ) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 32b233aea..fef9cc4f0 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -1,4 +1,4 @@ -ps.storage = data => { +W.storage = data => { clearTimeout( V.debounce ); V.debounce = setTimeout( () => { S.liststorage = data.list; From ed9c400dc5bcbb081a5bb358bb28fa75b955b10e Mon Sep 17 00:00:00 2001 From: rern Date: Sun, 29 Dec 2024 21:52:58 +0700 Subject: [PATCH 10/88] u --- install.sh | 3 +++ srv/http/assets/js/common.js | 1 - srv/http/assets/js/system.js | 26 +++++++++---------- srv/http/bash/lcdchar.py | 36 ++++++--------------------- srv/http/bash/settings/data-config.sh | 34 +++++++++++-------------- srv/http/bash/settings/system.sh | 14 +++++++++++ srv/http/bash/status-push.sh | 8 +++--- 7 files changed, 58 insertions(+), 64 deletions(-) diff --git a/install.sh b/install.sh index c298a6c6c..3c0451908 100644 --- a/install.sh +++ b/install.sh @@ -4,6 +4,9 @@ alias=r1 . /srv/http/bash/settings/addons.sh +# 20250106 +[[ -e $dirsystem/lcdchar && ! -e $dirsystem/lcdcharconf.py ]] && $dirsettings/system.sh lcdchar + # 20241208 rm -f $dirshm/playlist* diff --git a/srv/http/assets/js/common.js b/srv/http/assets/js/common.js index d8d57627a..5646c1b68 100644 --- a/srv/http/assets/js/common.js +++ b/srv/http/assets/js/common.js @@ -6,7 +6,6 @@ loader() local() selectSet() websocket bash() */ - S = {} // status V = {} // variable W = { // ws push diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index fef9cc4f0..c8f97ee5b 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -127,7 +127,7 @@ var config = { } } , lcdchar : data => { - 'address' in data ? util.lcdchar.i2s( data ) : util.lcdchar.gpio( data ); + util.lcdchar[ data.values.INF ]( data ); } , mpdoled : data => { var values = data.values; @@ -343,7 +343,7 @@ var util = { } } , lcdchar : { - gpio : values => { + gpio : data => { var list0 = jsonClone( util.lcdchar.list ); var list = list0.slice( 0, 3 ); [ 'Pins:   D4', 'RS', 'D5', 'RW', 'D6', 'E', 'D7' ].forEach( ( k, i ) => { @@ -352,32 +352,32 @@ var util = { list.push( [ '', '' ], list0.slice( -1 )[ 0 ] ); info( { ...util.lcdchar.json - , tab : [ () => infoSetting( 'lcdchar', util.lcdchar.i2s ), '' ] + , tab : [ () => infoSetting( 'lcdchar i2c', config.lcdchar ), '' ] , message : util.gpiosvg , list : list , boxwidth : 70 - , values : values - , checkchanged : S.lcdchar + , values : data.values + , checkchanged : S.lcdchar && data.current === 'gpio' } ); } - , i2s : data => { + , i2c : data => { var list = jsonClone( util.lcdchar.list ); list[ 3 ][ 2 ].kv = data.address; info( { ...util.lcdchar.json - , tab : [ '', () => infoSetting( 'lcdchar gpio', util.lcdchar.gpio ) ] + , tab : [ '', () => infoSetting( 'lcdchar gpio', config.lcdchar ) ] , list : list , boxwidth : 180 , values : data.values - , checkchanged : S.lcdchar + , checkchanged : S.lcdchar && data.current === 'i2c' } ); } , json : { - icon : 'lcdchar' - , title : 'Character LCD' - , tablabel : [ 'I²C', 'GPIO' ] - , footer : ico( 'raudio' ) +'Logo '+ ico( 'screenoff' ) +'Sleep' - , beforeshow : () => { + icon : 'lcdchar' + , title : 'Character LCD' + , tablabel : [ 'I²C', 'GPIO' ] + , footer : ico( 'raudio' ) +'Logo '+ ico( 'screenoff' ) +'Sleep' + , beforeshow : () => { $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); $( '.infofooter i' ) .toggleClass( 'disabled', ! S.lcdchar ) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index 2fc5a86fb..7d10f54c6 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -2,18 +2,8 @@ import sys -with open( '/srv/http/data/system/lcdchar.conf', 'r' ) as f: - conf = {} - for line in f: - kv = line.split( '=' ) - k = kv[ 0 ] - v = kv[ 1 ].rstrip() - if k == 'address' or k == 'cols': - v = int( v ) - elif k == 'backlight': - v = bool( v ) - conf[ k ] = v -locals().update( conf ) # inf, cols, charmap, address, chip, backlight +sys.path.append( '/srv/http/data/system' ) # i2c : inf, cols, charmap, backlight, address, chip +from lcdcharconf import * # gpio : inf, cols, charmap, backlight, p*... rows = cols == 16 and 2 or 4 @@ -22,11 +12,10 @@ lcd = CharLCD( cols=cols, rows=rows, charmap=charmap , address=address, i2c_expander=chip ) else: - pins_data = [ p0, p1, p2, p3 ] from RPLCD.gpio import CharLCD from RPi import GPIO lcd = CharLCD( cols=cols, rows=rows, charmap=charmap - , numbering_mode=GPIO.BOARD, pin_rs=pin_rs, pin_rw=pin_rw, pin_e=pin_e, pins_data=pins_data ) + , numbering_mode=GPIO.BOARD, pin_rs=pin_rs, pin_rw=pin_rw, pin_e=pin_e, pins_data=[ p0, p1, p2, p3 ] ) pause = ( 0b00000, @@ -140,8 +129,8 @@ def second2hhmmss( sec ): return HH + MM + SS sys.path.append( '/srv/http/data/shm' ) -from lcdcharstatus import * -keys = [ 'Album', 'Artist', 'elapsed', 'file', 'station', 'Time', 'timestamp', 'Title' ] +from status import * +keys = [ 'Album', 'Artist', 'file', 'station', 'Title' ] data = {} if charmap == 'A00': @@ -150,25 +139,16 @@ def normalize( str ): return ''.join( c for c in unicodedata.normalize( 'NFD', str ) if unicodedata.category( c ) != 'Mn' ) for k in keys: - if k in locals(): - if k in [ 'elapsed', 'Time', 'timestamp' ]: - data[ k ] = locals()[ k ] - else: - data[ k ] = normalize( locals()[ k ] ) - else: - data[ k ] = '' + data[ k ] = k in locals() and normalize( locals()[ k ] ) or '' else: for k in keys: data[ k ] = k in locals() and locals()[ k ] or '' - +# set width Album = data[ 'Album' ][ :cols ] Artist = data[ 'Artist' ][ :cols ] file = data[ 'file' ][ :cols ] station = data[ 'station' ][ :cols ] Title = data[ 'Title' ][ :cols ] -elapsed = data[ 'elapsed' ] -Time = data[ 'Time' ] -timestamp = data[ 'timestamp' ] / 1000 if webradio: if state != 'play': @@ -212,7 +192,7 @@ def normalize( str ): # -------------------------------------------------------------------- row = rows - 1 starttime = time.time() -elapsed += math.ceil( ( starttime - timestamp ) / 1000 ) +elapsed += math.ceil( ( starttime - timestamp / 1000 ) / 1000 ) PLAY = ICON[ 'play' ] while True: diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 3b3245294..cc1d54108 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -3,10 +3,11 @@ . /srv/http/bash/common.sh toReboot() { - if [[ -e $dirshm/reboot ]]; then - grep -q $CMD <<< $dirshm/reboot && echo true || echo false + if [[ -s $dirshm/reboot ]]; then + grep -q $ID <<< $dirshm/reboot && echo true || echo false else echo false + rm -f $dirshm/reboot fi } @@ -58,21 +59,20 @@ i2slist ) lcdchar ) fileconf=$dirsystem/lcdchar.conf if [[ -e $fileconf ]]; then - grep -q ^p0 $fileconf && conf2json $fileconf && exit # gpio -# -------------------------------------------------------------------- values=$( conf2json $fileconf ) - else - if [[ $2 ]]; then - echo '{ "INF": "gpio", "COLS": 20, "CHARMAP": "A00" - , "P0": 21, "PIN_RS": 15, "P1": 22, "PIN_RW": 18, "P2": 23, "PIN_E": 16, "P3": 24 - , "BACKLIGHT": false }' - exit + current=$( getVar inf $fileconf ) + [[ ! $2 && $current == gpio ]] && echo '{ "values": '$values', "current": "'$current'" }' && exit # -------------------------------------------------------------------- - fi - values='{ "INF": "i2c", "COLS": 20, "CHARMAP": "A00" - , "ADDRESS": 39, "CHIP": "PCF8574" - , "BACKLIGHT": false }' fi + val='{ "INF": "gpio", "COLS": 20, "CHARMAP": "A00"' + if [[ $2 == gpio ]]; then + [[ $current != gpio ]] && values=$val', "P0": 21, "PIN_RS": 15, "P1": 22, "PIN_RW": 18, "P2": 23, "PIN_E": 16, "P3": 24' + elif [[ $2 == i2c ]]; then + [[ $current != i2c ]] && values=${val/gpio/i2c}', "ADDRESS": 39, "CHIP": "PCF8574"' + fi + ! grep -q BACKLIGHT <<< $values && values+=', "BACKLIGHT": false }' + [[ $2 == gpio ]] && echo '{ "values": '$values', "current": "'$current'" }' && exit +# -------------------------------------------------------------------- dev=$( ls /dev/i2c* 2> /dev/null | cut -d- -f2 ) [[ $dev ]] && lines=$( i2cdetect -y $dev 2> /dev/null ) if [[ $lines ]]; then @@ -87,11 +87,7 @@ lcdchar ) else address=', "0x27": 39, "0x3f": 63' fi - echo '{ - "values" : '$values' -, "address" : { '${address:1}' } -, "reboot" : '$( toReboot )' -}' + echo '{ "values": '$values', "current": "'$current'", "address": { '${address:1}' } }' ;; localbrowser ) echo '{ diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 7387d286c..e3b48857e 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -203,6 +203,20 @@ lcdchar ) enableFlagSet i2cset=1 configTxt + if [[ $ON ]]; then + fileconf=$dirsystem/lcdchar.conf + filter='^backlight|^charmap|^chip|^inf' + . <( grep -E $filter $fileconf ) + data=$( grep -v -E $filter $fileconf ) + data+=' +backlight='$( [[ $backlight ]] && echo True || echo False )' +inf="'$inf'" +charmap="'$charmap'"' + [[ $inf == i2c ]] && data+=' +chip="'$chip'"' + echo "$data" > $dirsystem/lcdcharconf.py + $dirbash/status-push.sh + fi ;; lcdcharset ) systemctl stop lcdchar diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index 3ad202888..f7a245470 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -56,11 +56,13 @@ if [[ $clientip ]]; then done fi if [[ -e $dirsystem/lcdchar ]]; then - status=$( < $dirshm/status ) + status=$( sed -E 's/(true|false)$/\u\1/' $dirshm/status ) if grep -q ^webradio=true <<< $status && grep -q radioelapsed.*false $dirsystem/display.json; then - status=$( sed -E 's/^(elapsed=).*/\1false/' <<< $status ) + status="\ +$( grep -v ^elapsed <<< $status ) +elapsed=False" fi - sed -E 's/(true|false)$/\u\1/' <<< $status > $dirshm/lcdcharstatus.py + echo "$status" > $dirshm/status.py systemctl restart lcdchar fi From 5028fcdaf51787284da23bc2e9c36fe672101f7e Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 10:51:12 +0700 Subject: [PATCH 11/88] u --- install.sh | 6 ++- srv/http/assets/js/system.js | 5 +- srv/http/bash/common.sh | 4 +- srv/http/bash/lcdchar.py | 73 +++++++++++++-------------- srv/http/bash/settings/data-config.sh | 6 +-- srv/http/bash/settings/system.sh | 14 ----- srv/http/bash/status-push.sh | 15 +++--- srv/http/bash/status-radio.sh | 1 + 8 files changed, 59 insertions(+), 65 deletions(-) diff --git a/install.sh b/install.sh index 3c0451908..3ffe40828 100644 --- a/install.sh +++ b/install.sh @@ -5,7 +5,11 @@ alias=r1 . /srv/http/bash/settings/addons.sh # 20250106 -[[ -e $dirsystem/lcdchar && ! -e $dirsystem/lcdcharconf.py ]] && $dirsettings/system.sh lcdchar +file=$dirsystem/lcdchar.conf +if [[ -e $dirsystem/lcdchar.conf ]]; then + conf2json $file | jq > ${file/conf/json} + rm -f $file +fi # 20241208 rm -f $dirshm/playlist* diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index c8f97ee5b..da2abd525 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -386,7 +386,10 @@ var util = { } ); } , cancel : switchCancel - , ok : switchEnable + , ok : () => { + jsonSave( 'lcdchar', infoVal() ); + switchEnable(); + } , fileconf : true } , list : [ diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index 9e1f05e9a..02daedbcc 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -216,13 +216,13 @@ getVar() { # var=value local data line var data=$( < $2 ) if [[ $( head -1 <<< $data ) == { ]]; then - var=$( sed -n -E '/'$1'/ {s/.*: "*|"*,*$//g; p}' <<< $data ) + var=$( sed -n -E '/'$1'/ {s/.*: "*|"*,*$//g; p}' <<< $data ) # var: value else line=$( grep ^$1= <<< $data ) # var= [[ ! $line ]] && line=$( grep -E "^${1// /|^}" <<< $data ) # var [[ ! $line ]] && line=$( grep -E "^\s*${1// /|^\s*}" <<< $data ) # var [[ $line != *=* ]] && line=$( sed 's/ \+/=/' <<< $line ) # var value > var=value - var=$( sed -E "s/.* *= *//; s/^[\"']|[\"'];*$//g" <<< $line ) # var=value || var = value || var="value"; > value + var=$( sed -E "s/.* *= *//; s/^[\"']|[\"'];*$//g" <<< $line ) # var=value || var = value || var="value"; > value fi [[ $var ]] && quoteEscape $var || echo $3 } diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index 7d10f54c6..a0effef32 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -1,21 +1,23 @@ #!/usr/bin/python import sys +import json -sys.path.append( '/srv/http/data/system' ) # i2c : inf, cols, charmap, backlight, address, chip -from lcdcharconf import * # gpio : inf, cols, charmap, backlight, p*... +with open( '/srv/http/data/system/lcdchar.json' ) as f: + CONF = json.load( f ) # i2c : INF, COLS, CHARMAP, BACKLIGHT, [ ADDRESS, CHIP | P* ... ] +locals().update( CONF ) +rows = COLS == 16 and 2 or 4 -rows = cols == 16 and 2 or 4 - -if inf == 'i2c': +if INF == 'i2c': from RPLCD.i2c import CharLCD - lcd = CharLCD( cols=cols, rows=rows, charmap=charmap - , address=address, i2c_expander=chip ) + lcd = CharLCD( cols=COLS, rows=rows, charmap=CHARMAP + , address=ADDRESS, i2c_expander=CHIP ) else: from RPLCD.gpio import CharLCD from RPi import GPIO - lcd = CharLCD( cols=cols, rows=rows, charmap=charmap - , numbering_mode=GPIO.BOARD, pin_rs=pin_rs, pin_rw=pin_rw, pin_e=pin_e, pins_data=[ p0, p1, p2, p3 ] ) + GPIO.setwarnings( False ) + lcd = CharLCD( cols=COLS, rows=rows, charmap=CHARMAP + , numbering_mode=GPIO.BOARD, pin_rs=PIN_RS, pin_rw=PIN_RW, pin_e=PIN_E, pins_data=[ P0, P1, P2, P3 ] ) pause = ( 0b00000, @@ -90,7 +92,7 @@ DOTS = '\x05 \x05 \x05' RN = '\r\n' -SPACES = ' ' * ( ( cols - 6 ) // 2 + 1 ) +SPACES = ' ' * ( ( COLS - 6 ) // 2 + 1 ) LOGO = rows > 2 and RN or '' LOGO += SPACES + RA + RN + SPACES +'rAudio' @@ -111,6 +113,13 @@ import math import time +if CHARMAP == 'A00': + A00 = True + import unicodedata + def normalize( str ): + return ''.join( c for c in unicodedata.normalize( 'NFD', str ) + if unicodedata.category( c ) != 'Mn' ) + def backlightOff(): time.sleep( 60 ) lcd.backlight_enabled = False @@ -128,27 +137,17 @@ def second2hhmmss( sec ): SS = mm > 0 and ( ss > 9 and sst or '0'+ sst ) or sst return HH + MM + SS -sys.path.append( '/srv/http/data/shm' ) -from status import * -keys = [ 'Album', 'Artist', 'file', 'station', 'Title' ] -data = {} - -if charmap == 'A00': - import unicodedata - def normalize( str ): - return ''.join( c for c in unicodedata.normalize( 'NFD', str ) - if unicodedata.category( c ) != 'Mn' ) - for k in keys: - data[ k ] = k in locals() and normalize( locals()[ k ] ) or '' -else: - for k in keys: - data[ k ] = k in locals() and locals()[ k ] or '' -# set width -Album = data[ 'Album' ][ :cols ] -Artist = data[ 'Artist' ][ :cols ] -file = data[ 'file' ][ :cols ] -station = data[ 'station' ][ :cols ] -Title = data[ 'Title' ][ :cols ] +with open( '/srv/http/data/shm/status.json' ) as f: + STATUS = json.load( f ) + +for k in [ 'Album', 'Artist', 'file', 'station', 'Title' ]: + if k in STATUS: + v = str( STATUS[ k ] ) + if A00: STATUS[ k ] = normalize( v ) + STATUS[ k ] = v[ :COLS ] # set width + else: + STATUS[ k ] = '' +locals().update( STATUS ) if webradio: if state != 'play': @@ -157,14 +156,14 @@ def normalize( str ): else: if not Artist and not Title: Artist = station if not Album: Album = station or file - + if not Artist: Artist = DOTS if not Title: Title = DOTS if not Album: Album = DOTS if rows == 2: if state == 'play': lines = Title - elif backlight: + elif BACKLIGHT: backlightOff() else: lines = Artist + RN + Title + RN + Album @@ -172,7 +171,7 @@ def normalize( str ): hhmmss = Time and second2hhmmss( round( float( Time ) ) ) or '' if state == 'stop': - progress = ( hhmmss + ' ' * cols )[ :cols - 4 ] + progress = ( hhmmss + ' ' * COLS )[ :COLS - 4 ] else: if elapsed is False: # can be 0 elapsedhhmmss = '' @@ -180,13 +179,13 @@ def normalize( str ): else: elapsed = int( elapsed ) elapsedhhmmss = second2hhmmss( elapsed ) - slash = cols > 16 and ' / ' or '/' + slash = COLS > 16 and ' / ' or '/' if Time: hhmmss = slash + hhmmss - progress = ( elapsedhhmmss + hhmmss + ' ' * cols )[ :cols - 4 ] + progress = ( elapsedhhmmss + hhmmss + ' ' * COLS )[ :COLS - 4 ] lcd.write_string( lines + RN + ICON[ state ] + progress + RA ) -if backlight and state != 'play': backlightOff() +if BACKLIGHT and state != 'play': backlightOff() if state != 'play' or elapsed is False: sys.exit() # -------------------------------------------------------------------- diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index cc1d54108..8c8ba54a1 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -57,10 +57,10 @@ i2slist ) cat /srv/http/assets/data/system-i2s.json ;; lcdchar ) - fileconf=$dirsystem/lcdchar.conf + fileconf=$dirsystem/lcdchar.json if [[ -e $fileconf ]]; then - values=$( conf2json $fileconf ) - current=$( getVar inf $fileconf ) + values=$( < $fileconf ) + current=$( jq .INF $fileconf ) [[ ! $2 && $current == gpio ]] && echo '{ "values": '$values', "current": "'$current'" }' && exit # -------------------------------------------------------------------- fi diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index e3b48857e..7387d286c 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -203,20 +203,6 @@ lcdchar ) enableFlagSet i2cset=1 configTxt - if [[ $ON ]]; then - fileconf=$dirsystem/lcdchar.conf - filter='^backlight|^charmap|^chip|^inf' - . <( grep -E $filter $fileconf ) - data=$( grep -v -E $filter $fileconf ) - data+=' -backlight='$( [[ $backlight ]] && echo True || echo False )' -inf="'$inf'" -charmap="'$charmap'"' - [[ $inf == i2c ]] && data+=' -chip="'$chip'"' - echo "$data" > $dirsystem/lcdcharconf.py - $dirbash/status-push.sh - fi ;; lcdcharset ) systemctl stop lcdchar diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index f7a245470..b6776427f 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -7,8 +7,9 @@ killProcess statuspush echo $$ > $dirshm/pidstatuspush -if [[ $1 == statusradio ]]; then # from status-radio.sh +if [[ $1 == statusradio ]]; then # from status-radio.sh radioStatusFile state=play + statusradio=1 else status=$( $dirbash/status.sh | jq ) statusnew=$( sed -E -n \ @@ -56,13 +57,13 @@ if [[ $clientip ]]; then done fi if [[ -e $dirsystem/lcdchar ]]; then - status=$( sed -E 's/(true|false)$/\u\1/' $dirshm/status ) - if grep -q ^webradio=true <<< $status && grep -q radioelapsed.*false $dirsystem/display.json; then - status="\ -$( grep -v ^elapsed <<< $status ) -elapsed=False" + if [[ ! $statusradio ]]; then + json=$( conf2json -nocap $dirshm/status | jq ) + if [[ $( jq .webradio <<< $json ) == true ]]; then + [[ $( jq .radioelapsed $dirsystem/display.json ) == false ]] && json=$( jq '.elapsed = false' <<< $json ) + fi + echo "$json" > $dirshm/status.json fi - echo "$status" > $dirshm/status.py systemctl restart lcdchar fi diff --git a/srv/http/bash/status-radio.sh b/srv/http/bash/status-radio.sh index 9a2456616..786ff97fd 100644 --- a/srv/http/bash/status-radio.sh +++ b/srv/http/bash/status-radio.sh @@ -155,6 +155,7 @@ webradio CMD ARTIST ALBUM MODE" &> /dev/null & fi pushData mpdradio "{ $data }" + [[ -e $dirsystem/lcdchar ]] && jq <<< "{ $data }" > $dirshm/status.json [[ -e $dirsystem/scrobble ]] && cp -f $dirshm/status{,prev} radioStatusFile [[ $coverart ]] && $dirbash/cmd.sh coverfileslimit From 195de761dcd0019473bd65893e765e4f8065746b Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 10:55:58 +0700 Subject: [PATCH 12/88] Update data-config.sh --- srv/http/bash/settings/data-config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 8c8ba54a1..2f04c216c 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -60,7 +60,7 @@ lcdchar ) fileconf=$dirsystem/lcdchar.json if [[ -e $fileconf ]]; then values=$( < $fileconf ) - current=$( jq .INF $fileconf ) + current=$( jq -r .INF $fileconf ) [[ ! $2 && $current == gpio ]] && echo '{ "values": '$values', "current": "'$current'" }' && exit # -------------------------------------------------------------------- fi From 132ab7a580f1dad29d7a8d990079dd016a56de90 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 14:32:51 +0700 Subject: [PATCH 13/88] u --- srv/http/bash/lcdchar.py | 17 +++++++---------- srv/http/bash/status-push.sh | 2 +- srv/http/bash/status-radio.sh | 10 ++++++++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index a0effef32..84fe388ce 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -3,10 +3,10 @@ import sys import json -with open( '/srv/http/data/system/lcdchar.json' ) as f: - CONF = json.load( f ) # i2c : INF, COLS, CHARMAP, BACKLIGHT, [ ADDRESS, CHIP | P* ... ] -locals().update( CONF ) -rows = COLS == 16 and 2 or 4 +with open( '/srv/http/data/system/lcdchar.json' ) as f: CONF = json.load( f ) +locals().update( CONF ) # INF, COLS, CHARMAP, BACKLIGHT, [ ADDRESS, CHIP | P* ... ] +rows = COLS == 16 and 2 or 4 +cmA00 = CHARMAP == 'A00' if INF == 'i2c': from RPLCD.i2c import CharLCD @@ -113,8 +113,7 @@ import math import time -if CHARMAP == 'A00': - A00 = True +if cmA00: import unicodedata def normalize( str ): return ''.join( c for c in unicodedata.normalize( 'NFD', str ) @@ -137,13 +136,11 @@ def second2hhmmss( sec ): SS = mm > 0 and ( ss > 9 and sst or '0'+ sst ) or sst return HH + MM + SS -with open( '/srv/http/data/shm/status.json' ) as f: - STATUS = json.load( f ) - +with open( '/srv/http/data/shm/status.json' ) as f: STATUS = json.load( f ) for k in [ 'Album', 'Artist', 'file', 'station', 'Title' ]: if k in STATUS: v = str( STATUS[ k ] ) - if A00: STATUS[ k ] = normalize( v ) + if cmA00: STATUS[ k ] = normalize( v ) STATUS[ k ] = v[ :COLS ] # set width else: STATUS[ k ] = '' diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index b6776427f..4d270547f 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -60,7 +60,7 @@ if [[ -e $dirsystem/lcdchar ]]; then if [[ ! $statusradio ]]; then json=$( conf2json -nocap $dirshm/status | jq ) if [[ $( jq .webradio <<< $json ) == true ]]; then - [[ $( jq .radioelapsed $dirsystem/display.json ) == false ]] && json=$( jq '.elapsed = false' <<< $json ) + grep -q radioelapsed.*false $dirsystem/display.json && json=$( jq '.elapsed = false' <<< $json ) fi echo "$json" > $dirshm/status.json fi diff --git a/srv/http/bash/status-radio.sh b/srv/http/bash/status-radio.sh index 786ff97fd..b4aff2a98 100644 --- a/srv/http/bash/status-radio.sh +++ b/srv/http/bash/status-radio.sh @@ -134,7 +134,7 @@ $( jq -r .albumTitle <<< $track )" fi fi [[ -e $coverfile ]] && coverart=${coverfile:9} || coverart= - elapsed=$( mpcElapsed ) + grep -q radioelapsed.*false $dirsystem/display.json && elapsed=false || elapsed=$( mpcElapsed ) pllength=$( mpc status %length% ) data=' "player" : "mpd" @@ -155,7 +155,13 @@ webradio CMD ARTIST ALBUM MODE" &> /dev/null & fi pushData mpdradio "{ $data }" - [[ -e $dirsystem/lcdchar ]] && jq <<< "{ $data }" > $dirshm/status.json + if [[ -e $dirsystem/lcdchar ]]; then + data+=' +, "Time" : false +, "timestamp" : '$( date +%s%3N )' +, "webradio" : true' + echo "{ $data }" > $dirshm/status.json + fi [[ -e $dirsystem/scrobble ]] && cp -f $dirshm/status{,prev} radioStatusFile [[ $coverart ]] && $dirbash/cmd.sh coverfileslimit From bb8113421b26e48d67ef58d97de2338b8a033b60 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 14:42:39 +0700 Subject: [PATCH 14/88] Update lcdchar.py --- srv/http/bash/lcdchar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index 84fe388ce..032b07b74 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -140,8 +140,8 @@ def second2hhmmss( sec ): for k in [ 'Album', 'Artist', 'file', 'station', 'Title' ]: if k in STATUS: v = str( STATUS[ k ] ) - if cmA00: STATUS[ k ] = normalize( v ) - STATUS[ k ] = v[ :COLS ] # set width + if cmA00: STATUS[ k ] = normalize( v ) # character: accent with sequence code > single code + STATUS[ k ] = v[ :COLS ] # set width else: STATUS[ k ] = '' locals().update( STATUS ) From afdb5bdc75c526b245c8b18e0bc728d792634a98 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 14:48:00 +0700 Subject: [PATCH 15/88] Update lcdchar.py --- srv/http/bash/lcdchar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index 032b07b74..b9484610e 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -188,7 +188,7 @@ def second2hhmmss( sec ): # -------------------------------------------------------------------- row = rows - 1 starttime = time.time() -elapsed += math.ceil( ( starttime - timestamp / 1000 ) / 1000 ) +elapsed += math.ceil( ( starttime * 1000 - timestamp ) / 1000000 ) PLAY = ICON[ 'play' ] while True: From 1b772c114debc4469a9fd28379503f71c5110d85 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 17:40:28 +0700 Subject: [PATCH 16/88] u --- srv/http/bash/common.sh | 6 +++++- srv/http/bash/lcdchar.py | 2 +- srv/http/bash/status-push.sh | 20 ++++++-------------- srv/http/bash/status.sh | 7 ++++--- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index 02daedbcc..f340b2c18 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -288,7 +288,11 @@ $2" fi } mpcElapsed() { - mpc status %currenttime% | awk -F: '{print ($1 * 60) + $2}' + if [[ $1 ]] && grep -q radioelapsed.*false $dirsystem/display.json; then # webradio + radioelapsed + echo false + else + mpc status %currenttime% | awk -F: '{print ($1 * 60) + $2}' + fi } mpcPlayback() { $dirbash/cmd.sh "mpcplayback diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index b9484610e..69302b72a 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -139,7 +139,7 @@ def second2hhmmss( sec ): with open( '/srv/http/data/shm/status.json' ) as f: STATUS = json.load( f ) for k in [ 'Album', 'Artist', 'file', 'station', 'Title' ]: if k in STATUS: - v = str( STATUS[ k ] ) + v = STATUS[ k ] or DOTS if cmA00: STATUS[ k ] = normalize( v ) # character: accent with sequence code > single code STATUS[ k ] = v[ :COLS ] # set width else: diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index 4d270547f..84821755d 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -12,13 +12,11 @@ if [[ $1 == statusradio ]]; then # from status-radio.sh radioStatusFile statusradio=1 else status=$( $dirbash/status.sh | jq ) - statusnew=$( sed -E -n \ -'/^ "Artist|^ "Album|^ "Composer|^ "elapsed|^ "file|^ "player|^ "station"|^ "state|^ "Time|^ "timestamp|^ "Title|^ "webradio/ { - s/^ *"|,$//g - s/" *: */=/ - p -}' <<< $status \ -| tee $dirshm/statusnew ) + for k in Artist Album Composer elapsed file player station state Time timestamp Title webradio; do + filter+='|^ "'$k + done + statuslines=$( grep -E "${filter:1}" <<< $status ) + statusnew=$( sed -E 's/^ *"|,$//g; s/" *: */=/' <<< $statuslines | tee $dirshm/statusnew ) statusprev=$( < $dirshm/status ) compare='^Artist|^Title|^Album' [[ "$( grep -E "$compare" <<< $statusnew | sort )" != "$( grep -E "$compare" <<< $statusprev | sort )" ]] && trackchanged=1 @@ -57,13 +55,7 @@ if [[ $clientip ]]; then done fi if [[ -e $dirsystem/lcdchar ]]; then - if [[ ! $statusradio ]]; then - json=$( conf2json -nocap $dirshm/status | jq ) - if [[ $( jq .webradio <<< $json ) == true ]]; then - grep -q radioelapsed.*false $dirsystem/display.json && json=$( jq '.elapsed = false' <<< $json ) - fi - echo "$json" > $dirshm/status.json - fi + [[ ! $statusradio ]] && jq <<< "{ ${statuslines%,} }" > $dirshm/status.json # remove trailing , systemctl restart lcdchar fi diff --git a/srv/http/bash/status.sh b/srv/http/bash/status.sh index c2d1d0ebe..9991b69ae 100644 --- a/srv/http/bash/status.sh +++ b/srv/http/bash/status.sh @@ -279,6 +279,7 @@ elif [[ $stream ]]; then [[ $onlinefile ]] && coverart="${onlinefile:9}" fi else + webradio=1 ext=Radio if [[ $file == *rtsp://*$( hostname -f )* ]]; then ext=DAB @@ -366,7 +367,7 @@ elif [[ $stream ]]; then , "Title" : "'$Title'" , "webradio" : true' if [[ $radio_dab ]]; then # rp / rf / dab - elapsed=$( mpcElapsed ) + elapsed=$( mpcElapsed $webradio ) ######## status+=' , "coverart" : "'$coverart'" @@ -496,7 +497,7 @@ status+=' , "sampling" : "'$sampling'"' if [[ $coverart || ! $displaycover ]]; then # webradio $coverart exists - elapsed=$( mpcElapsed ) + elapsed=$( mpcElapsed $webradio ) # >>>>>>>>>> webradio with found coverart ######## status+=' @@ -515,7 +516,7 @@ $Album $filenoesc CMD ARTIST ALBUM FILE" ) fi -elapsed=$( mpcElapsed ) +elapsed=$( mpcElapsed $webradio ) ######## status+=' , "elapsed" : '$elapsed' From c409081b04f64b363f462df7f12ad95b8c022e51 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 20:42:23 +0700 Subject: [PATCH 17/88] u --- srv/http/assets/js/system.js | 2 +- srv/http/bash/settings/system.sh | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index da2abd525..ec5c57180 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -382,7 +382,7 @@ var util = { $( '.infofooter i' ) .toggleClass( 'disabled', ! S.lcdchar ) .on( 'click', function() { - bash( [ 'lcdcharset', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); + bash( [ 'lcdchar', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); } ); } , cancel : switchCancel diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 7387d286c..03d1caa80 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -200,11 +200,12 @@ dtparam=audio=on" configTxt ;; lcdchar ) - enableFlagSet - i2cset=1 - configTxt - ;; -lcdcharset ) + if [[ ! $ACTION ]]; then + enableFlagSet + i2cset=1 + configTxt + ACTION=logo + fi systemctl stop lcdchar $dirbash/lcdchar.py $ACTION ;; From a0b639547a81cbaf4a4990c16b7c6c58a13eb4eb Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 20:49:40 +0700 Subject: [PATCH 18/88] u --- srv/http/assets/css/settings.css | 1 + srv/http/assets/js/system.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/srv/http/assets/css/settings.css b/srv/http/assets/css/settings.css index decb1da45..79ab6d94a 100644 --- a/srv/http/assets/css/settings.css +++ b/srv/http/assets/css/settings.css @@ -670,6 +670,7 @@ input.disabled + .switchlabel:after { .helpblock bl, .i-mute, .img, + .infofooter a, .listtitle, .page-icon, .setting, diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index ec5c57180..3a5693f2b 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -376,10 +376,10 @@ var util = { icon : 'lcdchar' , title : 'Character LCD' , tablabel : [ 'I²C', 'GPIO' ] - , footer : ico( 'raudio' ) +'Logo '+ ico( 'screenoff' ) +'Sleep' + , footer : ''+ ico( 'raudio' ) +'Logo'+ ico( 'screenoff' ) +'Sleep' , beforeshow : () => { $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); - $( '.infofooter i' ) + $( '.infofooter a' ) .toggleClass( 'disabled', ! S.lcdchar ) .on( 'click', function() { bash( [ 'lcdchar', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); From 15bbba37ea042335d37ea76af5f89b25ce27c067 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 30 Dec 2024 21:07:09 +0700 Subject: [PATCH 19/88] u --- srv/http/assets/css/common.css | 7 ++++++- srv/http/assets/css/settings.css | 1 - srv/http/assets/js/function.js | 12 +++++------- srv/http/assets/js/system.js | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 21f1b1aba..4a57b1ab2 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -10,7 +10,7 @@ @font-face { font-family : rern; - src : url( '/assets/fonts/rern.woff2?v=1733921041' ); + src : url( '/assets/fonts/rern.woff2?v=1735435369' ); } @font-face { font-family : Lato; @@ -824,9 +824,13 @@ hr { color: var( --cg60 ); } .infofooter i { + width: auto !important; margin: 0 6px; vertical-align: -2px; } +.infofooter span { + margin-right: 10px; +} .infomessage { padding-top: 5px; line-height: 24px; @@ -1052,6 +1056,7 @@ input[ type=radio ]:disabled { .i-volume, .infobtn, .infofooter i, + .infofooter span, .infolabel i, .infomessage img, .infomessage .tagpath, diff --git a/srv/http/assets/css/settings.css b/srv/http/assets/css/settings.css index 79ab6d94a..decb1da45 100644 --- a/srv/http/assets/css/settings.css +++ b/srv/http/assets/css/settings.css @@ -670,7 +670,6 @@ input.disabled + .switchlabel:after { .helpblock bl, .i-mute, .img, - .infofooter a, .listtitle, .page-icon, .setting, diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 5db356cdf..611b08539 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -741,10 +741,10 @@ function infoTitle() { var titlenoparen = title.replace( / $|\(.*$/, '' ); list.push( [ ico( 'music wh' ) +'Title includes: '+ title.replace( /^.*\(/, '(' ), 'checkbox' ] ); } - var footer = ''+ ico( 'lyrics' ) +' Lyrics' - +''+ ico( 'bio' ) +' Bio' - +''+ ico( 'lastfm' ) +' Add Similar' - +''+ ico( 'lastfm' ) +' Scrobble'; + var footer = ''+ ico( 'lyrics' ) +'Lyrics' + +''+ ico( 'bio' ) +'Bio' + +''+ ico( 'lastfm' ) +'Add Similar' + +''+ ico( 'lastfm' ) +'Scrobble'; info( { icon : 'playback' , title : 'Current Track' @@ -756,9 +756,7 @@ function infoTitle() { , values : paren ? [ artist, titlenoparen, album ] : [ artist, title, album ] , beforeshow : () => { $( '#infoList input' ).eq( 2 ).toggleClass( 'hide', album === '' ); - $( '.infofooter' ) - .css( 'padding-left', '40px' ) - .find( 'span' ).css( { 'margin-right': '20px', cursor: 'pointer' } ); + $( '.infofooter' ).css( 'padding-left', '35px' ); $( '.infofooter .lyrics' ).toggleClass( 'hide', ! S.lyrics ); $( '.infofooter .scrobble' ).toggleClass( 'hide', ! S.scrobble ); if ( S.scrobble ) $( '.infofooter .scrobble' ).toggleClass( 'disabled', ! artist || ! title || ! S.webradio || S.scrobbleconf[ S.player ] ); diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 3a5693f2b..1bebdafae 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -376,7 +376,7 @@ var util = { icon : 'lcdchar' , title : 'Character LCD' , tablabel : [ 'I²C', 'GPIO' ] - , footer : ''+ ico( 'raudio' ) +'Logo'+ ico( 'screenoff' ) +'Sleep' + , footer : ''+ ico( 'raudio' ) +'Logo'+ ico( 'screenoff' ) +'Sleep' , beforeshow : () => { $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); $( '.infofooter a' ) From a3c9e3197d477296a93e57182d525793969b3403 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 11:03:42 +0700 Subject: [PATCH 20/88] u --- srv/http/assets/css/common.css | 3 +++ srv/http/assets/js/settings.js | 6 ++---- srv/http/assets/js/system.js | 17 ++++++++--------- srv/http/bash/settings/data-config.sh | 8 ++++---- srv/http/bash/settings/system.sh | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 4a57b1ab2..77ecc232d 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -831,6 +831,9 @@ hr { .infofooter span { margin-right: 10px; } +.infofooter span:last-child { + margin-right: 0; +} .infomessage { padding-top: 5px; line-height: 24px; diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 7fb1b5f12..5b5206622 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -25,10 +25,8 @@ W = { } $( '#'+ player_id[ data.player ] ).toggleClass( 'disabled', data.active ); } - , reboot : data => { - var msg = ''; - data.id.forEach( id => msg += '
• '+ $( '#div'+ id +' .label' ).text() +'
' ); - banner( 'reboot', 'Reboot required', msg, 5000 ); + , reboot : () => { + if ( page === 'system' ) banner( SW.icon, SW.title, 'Reboot required', 5000 ); } , refresh : data => { if ( data.page !== page ) return diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 1bebdafae..958668dce 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -373,24 +373,23 @@ var util = { } ); } , json : { - icon : 'lcdchar' - , title : 'Character LCD' - , tablabel : [ 'I²C', 'GPIO' ] - , footer : ''+ ico( 'raudio' ) +'Logo'+ ico( 'screenoff' ) +'Sleep' - , beforeshow : () => { + icon : 'lcdchar' + , title : 'Character LCD' + , tablabel : [ 'I²C', 'GPIO' ] + , footer : ''+ ico( 'raudio' ) +'Logo'+ ico( 'screenoff' ) +'Sleep' + , beforeshow : () => { $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); - $( '.infofooter a' ) + $( '.infofooter span' ) .toggleClass( 'disabled', ! S.lcdchar ) .on( 'click', function() { bash( [ 'lcdchar', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); } ); } - , cancel : switchCancel - , ok : () => { + , cancel : switchCancel + , ok : () => { jsonSave( 'lcdchar', infoVal() ); switchEnable(); } - , fileconf : true } , list : [ [ 'Type', 'hidden' ] diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 2f04c216c..f4e361529 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -104,10 +104,6 @@ mpdoled ) , "reboot" : '$( toReboot )' }' ;; -reboot ) - getContent $dirshm/reboot - rm -f $dirshm/{reboot,backup.gz} - ;; packagelist ) filepackages=/tmp/packages if [[ ! -e $filepackages ]]; then @@ -135,6 +131,10 @@ $description fi grep -B1 -A2 --no-group-separator ^${2,} $filepackages ;; +reboot ) + getContent $dirshm/reboot + rm -f $dirshm/{reboot,backup.gz} + ;; relays ) if [[ -e $dirsystem/relays.conf ]]; then . $dirsystem/relays.conf diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 03d1caa80..985f9790f 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -67,8 +67,8 @@ dtoverlay=gpio-shutdown,gpio_pin=17,active_low=0,gpio_pull=down" fi fi if [[ $reboot ]]; then + pushData reboot 1 appendSortUnique $CMD $dirshm/reboot - pushData reboot '{ "id": '$( line2array $( < $dirshm/reboot ) )' }' else sed -i "/$CMD/ d" $dirshm/reboot fi From 570c78acc1dd84247f013a58446e6978835eb009 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 11:23:01 +0700 Subject: [PATCH 21/88] u --- srv/http/assets/js/settings.js | 8 -------- srv/http/assets/js/system.js | 2 ++ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 5b5206622..ff6a7de06 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -6,11 +6,6 @@ Naming must be the same for: */ W = { ...W // from common.js - , camilla : data => { - S.range = data; - $( '#volume' ).prop( { min: S.range.VOLUMEMIN, max: S.range.VOLUMEMAX } ) - $( '.tab input[type=range]' ).prop( { min: S.range.GAINMIN, max: S.range.GAINMAX } ); - } , mpdplayer : data => playbackButton( data ) , mpdradio : data => playbackButton( data ) , player : data => { @@ -25,9 +20,6 @@ W = { } $( '#'+ player_id[ data.player ] ).toggleClass( 'disabled', data.active ); } - , reboot : () => { - if ( page === 'system' ) banner( SW.icon, SW.title, 'Reboot required', 5000 ); - } , refresh : data => { if ( data.page !== page ) return diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 958668dce..6d331644e 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -1,3 +1,4 @@ +W.reboot = () => banner( SW.icon, SW.title, 'Reboot required', 5000 ); W.storage = data => { clearTimeout( V.debounce ); V.debounce = setTimeout( () => { @@ -6,6 +7,7 @@ W.storage = data => { if ( $( '#data' ).length ) $( '#data' ).html( highlightJSON( S ) ); }, 1000 ); } + var config = { _disable : { shareddata : () => { From dce44202dcd81f2f92d0c7f7d4f0425ee50b70d9 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 11:34:08 +0700 Subject: [PATCH 22/88] Update settings.js --- srv/http/assets/js/settings.js | 67 +++++++++++++++++----------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index ff6a7de06..298d37dc4 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -4,23 +4,7 @@ Naming must be the same for: js - id = icon = NAME, #setting-NAME bash - cmd=NAME, save to NAME.conf */ -W = { - ...W // from common.js - , mpdplayer : data => playbackButton( data ) - , mpdradio : data => playbackButton( data ) - , player : data => { - if ( ! [ 'camilla', 'player' ].includes( page ) ) return - - var player_id = { - airplay : 'shairport-sync' - , bluetooth : 'bluetooth' - , snapcast : 'snapserver' - , spotify : 'spotifyd' - , upnp : 'upmpdcli' - } - $( '#'+ player_id[ data.player ] ).toggleClass( 'disabled', data.active ); - } - , refresh : data => { +W.refresh = data => { if ( data.page !== page ) return clearTimeout( V.debounce ); @@ -35,6 +19,38 @@ W = { }, 300 ); } } +if ( [ 'camilla', 'player' ].includes( page ) ) { + W = { + ...W // from common.js + , mpdplayer : data => playbackButton( data ) + , mpdradio : data => playbackButton( data ) + , player : data => { + var player_id = { + airplay : 'shairport-sync' + , bluetooth : 'bluetooth' + , snapcast : 'snapserver' + , spotify : 'spotifyd' + , upnp : 'upmpdcli' + } + $( '#'+ player_id[ data.player ] ).toggleClass( 'disabled', data.active ); + } + } + function playbackButton( data ) { + if ( data ) [ 'player', 'state' ].forEach( k => S[ k ] = data[ k ] ); + if ( S.pllength ) { + var btn = S.state === 'play' ? 'pause' : 'play'; + } else { + var btn = 'play disabled'; + } + $( '.playback' ).prop( 'class', 'playback i-'+ btn ); + } + $( '.playback' ).on( 'click', function() { // for player and camilla + S.state = S.state === 'play' ? 'pause' : 'play'; + if ( page === 'camilla' && S.state === 'pause' ) render.statusStop(); + playbackButton(); + bash( [ 'cmd.sh', 'mpcplayback' ] ); + } ); +} function bannerReset() { var delay = $( '#bannerIcon i' ).hasClass( 'blink' ) ? 1000 : 3000; @@ -127,17 +143,6 @@ function notifyCommon( message ) { } banner( SW.icon +' blink', SW.title, message, -1 ); } -function playbackButton( data ) { - if ( ! [ 'camilla', 'player' ].includes( page ) ) return - - if ( data ) [ 'player', 'state' ].forEach( k => S[ k ] = data[ k ] ); - if ( S.pllength ) { - var btn = S.state === 'play' ? 'pause' : 'play'; - } else { - var btn = 'play disabled'; - } - $( '.playback' ).prop( 'class', 'playback i-'+ btn ); -} function refreshData() { if ( page === 'guide' || ( I.active && ! I.rangelabel ) ) return @@ -317,12 +322,6 @@ $( '.container' ).on( 'click', '.status .headtitle, .col-l.status', function() { $( '.page-icon' ).on( 'click', function() { $( '#debug' ).trigger( 'click' ); } ).press( () => location.reload() ); -$( '.playback' ).on( 'click', function() { // for player and camilla - S.state = S.state === 'play' ? 'pause' : 'play'; - if ( page === 'camilla' && S.state === 'pause' ) render.statusStop(); - playbackButton(); - bash( [ 'cmd.sh', 'mpcplayback' ] ); -} ); $( '.head .i-gear' ).on( 'click', function() { $( '#bar-bottom' ).toggle(); } ); From a9f33f57abc259faab1cb469df3bc80788dea150 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 12:40:45 +0700 Subject: [PATCH 23/88] u --- srv/http/assets/js/camilla.js | 2 +- srv/http/assets/js/player.js | 2 +- srv/http/assets/js/settings.js | 61 +++++++++++++++------------------- srv/http/bash/cmd.sh | 2 -- 4 files changed, 28 insertions(+), 39 deletions(-) diff --git a/srv/http/assets/js/camilla.js b/srv/http/assets/js/camilla.js index bc384da9c..dd6b113d1 100644 --- a/srv/http/assets/js/camilla.js +++ b/srv/http/assets/js/camilla.js @@ -722,7 +722,7 @@ var graph = { } var render = { status : () => { // onload only - playbackButton(); + headIcon.player(); if ( S.volume !== false ) { $( '#divvolume' ).removeClass( 'hide' ); $( '#divvolume .control' ).text( S.control ); diff --git a/srv/http/assets/js/player.js b/srv/http/assets/js/player.js index 7640584e0..b8d68b838 100644 --- a/srv/http/assets/js/player.js +++ b/srv/http/assets/js/player.js @@ -349,7 +349,7 @@ var util = { } function renderPage() { - playbackButton(); + headIcon.player(); util.statusSet(); if ( S.bluetooth ) { $( '#btreceiver' ).html( '' ); diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 298d37dc4..e7741493f 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -5,50 +5,41 @@ Naming must be the same for: bash - cmd=NAME, save to NAME.conf */ W.refresh = data => { - if ( data.page !== page ) return - - clearTimeout( V.debounce ); - V.debounce = setTimeout( () => { - $.each( data, ( k, v ) => { S[ k ] = v } ); // need braces - if ( page === 'networks' ) { - if ( $( '#divinterface' ).hasClass( 'hide' ) ) $( '.back' ).trigger( 'click' ); - } else { - switchSet(); - } - renderPage(); - }, 300 ); - } + if ( data.page !== page ) return + + clearTimeout( V.debounce ); + V.debounce = setTimeout( () => { + $.each( data, ( k, v ) => { S[ k ] = v } ); // need braces + if ( page === 'networks' ) { + if ( $( '#divinterface' ).hasClass( 'hide' ) ) $( '.back' ).trigger( 'click' ); + } else { + switchSet(); + } + renderPage(); + }, 300 ); } if ( [ 'camilla', 'player' ].includes( page ) ) { W = { ...W // from common.js - , mpdplayer : data => playbackButton( data ) - , mpdradio : data => playbackButton( data ) - , player : data => { - var player_id = { - airplay : 'shairport-sync' - , bluetooth : 'bluetooth' - , snapcast : 'snapserver' - , spotify : 'spotifyd' - , upnp : 'upmpdcli' - } - $( '#'+ player_id[ data.player ] ).toggleClass( 'disabled', data.active ); - } + , mpdplayer : data => headIcon.player( data ) + , mpdradio : data => headIcon.player( data ) } - function playbackButton( data ) { - if ( data ) [ 'player', 'state' ].forEach( k => S[ k ] = data[ k ] ); - if ( S.pllength ) { - var btn = S.state === 'play' ? 'pause' : 'play'; - } else { - var btn = 'play disabled'; + var headIcon = { + control : () => { + $( '.playback' ).prop( 'class', 'playback i-'+ ( S.state === 'play' ? 'pause' : 'play' ) ); + } + , player : data => { + if ( ! data ) return + + [ 'player', 'state' ].forEach( k => S[ k ] = data[ k ] ); + $( 'heading .icon' ).prop( 'class', 'icon i-'+ S.player ); + headIcon.control(); } - $( '.playback' ).prop( 'class', 'playback i-'+ btn ); } $( '.playback' ).on( 'click', function() { // for player and camilla - S.state = S.state === 'play' ? 'pause' : 'play'; + headIcon.control(); if ( page === 'camilla' && S.state === 'pause' ) render.statusStop(); - playbackButton(); - bash( [ 'cmd.sh', 'mpcplayback' ] ); + bash( [ 'cmd.sh', S.player === 'mpd' ? 'mpcplayback' : 'playerstop' ] ); } ); } diff --git a/srv/http/bash/cmd.sh b/srv/http/bash/cmd.sh index 4412b582f..047297ade 100644 --- a/srv/http/bash/cmd.sh +++ b/srv/http/bash/cmd.sh @@ -68,7 +68,6 @@ playerStart() { renice -n -19 -p $pid &> /dev/null done fi - pushData player '{ "player": "'$player'", "active": true }' } playerStop() { local player @@ -101,7 +100,6 @@ playerStop() { $dirbash/status-push.sh ;; esac - [[ $player != mpd ]] && pushData player '{ "player": "'$player'", "active": false }' } plClear() { mpc -q clear From 3e18da4da61924763ff1c477c2bfb070c316c5aa Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 14:54:15 +0700 Subject: [PATCH 24/88] u --- srv/http/assets/css/common.css | 21 +++++++++++---------- srv/http/assets/js/settings.js | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 77ecc232d..b559b69d1 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -468,6 +468,17 @@ code { font-size: 13px; } +input[ type=checkbox ], +input[ type=radio ], +input[ type=range ], +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button, +input[ type=range ]::-webkit-slider-thumb { + appearance: none; +} +input[ type=number ] { + appearance: textfield; +} input[ type=range ] { --track: linear-gradient( 90deg, transparent 10px, #000 10px, #000 calc( 100% - 10px ), transparent 10px ) !important; --trackborder : 1px solid var( --cgd ) !important; @@ -476,7 +487,6 @@ input[ type=range ] { margin: 0; max-width: 70%; background: transparent; - -webkit-appearance: none; } input[ type=range ]::-webkit-slider-thumb { height: 40px; @@ -486,7 +496,6 @@ input[ type=range ]::-webkit-slider-thumb { border-radius: 4px; background: var( --glossy-btn ); background-color: var( --cm ); - -webkit-appearance: none; box-shadow: var( --shadow-btn ); } input[ type=range ]::-moz-range-thumb { /* cannot be combined */ @@ -908,13 +917,6 @@ input[ type=number ]:disabled { border: 1px solid var( --cgl ); opacity: 1; } -input::-webkit-outer-spin-button, -input::-webkit-inner-spin-button { - -webkit-appearance: none; -} -input[ type=number ] { - -moz-appearance:textfield; -} #infoPasswordBox { margin-top: 0 !important; outline: none; @@ -926,7 +928,6 @@ input[ type=number ] { } input[ type=radio ], input[ type=checkbox ] { - -webkit-appearance: none; width: 24px; height: 24px; margin: 3px 6px 3px 1px; diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index e7741493f..7bf715350 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -18,7 +18,7 @@ W.refresh = data => { renderPage(); }, 300 ); } -if ( [ 'camilla', 'player' ].includes( page ) ) { +if ( $( 'heading .playback' ).length ) { W = { ...W // from common.js , mpdplayer : data => headIcon.player( data ) From b894c8d6316fcbebc6ecdec98da2b6cd70f87cb0 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 15:18:50 +0700 Subject: [PATCH 25/88] Update startup.sh --- srv/http/bash/startup.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/srv/http/bash/startup.sh b/srv/http/bash/startup.sh index aefef08ae..241e24cf4 100644 --- a/srv/http/bash/startup.sh +++ b/srv/http/bash/startup.sh @@ -72,7 +72,6 @@ fi mkdir -p $dirshm/{airplay,embedded,spotify,local,online,sampling,webradio} chmod -R 777 $dirshm chown -R http:http $dirshm -echo 'state="stop"' > $dirshm/status echo mpd > $dirshm/player lsmod | grep -q -m1 brcmfmac && touch $dirshm/onboardwlan # initial status From 35fb9d31e06e80dd6896bfa124c2797ce13904a7 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 15:23:28 +0700 Subject: [PATCH 26/88] Update status-radio.sh --- srv/http/bash/status-radio.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/srv/http/bash/status-radio.sh b/srv/http/bash/status-radio.sh index b4aff2a98..a1a2dcafa 100644 --- a/srv/http/bash/status-radio.sh +++ b/srv/http/bash/status-radio.sh @@ -134,14 +134,12 @@ $( jq -r .albumTitle <<< $track )" fi fi [[ -e $coverfile ]] && coverart=${coverfile:9} || coverart= - grep -q radioelapsed.*false $dirsystem/display.json && elapsed=false || elapsed=$( mpcElapsed ) - pllength=$( mpc status %length% ) data=' "player" : "mpd" , "Album" : "'$album'" , "Artist" : "'$artist'" -, "elapsed" : '$elapsed' -, "pllength" : '$pllength' +, "elapsed" : '$( mpcElapsed webradio )' +, "pllength" : '$( mpc status %length% )' , "state" : "play" , "Title" : "'$title'"' if [[ $coverart ]]; then From f89c8a4a21f091a0239a66dfbdc789a55f01fcff Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 17:34:52 +0700 Subject: [PATCH 27/88] u --- srv/http/assets/css/common.css | 5 +++-- srv/http/bash/settings/data-config.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index b559b69d1..62f1ca8fb 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -10,7 +10,7 @@ @font-face { font-family : rern; - src : url( '/assets/fonts/rern.woff2?v=1735435369' ); + src : url( '/assets/fonts/rern.woff2?v=1735640240' ); } @font-face { font-family : Lato; @@ -582,7 +582,8 @@ input[ type=checkbox ] { .infobtn-default { background-color: var( --cg ); } -.disabled { +.disabled, +.disabled i { color: var( --cg60 ) !important; pointer-events: none; } diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index f4e361529..1b35ec812 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -67,7 +67,7 @@ lcdchar ) val='{ "INF": "gpio", "COLS": 20, "CHARMAP": "A00"' if [[ $2 == gpio ]]; then [[ $current != gpio ]] && values=$val', "P0": 21, "PIN_RS": 15, "P1": 22, "PIN_RW": 18, "P2": 23, "PIN_E": 16, "P3": 24' - elif [[ $2 == i2c ]]; then + else [[ $current != i2c ]] && values=${val/gpio/i2c}', "ADDRESS": 39, "CHIP": "PCF8574"' fi ! grep -q BACKLIGHT <<< $values && values+=', "BACKLIGHT": false }' From a287117a82f7e58f2aacffbe5cafb310b6956f22 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 17:48:36 +0700 Subject: [PATCH 28/88] Update system.js --- srv/http/assets/js/system.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 6d331644e..adce29377 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -378,13 +378,14 @@ var util = { icon : 'lcdchar' , title : 'Character LCD' , tablabel : [ 'I²C', 'GPIO' ] - , footer : ''+ ico( 'raudio' ) +'Logo'+ ico( 'screenoff' ) +'Sleep' + , footer : '' + +''+ ico( 'screenoff' ) +'Sleep' , beforeshow : () => { $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); $( '.infofooter span' ) .toggleClass( 'disabled', ! S.lcdchar ) .on( 'click', function() { - bash( [ 'lcdchar', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); + bash( [ 'lcdchar', $( this ).prop( 'class' ), 'CMD ACTION' ] ); } ); } , cancel : switchCancel From 0493ca257f406c651b2fa1dec63b47e513f07bf6 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 20:24:59 +0700 Subject: [PATCH 29/88] u --- srv/http/assets/js/system.js | 30 +++++++++++++-------------- srv/http/bash/settings/data-config.sh | 10 ++------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index adce29377..42d3e3861 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -131,9 +131,7 @@ var config = { , lcdchar : data => { util.lcdchar[ data.values.INF ]( data ); } - , mpdoled : data => { - var values = data.values; - var buttonlogo = S.mpdoled && ! data.reboot; + , mpdoled : values => { var chip = { 'SSD130x SP' : 1 , 'SSD130x I²C' : 3 @@ -147,7 +145,7 @@ var config = { [ 'Controller', 'select', chip ] , [ 'Refresh (baud)', 'select', { kv: { '800,000': 800000, '1,000,000': 1000000, '1,200,000': 1200000 } } ] ] - , footer : ico( 'raudio' ) +'Logo' + , footer : ''+ ico( 'raudio' ) +'Logo' , values : values , checkchanged : S.mpdoled , boxwidth : 140 @@ -155,7 +153,11 @@ var config = { var $tr = $( '#infoList tr' ); var $baud = $tr.eq( 1 ) $baud.toggleClass( 'hide', S.mpdoled && ( values.CHIP < 3 || values.CHIP > 6 ) ); - $( '.infofooter i' ).toggleClass( 'disabled', ! S.mpdoled || data.reboot ) + $( '.infofooter span' ) + .toggleClass( 'disabled', ! S.mpdoled ) + .on( 'click', function() { + bash( [ 'mpdoledlogo' ] ); + } ); $tr.eq( 0 ).on( 'input', function() { var val = this.value; $baud.toggleClass( 'hide', val < 3 || val > 6 ); @@ -207,7 +209,7 @@ var config = { } ); } , timezone : () => util.server.ntp() - , tft : data => { + , tft : values => { var type = { 'Generic' : 'tft35a' , 'Waveshare (A)' : 'waveshare35a' @@ -215,23 +217,19 @@ var config = { , 'Waveshare (B) Rev 2.0' : 'waveshare35b-v2' , 'Waveshare (C)' : 'waveshare35c' } - var buttoncalibrate = S.tft && ! data.reboot; info( { ...SW , list : [ 'Type', 'select', type ] - , values : data.values + , footer : ''+ ico( 'cursor' ) +'Calibrate' + , values : values , checkchanged : S.tft , boxwidth : 190 - , buttonlabel : ! buttoncalibrate ? '' : 'Calibrate' - , button : ! buttoncalibrate ? '' : () => { - info( { - ...SW - , message : 'Calibrate touchscreen?' - +'
(Get stylus ready.)' - , ok : () => { + , beforeshow : () => { + $( '.infofooter span' ) + .toggleClass( 'disabled', ! S.tft ) + .on( 'click', function() { notify( SW.icon, 'Calibrate Touchscreen', 'Start ...' ); bash( [ 'tftcalibrate' ] ); - } } ); } , cancel : switchCancel diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 1b35ec812..2f9e09310 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -99,10 +99,7 @@ mpdoled ) chip=$( grep mpd_oled /etc/systemd/system/mpd_oled.service | cut -d' ' -f3 ) baud=$( grep baudrate /boot/config.txt | cut -d= -f3 ) [[ ! $baud ]] && baud=800000 - echo '{ - "values" : { "CHIP": "'$chip'", "BAUD": '$baud' } -, "reboot" : '$( toReboot )' -}' + echo '{ "values" : { "CHIP": "'$chip'", "BAUD": '$baud' } }' ;; packagelist ) filepackages=/tmp/packages @@ -249,10 +246,7 @@ spotifyoutput ) ;; tft ) model=$( sed -n -E '/rotate=/ {s/dtoverlay=(.*):rotate.*/\1/; p}' /boot/config.txt ) - echo '{ - "values" : { "MODEL": "'$( [[ $model ]] && echo $model || echo tft35a )'" } -, "reboot" : '$( toReboot )' -}' + echo '{ "values" : { "MODEL": "'$( [[ $model ]] && echo $model || echo tft35a )'" } }' ;; wlan ) echo '{ From c83bdde735d01a63ed66c801e9654296f16d5d99 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 31 Dec 2024 20:28:17 +0700 Subject: [PATCH 30/88] Update data-config.sh --- srv/http/bash/settings/data-config.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 2f9e09310..42b17954d 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -99,7 +99,7 @@ mpdoled ) chip=$( grep mpd_oled /etc/systemd/system/mpd_oled.service | cut -d' ' -f3 ) baud=$( grep baudrate /boot/config.txt | cut -d= -f3 ) [[ ! $baud ]] && baud=800000 - echo '{ "values" : { "CHIP": "'$chip'", "BAUD": '$baud' } }' + echo '{ "CHIP": "'$chip'", "BAUD": '$baud' }' ;; packagelist ) filepackages=/tmp/packages @@ -246,7 +246,7 @@ spotifyoutput ) ;; tft ) model=$( sed -n -E '/rotate=/ {s/dtoverlay=(.*):rotate.*/\1/; p}' /boot/config.txt ) - echo '{ "values" : { "MODEL": "'$( [[ $model ]] && echo $model || echo tft35a )'" } }' + echo '{ "MODEL": "'$( [[ $model ]] && echo $model || echo tft35a )'" }' ;; wlan ) echo '{ From f0d46aafe3e51b7b9d76b6da4cf246b908ecd5d9 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 07:44:28 +0700 Subject: [PATCH 31/88] u --- srv/http/assets/js/system.js | 4 +++- srv/http/bash/settings/system.sh | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 42d3e3861..e67a795db 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -1,4 +1,6 @@ -W.reboot = () => banner( SW.icon, SW.title, 'Reboot required', 5000 ); +W.reboot = id => { + banner( id, $( '#div'+ id +' .col-l .label' ).text(), 'Reboot required', 5000 ); +} W.storage = data => { clearTimeout( V.debounce ); V.debounce = setTimeout( () => { diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 985f9790f..a8b5a383c 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -67,7 +67,7 @@ dtoverlay=gpio-shutdown,gpio_pin=17,active_low=0,gpio_pull=down" fi fi if [[ $reboot ]]; then - pushData reboot 1 + pushData reboot $CMD appendSortUnique $CMD $dirshm/reboot else sed -i "/$CMD/ d" $dirshm/reboot @@ -254,12 +254,10 @@ mpdoled ) sed -i 's/-o ./-o '$CHIP'/' /etc/systemd/system/mpd_oled.service systemctl daemon-reload fi - else - $dirsettings/player-conf.sh fi i2cset=1 configTxt - [[ -e $dirsystem/mpdoled && ! -e $dirshm/reboot && ! -e $dirmpdconf/fifo.conf ]] && $dirsettings/player-conf.sh + $dirsettings/player-conf.sh ;; ntp ) file=/etc/systemd/timesyncd.conf From 7b27cc5f898b833087d997a3197c882486ead5a2 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 09:00:33 +0700 Subject: [PATCH 32/88] Update system.sh --- srv/http/bash/settings/system.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index a8b5a383c..23e814a5f 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -246,6 +246,10 @@ mpdoledlogo ) systemctl stop mpd_oled type=$( grep mpd_oled /etc/systemd/system/mpd_oled.service | cut -d' ' -f3 ) mpd_oled -o $type -L + sleep 10 + systemctl start mpd_oled + sleep 1 + systemctl stop mpd_oled ;; mpdoled ) enableFlagSet From 1ece692aacccab8bcaff99676cb6fb37b30e1343 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 10:17:04 +0700 Subject: [PATCH 33/88] u --- srv/http/assets/js/system.js | 3 ++- srv/http/bash/settings/system.sh | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index e67a795db..52517d179 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -158,7 +158,8 @@ var config = { $( '.infofooter span' ) .toggleClass( 'disabled', ! S.mpdoled ) .on( 'click', function() { - bash( [ 'mpdoledlogo' ] ); + bash( [ 'mpdoled', true, 'CMD LOGO' ] ); + $( '#infoX' ).trigger( 'click' ); } ); $tr.eq( 0 ).on( 'input', function() { var val = this.value; diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 23e814a5f..aa696204f 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -242,22 +242,26 @@ mountunmount ) fi pushRefresh ;; -mpdoledlogo ) - systemctl stop mpd_oled - type=$( grep mpd_oled /etc/systemd/system/mpd_oled.service | cut -d' ' -f3 ) - mpd_oled -o $type -L - sleep 10 - systemctl start mpd_oled - sleep 1 - systemctl stop mpd_oled - ;; mpdoled ) + systemctl stop mpd_oled + chip=$( awk '/^ExecStart/ {print $3}' /etc/systemd/system/mpd_oled.service ) + mpd_oled -o $chip -L + ( + [[ $ON ]] && sleep 10 + systemctl start mpd_oled + sleep 0.5 + systemctl stop mpd_oled + ) & + [[ $LOGO ]] && exit +# -------------------------------------------------------------------- enableFlagSet if [[ $ON ]]; then - if [[ $( grep mpd_oled /etc/systemd/system/mpd_oled.service | cut -d' ' -f3 ) != $CHIP ]]; then + if [[ $chip != $CHIP ]]; then sed -i 's/-o ./-o '$CHIP'/' /etc/systemd/system/mpd_oled.service systemctl daemon-reload fi + else + systemctl stop mpd_oled fi i2cset=1 configTxt From 26609320d5bb3697da6cdbda6ac387fdb65b043a Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 10:19:45 +0700 Subject: [PATCH 34/88] Update system.sh --- srv/http/bash/settings/system.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index aa696204f..a57f6f158 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -260,8 +260,6 @@ mpdoled ) sed -i 's/-o ./-o '$CHIP'/' /etc/systemd/system/mpd_oled.service systemctl daemon-reload fi - else - systemctl stop mpd_oled fi i2cset=1 configTxt From e0b2c07603425b683aa870886a802ef52a0d9406 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 11:14:12 +0700 Subject: [PATCH 35/88] u --- srv/http/assets/css/common.css | 2 +- srv/http/assets/css/hovercursor.css | 5 +++-- srv/http/assets/js/settings.js | 10 ++++++---- srv/http/bash/settings/camilla-data.sh | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 62f1ca8fb..ab69b55be 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -586,6 +586,7 @@ input[ type=checkbox ] { .disabled i { color: var( --cg60 ) !important; pointer-events: none; + cursor: default; } .infobtn.disabled { background-color: var( --cgd ) !important; @@ -594,7 +595,6 @@ input[ type=checkbox ] { } #infoOk.disabled { pointer-events: auto; - cursor: default; } input[ type=checkbox ].disabled { pointer-events: auto; diff --git a/srv/http/assets/css/hovercursor.css b/srv/http/assets/css/hovercursor.css index 30f94ab9a..20cb5514e 100644 --- a/srv/http/assets/css/hovercursor.css +++ b/srv/http/assets/css/hovercursor.css @@ -144,8 +144,9 @@ li:not( .licover ), #volume-text { cursor: pointer; } -#lib-title a:last-of-type:hover, -.mode.nodata * { +.disabled, +.mode.nodata *, +#lib-title a:last-of-type:hover { cursor: default; } #lib-title a:last-of-type:hover { diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 7bf715350..ba684dc15 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -26,12 +26,14 @@ if ( $( 'heading .playback' ).length ) { } var headIcon = { control : () => { - $( '.playback' ).prop( 'class', 'playback i-'+ ( S.state === 'play' ? 'pause' : 'play' ) ); + $( '.playback' ) + .prop( 'class', 'playback i-'+ ( S.state === 'play' ? 'pause' : 'play' ) ) + .toggleClass( 'disabled', page === 'player' && S.player !== 'mpd' ); + } , player : data => { - if ( ! data ) return - - [ 'player', 'state' ].forEach( k => S[ k ] = data[ k ] ); + if ( ! data ) data = { player: S.player, state: S.state }; + [ 'player', 'state' ].forEach( k => { S[ k ] = data[ k ] } ); $( 'heading .icon' ).prop( 'class', 'icon i-'+ S.player ); headIcon.control(); } diff --git a/srv/http/bash/settings/camilla-data.sh b/srv/http/bash/settings/camilla-data.sh index b7546c3c2..3c361a2da 100644 --- a/srv/http/bash/settings/camilla-data.sh +++ b/srv/http/bash/settings/camilla-data.sh @@ -18,7 +18,7 @@ data=' , "devices" : '$( < $dirshm/hwparams )' , "player" : "'$( < $dirshm/player )'" , "pllength" : '$( mpc status %length% )' -, "state" : "'$( mpcState )'" +, "state" : "'$( getVar state $dirshm/status )'" , "volume" : '$( [[ $mixer ]] && volumeGet )' , "volumemax" : '$( volumeMaxGet )' , "volumemute" : '$( getContent $dirsystem/volumemute 0 ) From 184111d8e3f07c07433fe051f26a7289118a7ae6 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 11:32:07 +0700 Subject: [PATCH 36/88] Update system.php --- srv/http/settings/system.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/srv/http/settings/system.php b/srv/http/settings/system.php index e6a0e828e..d78b038b4 100644 --- a/srv/http/settings/system.php +++ b/srv/http/settings/system.php @@ -10,11 +10,13 @@ commonVariables( [ 'buttons' => [ 'add', 'gear', 'microsd', 'networks', 'power', 'refresh', 'rserver', 'usbdrive' ] , 'labels' => [ - 'Bluetooth' => 'bluetooth' + 'Airplay' => 'airplay' + , 'Bluetooth' => 'bluetooth' , 'Device' => '' , 'Output' => '' , 'Server rAudio' => 'rserver' , 'Shared Data' => 'networks' + , 'Spotify' => 'spotify' , 'Storage' => '' ] , 'menus' => [ @@ -202,7 +204,11 @@ 'id' => 'mpdoled' , 'label' => 'Spectrum OLED' , 'sub' => 'mpd_oled' - , 'help' => 'OLED module - display audio level spectrum' + , 'help' => <<OLED module - display audio level spectrum + +Note: Not run with $L->airplay $L->spotify +EOF ] , [ 'id' => 'tft' From b8b3bd9dbb7875534fe58bd244fcd649261bbeba Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 13:00:16 +0700 Subject: [PATCH 37/88] Update system.php --- srv/http/settings/system.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/settings/system.php b/srv/http/settings/system.php index d78b038b4..c1134aeab 100644 --- a/srv/http/settings/system.php +++ b/srv/http/settings/system.php @@ -207,7 +207,7 @@ , 'help' => <<OLED module - display audio level spectrum -Note: Not run with $L->airplay $L->spotify +Note: Not yet support $L->airplay $L->spotify EOF ] , [ From 25083816a3f6a8cac8682054440b5fb7c61d602d Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 13:18:14 +0700 Subject: [PATCH 38/88] Update settings.css --- srv/http/assets/css/settings.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/srv/http/assets/css/settings.css b/srv/http/assets/css/settings.css index decb1da45..b8b5ea792 100644 --- a/srv/http/assets/css/settings.css +++ b/srv/http/assets/css/settings.css @@ -200,8 +200,6 @@ heading { font-size: 24px; font-weight: 300; border-bottom: 1px solid var( --cg ); -} -heading { letter-spacing: 5px; } heading.subhead { From f8882c11e2d476a94c08e0ff04ec1440771f7ff4 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 15:44:43 +0700 Subject: [PATCH 39/88] u --- srv/http/assets/js/camilla.js | 2 +- srv/http/assets/js/player.js | 2 +- srv/http/assets/js/settings.js | 30 ++++++++++++------------------ srv/http/settings/camilla.php | 2 +- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/srv/http/assets/js/camilla.js b/srv/http/assets/js/camilla.js index dd6b113d1..dac41a61e 100644 --- a/srv/http/assets/js/camilla.js +++ b/srv/http/assets/js/camilla.js @@ -722,7 +722,7 @@ var graph = { } var render = { status : () => { // onload only - headIcon.player(); + headIcon(); if ( S.volume !== false ) { $( '#divvolume' ).removeClass( 'hide' ); $( '#divvolume .control' ).text( S.control ); diff --git a/srv/http/assets/js/player.js b/srv/http/assets/js/player.js index b8d68b838..fc62a6a7f 100644 --- a/srv/http/assets/js/player.js +++ b/srv/http/assets/js/player.js @@ -349,7 +349,7 @@ var util = { } function renderPage() { - headIcon.player(); + headIcon(); util.statusSet(); if ( S.bluetooth ) { $( '#btreceiver' ).html( '' ); diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index ba684dc15..6153fe947 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -18,28 +18,22 @@ W.refresh = data => { renderPage(); }, 300 ); } -if ( $( 'heading .playback' ).length ) { +if ( $( 'heading .playback' ).length ) { // for player and camilla W = { ...W // from common.js - , mpdplayer : data => headIcon.player( data ) - , mpdradio : data => headIcon.player( data ) + , mpdplayer : data => headIcon( data ) + , mpdradio : data => headIcon( data ) } - var headIcon = { - control : () => { - $( '.playback' ) - .prop( 'class', 'playback i-'+ ( S.state === 'play' ? 'pause' : 'play' ) ) - .toggleClass( 'disabled', page === 'player' && S.player !== 'mpd' ); - - } - , player : data => { - if ( ! data ) data = { player: S.player, state: S.state }; - [ 'player', 'state' ].forEach( k => { S[ k ] = data[ k ] } ); - $( 'heading .icon' ).prop( 'class', 'icon i-'+ S.player ); - headIcon.control(); - } + function headIcon( data ) { + if ( data ) [ 'player', 'state' ].forEach( k => { S[ k ] = data[ k ] } ); + $( 'heading .player' ).prop( 'class', 'player i-'+ S.player ); + $( '.playback' ) + .prop( 'class', 'playback i-'+ ( S.state === 'play' ? 'pause' : 'play' ) ) + .toggleClass( 'disabled', page === 'player' && S.player !== 'mpd' ); } - $( '.playback' ).on( 'click', function() { // for player and camilla - headIcon.control(); + $( '.playback' ).on( 'click', function() { + S.state = S.state === 'play' ? 'pause' : 'play' + headIcon(); if ( page === 'camilla' && S.state === 'pause' ) render.statusStop(); bash( [ 'cmd.sh', S.player === 'mpd' ? 'mpcplayback' : 'playerstop' ] ); } ); diff --git a/srv/http/settings/camilla.php b/srv/http/settings/camilla.php index 9f96f4337..e527aec2d 100644 --- a/srv/http/settings/camilla.php +++ b/srv/http/settings/camilla.php @@ -114,7 +114,7 @@ $head = [ 'title' => 'Status' , 'status' => 'camilladsp' - , 'button' => [ 'mpd icon', 'play playback' ] + , 'button' => [ 'mpd player', 'play playback' ] , 'help' => <<< EOF $B->play$B->pause$B->stop Playback control From 28866e61be4823c1a6f7aa7bc3b37a70a7f70c9e Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 15:59:03 +0700 Subject: [PATCH 40/88] Update settings.js --- srv/http/assets/js/settings.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 6153fe947..8bd3c4e72 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -25,11 +25,16 @@ if ( $( 'heading .playback' ).length ) { // for player and camilla , mpdradio : data => headIcon( data ) } function headIcon( data ) { - if ( data ) [ 'player', 'state' ].forEach( k => { S[ k ] = data[ k ] } ); - $( 'heading .player' ).prop( 'class', 'player i-'+ S.player ); + if ( data ) { + if ( ( ! data.player || ! data.state ) || ( data.player === S.player && data.state === S.state ) return + + S.player = data.player; + S.state = data.state; + } $( '.playback' ) .prop( 'class', 'playback i-'+ ( S.state === 'play' ? 'pause' : 'play' ) ) .toggleClass( 'disabled', page === 'player' && S.player !== 'mpd' ); + $( 'heading .player' ).prop( 'class', 'player i-'+ S.player ); } $( '.playback' ).on( 'click', function() { S.state = S.state === 'play' ? 'pause' : 'play' From 099205fbc05ebe243ffdea73098bff9af5fd2812 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 20:04:01 +0700 Subject: [PATCH 41/88] Update settings.js --- srv/http/assets/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/assets/js/settings.js b/srv/http/assets/js/settings.js index 8bd3c4e72..f8d44bee2 100644 --- a/srv/http/assets/js/settings.js +++ b/srv/http/assets/js/settings.js @@ -26,7 +26,7 @@ if ( $( 'heading .playback' ).length ) { // for player and camilla } function headIcon( data ) { if ( data ) { - if ( ( ! data.player || ! data.state ) || ( data.player === S.player && data.state === S.state ) return + if ( ( ! data.player || ! data.state ) || ( data.player === S.player && data.state === S.state ) ) return S.player = data.player; S.state = data.state; From 75de66b34414019c8c251d2556a8cf9ffcc1b17a Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 1 Jan 2025 20:10:33 +0700 Subject: [PATCH 42/88] Update common.css --- srv/http/assets/css/common.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index ab69b55be..1bcdbc05f 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -839,7 +839,8 @@ hr { vertical-align: -2px; } .infofooter span { - margin-right: 10px; + display: inline-block; + margin: 10px 10px 0 0; } .infofooter span:last-child { margin-right: 0; From 28f2f20326492f7b57fb37f2e78943ce910ecbee Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 2 Jan 2025 09:15:00 +0700 Subject: [PATCH 43/88] u --- srv/http/assets/css/common.css | 7 ++--- srv/http/assets/fonts/rern.woff2 | Bin 19672 -> 19768 bytes srv/http/assets/js/features.js | 48 ++++++++++++++++--------------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 1bcdbc05f..1495f75e3 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -10,7 +10,7 @@ @font-face { font-family : rern; - src : url( '/assets/fonts/rern.woff2?v=1735640240' ); + src : url( '/assets/fonts/rern.woff2?v=1735640241' ); } @font-face { font-family : Lato; @@ -61,6 +61,7 @@ i { .i-star::before { content: '\F550' } .i-bluealsa::before, .i-bluetooth::before, +.i-brightness::before { content: '\F55F' } .i-btreceiver::before { content: '\F51A' } .i-btsender::before { content: '\F51B' } .i-camilla::before, @@ -839,8 +840,7 @@ hr { vertical-align: -2px; } .infofooter span { - display: inline-block; - margin: 10px 10px 0 0; + margin-right: 10px; } .infofooter span:last-child { margin-right: 0; @@ -1038,7 +1038,6 @@ input[ type=radio ]:disabled { } @media ( max-width: 420px ) { #infoList { padding: 20px 5px 10px 5px } - .infoheader, .infofooter { padding: 0 5px } } @media ( max-width: 330px ) { #infoOverlay { diff --git a/srv/http/assets/fonts/rern.woff2 b/srv/http/assets/fonts/rern.woff2 index 7a0bbd181901e89cd064139d9b981962734c9064..c338d499d9b7fd283ee427d222854c045aea96d3 100644 GIT binary patch literal 19768 zcmV(@K-Rx^Pew8T0RR9108Kam4gdfE0F+<=08HTk0RR9100000000000000000000 z00006U;tbQ1_^?55eN!`mnebTJ^?lYBm;#I3xY}j1Rw>0dIum379TWpMI&;z0~o!! zUbrY~6eX1x_`gixhKPWF&@RKc#NDPNAq>DlsFVG_v-N$S8d~gWpH84&K~ID;2A{a$ zI}wPW#X*2E0)BG#1VR{0AeK;a@sd9~LSvug4$+)7rR$_dq{oKZ(=N>ymjowm;j@K4R<-#y-3iLArzl~6LgL?)JHRfX-; zXh0=8ug*8=b(2;yv}_0*0j2){w|ln}SgW*>p=Co7e`q-e1j+ZqwNH@=P2OfFS>R)q z$C}GZSBV;T-c*=B1as>~^oTKP&>I8XMvNLYR>c?$7(E6fasx&vqf$}?9d%zp-TS^~Ri1xe{)BOEru`9P3MT6XLsNG_7KMC~TEkBo`4-rXnf{i$jevR2?#OYjkPh< z9!=L!5Kc6^zif>8-+q70%8?>*fZYZ_SRL#D6aexXF#`Zzd0s!X5J1=to`+BaZ19E2 zBjB;XlK-6m;89?*31In3+(N!q7Dz}e*DVd6S_#NZD1nfl9UD=M%o(W|X&-s#u`o6! zjersL$h?uNk&edzn>2vZnDnpokMy_HiBSC}0t4!+8$P)Y2)3d<5WeB)gJUmGpLCyo zAOJjTX2hHTh8qkSHR-*uWEdzMG{TH8!zn*&FAlWk7Wq32?YoubY;VPe>QZMf3Cxq^ z1QqR$XAHd{uc+qP*j{ApO?G&(WfcxbLPQ@RSWSer52)5_QJQK==l>8b8a`PY#6h;A zoTA>Abg$mzbcdJGXvpY2ZUfQrgwf$(E@s{mf9c8^z2BG{EUd=`B$hW>a$g1!C5YhFPU^)yU^ zS`kl|d!^A*F7Y_3)6|r*00{+C4f>+-JiT*CG_jOgQ%-F|%pVFl+A?t8VjN>Nx3^M zvRb%Rol*x=fa*W-zg077*?=M0_9*wM-_ASC@|S(o@;#BU>;y+ggFTa=6-9}W1(UJ# z24cZwPlKq%hM~>!jnQzv*0E~r?7mh<=n2}AHkuHvUtLK}L4m2oSwBl~bZq|sa~wEX zYH&+57pWKPCj-yVcnvs#dxk;Y1vcMsD&z?6&RP=ii z8nP)vTCtXrNhjCm(Q>_Jz~TO)-U8Bh%tQMp=UyK4rmmZ&Lfdv5DNC9*Ha4_V4n&7> zxl#F53A-5Gx;wCi3ZZ#|Iu`xh=s!DD)r8jLeeUDZ7zCf(-_pjy z*8OQiZ*5j{L{f$bW{_iwcp9Yy2y*IxGiAa`ZilpP%0u-+ZY{}d$EMt{RZ>z*jfqm* z(A^GwM-Pr&ZGhI!!#a2QEF8Xr+TTHtVw#6CM=7E7t3a)2sZgm%p#Z`~T14;0M?nDO z5xzUeHmLSPvi?~FSntEEmP>ML!$^awIZQWXpiA;vE?%}~h((}a!4r)ph>%am<}BrH z2rOjQ5qT28D;J$iIxx%}n2_UOqV{(RnKV;Ht~+V3V8x17u2GD5=<}l%QrYpG)?aR* z#c9ID1yAFXEfnSoz$8hH*%tc?dTw(Y$63v}2Owe}tHoW%Lu6_ZeT)GH!zaq8n4uJO z9#4eK>eQ$&4z+B_v5DsIqVT%^-S!iRUv*mG0XPHpCOsX{w|A$M&eq1;y6D;NcIReC zk9)hT&9TwisiPV-Tm3K_=&Y~Xy@h`c#F2j2Rk*o|uBz&@fd%aZ-HMklD-n~-$Bf)?m8#2(WK zEJy~3BYoFdfct^V9D-2-7g{?_8`6P5LO-E`NN>}|ZaPi{$_-6srtu-!)#(_px2-da z@?U6aT|8cn#O*Rn%e!v=o_@|_k+S8$WtIl4e}Mj#^MbM%uV z9C0`F%9#p<`P~8Ram;~X9h~q&W*pRaRpC|;$7}*zRZx*4vEI>`#rE>0t1a#8MI}AJ z>_r?pM!3!4b6edgkhy}0uXH>|6m!ThL55t{l`Q*cZRjJ5P&-ig-utm*ZPo1;FQhi< z-BPbgH;Tvq8jQ6EZI*Bw5(SfI&ll@kpAoI2wL^WQmJNLpNczE0xqd4smhTuI6? z-wnD^{fJKe>`5xk)E-Qdj|(Sl_9qr|Y--mQvzVF}=*KnofNGlY5iNCEiOAQ|JF=kf z;C9H_$?$h;MQ;ym*hWL7Mr}%0#KX1rwc0N_N>*-X|FB`IZK3}CpbpyKO($ulYWCmG z{@2-m`jCIO@B)EYoa@LJ&09ByWKi6ZESf*f=9`B(3R{NO2c{wI(HMr3j%3m7^+OPZ zB^~*qq3MFG8|Nx?IocHEYxivj3~<9*)7e5d2bA^aP;Y5p=|=?P0xG;i@Z@LT!rz2+ zFqPUZgay8Jkxyr2e7#n}JVU4y`19FHe#IcnW%eOR;Mq5l*MJLWFww$k;42sZXlmwn z8zf9JZIuGQ)#msbW@a;LLJdx%rW$81+fPX%TTs<9V3;9ubD~aG9kwx}28i@(%|s;h zDT%@(0Z&F}F9%AUr21TUjOJui;N2!f_K*1+2&?I5)<0KWt!6ze)JI$$QHObxXd-q* zKY%oKovci9439P8H-x?=FygO!^-s-gfvYL#rTQS)*h3(_#_~h4?8mW6&)h+Qse)p6 z$s~Xpz+Md!dU-hS1_DUnV-8woA!I}LMQOEDDF}Pg@f4_Sj>djECc8SBT5+3RRw}4(T*dzqRWnQF0h+aPLw-BR?UVp zOk%8x!NXLh5sZ4G=o+R^MwieR*s=&^zQF-7fReU}&5#eBY+;@m2P9u8TCWHUXhK02 z7+^FBxCu?0;=9^Lw516(j-lAqUFHn%L(q@@voGQl2<;h4 z6t1OKjslgUghGTOqynfSb+x2;cZU=^C_X*|hvYQuIj$a-pHf<@*tm9Lk?KJ z($Nk>3Ppnq9kg{pKn3oI@@pVW%Zw9P_=KcByJ{i48%Ook(jAXhB$>Ua7H)#(Dzha+#+hnnDugr?Uoy$b8##MIt21hnzu?bgW#d&M1?uA>)FSSyy+ z1H89aRp6jQ987xdskv!5=VEGD>;m-4deOQ>H#yk4R0ix3Zzj;5&}ge{c=BbYI77)G zy?*UOG|bCKrK$pLyAB)3V$2Q3kvvz?W{|gKa~@#xRNH_>W_b3mB)oJ3FrlEjQ}eq3 z-jP9MHCQqp2QxB9N4a#`QX0lpy}-`W@b`pjNw%CfmKPhD`=XGdfNaLkInp>PApA{x zi%PY6*|#|IqkWABcH&RrkS07%F0{p=^t;@-Tkkyi0iT%9Y`=qwMyMW$q7Vk22)^K% zlOfN3GJ6C7)22GF3i{{hxu<{>Qs$-PqmgCbjuoJ8Et-|-d;Ayg;6}V1@V@(+P0%|K zm^&>E8q5p5!kAgKNRj&EB7TkfYny1mZBh&Ve zTJG3!l19dA#ieNog63;%?ns5=*gDyeYG2R`JjEO&d)xkfUn$+>~X(@ff5-=QiX z`8o&S?&jqQfsX1$KT`|2BNBuC{#7gmMd zNTzlz=3_swVQ5*eeF;V+Fn6C2Ef_gO{%c1Xg^nFfHXb~WUvMct2?J3G zoBotZc(IBMKPDU!(&`jQHXpI=l$q_Z>i~j^!DJuyFfQZsOI(ZG$T5+RsL!xUU*FKC zvoBPvzguJhtkA!-*omQ`zx-U2sRyRR!fMT+p5i#v6CadeG4EHUrXf)n#|mOXi;fIy zUa2WS+p9a&gEWobohLdMmu3Igh^BkJ7QMNAmL?bMiM%Uvbe|>_lCX~voKFda49&aC z_-00pp^i116aiRr0o3rNroqZDmP@a`;b)>XlHxLZgq30vsQ>}Mt&pXOtGKc$nR?oy zOQKsN)11_RSkZ~6TPVV#d$xa2NqNn<^qXaYG0uW1_M&=CS5$dWdapnI*Zq1K6T@9N zGyh05ai~pWJl`881u{SRpD7o6>oNaEkPG2 zWL$k2rn)u8SOP|`+GnGf0+n&Df~4mM8ewq{4F*sWtkZ7wMTKVk9Iz zMd<$n3d_c@8ar1(@`-uQ^sW7rc@jm_Vg%=raCue&7+en3BZ$a_Ok4|N0f1R&zn-w17V zW2#FeB+yAfHHIlPZZ^?VE8Y_r=lm$L+-f`IgU~Vc*}~!*7LxgxkKXL}1n{ATG!M3+ zif+?Va}6U8&&wbyhDMUzFScCBvZ;as0XsBrBOLRK@Iqma5f|V&;;-Z=dM;@AmV9>M z27L4?40l+omYun(L`aV2$*%`1M^@U|f_=J~V1X9)siK-hwghCnxS@v9j1*UrVr6|$ zIu+5`GB(X^WVM0aB@{pMWz*HlVwd3b*Ul#q6e6AB;)W*H)g5G}2%>kwP+KN#Vj&L= zo@hC^^`Z^6Glo_d(>_%kimu~=7qO9)31dKSH3jV%YHKG&zP>_;Xuz(}Hsa)i%Fnz* zUiTbcUb=DV>E&dn(#us}BLkZ(d1z-m;s4KQ{`uruD7MBeY%ccJSSp$i^K1i9t~N zhT>dneoyK>VYLU()h+M$X9p);jm)=7w zT?YrCogaA+$4SY-`!r+y;a|p|+;F7wWruzqcWmv!;UU(?;=DN8`Nt=uIILq{Mk|x} z=D}9&zNusG7H4`JD{HkvJv~J2IdM)IIptKLjx4C0&1@5iXKGDMttUP`aEUNnHxI095Dqt%oEXs?#w75~5?N4x^r$k2r z;*@EDIz*)c2+wEqEpvKm`^`#CQ|e&uWRDYm8{@=WRX-P!RBoeV_Qi%T$69*k-MUZn z`rI<_*MFW*R`&A}M#bztTJ`5 zf2@gP9vj2=m$aDSF|SG+waj-n`&?3G>S2{|q|VF>$(A0ot*3Uzly+7b?u_@?_KepAJ>Dd3 z0?*DA>(LfuwUUCc7V&zk{G`}}71X043@k=j)U77H$>a4}WLvvnC+xoNv}rwA!VK+W zh)=PEyXFvFN4;|>UgIh2q6XHbAD0!UB%w7jk*6}sr>4kcO68S$rSAMu0M%%dh#Kui zT+~?Qn({xX0o7X+aKrSH(uwUI6SeOdpI`?dgB+eB!m&YR0R_mMVV3jfgdhc{FYXXW z+sDv<6Ect$g*x2PHg8m`H_98u?lxRPQ{%Y#I76;e6tnAg>1NN&s6z~;$n+o3fRud^ zYrhfw?8O3|jdw|$G77wSP=m)F?h>GkK$04ChR#SPW00<@P!iPfodbBl!WF8*PCwxE zfrx}RPSGTSHygX%|9Kd4)C+KCrEIX&WB5=vFv)xbCqrkQ(kp=@bd`j zGe|7K#UwEGO-2hh>P|#YyDIEF_^;4oxo1i@^kZZJ-ahiTsvjUE!54*a{$~`{SEf47 zY-Z(N842DI8s${dp{6$inr7~50_L6LfE)#yxuGWy>g5{6eqnj%IH`+o>OP}jBsPPx z#?^p4nP=Mk&1o;LMS;OzCK8KkmUV37<;B4mK1XFVCP!q}nN9HAY*~$J`s2%egA7kx znfJ(`;B%Jy2b*3;SzZn$CWagyg}^tJ2LbB>gnm2hw3F54V>ZCQ4h8qnwEl?g=$F^}GUT&Wus(ZA;X#cf9^bQ3u8mKl>v z6TSbtg4M3a^inyiY6&T#IdPsut8(YP^$rk)V!^$B#{BLKdW#y7Ke*j-HeHhi75W20oH&p4b(qou#Z@W;5sg!q zEQ~b!T!PU(_c5rvxv+e;Q4J4D6vr%TBPSP}AC!y``bUE20fVX%ELZN7_MG?4fHw;& z!%dlEPH0AIrQZcE>ajA@s{9J3H{ug}$4ols2?uYv;|RUQGD_M=)K6xe8(P6Usiz#d z%0dm3_hC@HTP7!F-g{Q;Mka)lE&&3vt&8Gl-)RLti#?OmZjr*I|64oJ|3(9DVN{Ius}h4ZOFm9q%>Hm&>R0kO~Zj&-h&bE{l%YN+s_qH<(+gA zy0|PAq(^MY15sZQt>C%YlN{WV%XZ^5#k#1;eH(ZTeDXI-zFH7V8=1)fHlCKJ&EZ7=#b_ zT)^c%6!rkOpegxi6^=aCp`7W>_3?W4ae^fdw9ngL0ewDjF%3se_W1YbYVj*=&BA|$ zOyva#Gs;3KAUlkRSE;E{R^CDkxZ3Z8UU&E4*a)sJ`j?KTx^S}|n&8tHJ+)*_rM?-$ zQP(opsgBj}mQdLA8wE0?K7T!0BAXAExHp|=<0Pdf50uphZ>f0)p0mxll-*nq!!e_A z8db_Ky_{R;8`k7c{0!*#RYkJ*kJH^Ebk?DfAy`-q-%MO*I@q-#rVe%^kE+t1M-%(b- zy8Y-!eE9grIVvf6RAjN<3!$Cto8YBCvxwPqLO)j-r-p|Pmu@#*FVOr({C`4ixGqP% zxv#HJL8C8?xTC|kwK~4O7B<>q8oe1OnBWpSjB3#_{9ip?=pw#t)b%RsY*4R7PHH#y zt#}ZnfogPr1)#nja304WEBJ#|k`9!Od~?a$z@K-gMH6oMY|E6R_M1U4GDJ<9DC+Wi zD#^8h@FDCOO_#R*W6I@{HqR)X{ThDu^GG(0{&}dqc9IW!BDwmjmx2BPbetFbTv|WT zcwDP50s2%!5aT&KFMSTeuY?{feMVpiIzXU{LLBnGz_9|*pqL4f^-ux4@e6d=3bvm| zxv1riu@zfIMWZNI`RKfpsUnkEZaYCF7kLpWRMDyHq$zc;RL+W%2YRB!{JV2NABMx< z;?^j)SY9emoIK!I$IkwN`n{ZPHkJAmtn{8;E(R9dh%V$NXTfP=s!-XFeKuHh^iw}$ zUyQzRpBT#7kpqY|zs-SiD#dQs)8@I^yLazLYHAu3&W^?hqY3n-JOf3eW>_ckX8+cg{%z&B z)R_JDli$W0MxOtU0dZutZ~edh);}_0L25_%?CzbRH4n@tzzLiyeph%zJ0ivL_rX0R z3Dj+;#siYBP6}Vv`P|EGZpwP#UHc|v@>Q5mUEV$DT|LNb@aDdm4u7TbbQ7<_33ak@ z_kZ7bYkosq6bx^yIeN6F>BwB%9UP(0_ayQD% zPVnWh+ z*odu|q>9jxsz9zSwm#Rr-mP0s4B-V-+VJYJki15mU5Gef>|VQcm$oNqS-U;9(vRY` z+ii!nJz=-l9PtwwK%%7B?jcOVKP!Z1ywVv0|AVf(@w=nVfc~+$fm!qm{EKMwmAK@i z`4e-IIdIQ_Zx!GRSja#z10}Y256MY^xjg$^mF9w5_*)|Ljr5|E_>R(HA9K9<>sI4a zlJ5iVa|nN^-hDi9fV}mwENMrlG_}(<%8KpjDP(Gq`7cvSE2^`Bz4q%Ac(d#8Q7j^@=Lx{5+w?d_VK?JA~5 zbCRtp*G@{yYK3AztW!KTFdu)VvaYn$%*=INSJlpnO4_T^9GIHov~-xovz4uX|MhJ0 z6!Cb=uerU@Gp8lVZp9D)pa&5k7POa}gFJBH1TOH!Gdu6nl-;^+9v3Ux!GowDl)VSn z?69JUJVURS7dm|=SyJo<3JM5mkOOHJc>-T0$8M^79Tz7zco2Dkw_WVEBW1m|)B1(M zQtTv^=;(F|@Bv@wDPQTndbK<4{{QJAe2q~mV`9ogygg7sLm;rT@#*yQ`sYv2g6v%P zq2S=qP*qR*(ZZUe1=|O-lb3sWz2M%Z#oonaTHrSQ|J%3sG+(m$OD0D|lu!5|O8(W? zKbXC5qYcti9>X#r!Oj=TPflLDw$A%^iHXGoLh;;OxpHjG&KDXwF!1P6pVJ>aOk&C$ zk^LfBImyn(05fAWY~CLf%o}!Fs0wIz3kj?|9<=$&z&1BtV0EAbyQ{;-QzrAGq1m*m zUV6HFDsH6R%1fT)NpoUT(aAF0Icg=AagMRr<7G%dwRw+BmfBfTB5ykv;5J{09SCTU z>{YX>VpV7YhGZRVwLKbUN55~sstv^P+aXzQm*@W|1+l%oJF#YZ-Q=X$u$-Nm%4S*q zI}j{Eso6K|5(Ybq{j3dOmayQ2<;<&@FYjJ9Jbl{m@}&j8_9gFqk)k^O|G(o{RY7ZU z_!fch(3wMZht#({;m*%--V-R zwr(|DitYUrfQG3PpFUk)HmbY)8bk>Od9Pn*W}ZHy4_!Vj{pDr0_sHoAA(!ECZ{7@P zVEQu?WDT|kx!apH1GjkUkfKTJ)cm)(|S!B=OqTk($9v_5GJM@2{Aw0A!d~opb zHUK3xVIo~r1*9wTSx7Jc3JRy>D`tY4Q}(a2!7VT}eAp{RMGtHCh9u2?K-$v4%gAy7 zjC-Y7YFb4t%R1639!wQovzCUe86mngKb-*7xw6pu7&S zFx&J`Yz&D6$lI(sXF8K(eQw;~1skzyDqsIg%b!l&w=?&4>Jz;x@9C28RO(&g0K z);A-tvbI?#(iW#Xe>&&5+Fh)XIVVa1k}nri&Y%5rG7k-kB{L7ls}3GNpqk0br}Mq| z+VT}()x+)ly}OYP=bnT)O=*^@R^BD%jE*wSsD^3WJaO{zGbO`SNp%@Vy3@$f#Fmz7%w@PV?!8j#rZwkwgngw zIb8gW%*;((?nER!w!_b>Ffdq@KFl`1IueP?AeO@5w}zuH67LpYIp5442|gbG??Rq` zGqG>BEzVoAIye)drW7BzN4#`CGdryJIC11ysFG6l53z-K?OP%tD9znFCMW;vXr=tP zAbs?a4p}1-4}?Z_T(J1Mh8a>5N-uJ(wLcu`T3HKh0nN2?M~J)M$_s4ih{vjX+$CO| z?-+5{F+rK^BeKlvUumyk@8~_n>3f>{N%$MC9k={m+l32l@km?mc(PcY8Q^W#y5Uzz z4_Br^0u|~1Q@$YaT8)&)y8kc4r6Uu$&i~O+kx1UPz>OUNNZP`NFpt=LwYxhS||B#?nhAc&Hdn6#!UN#RI=}6s+ z-aAd~7l;Z@jl1hMUnb+z+K^J~66;|;r14{^YX9m@z>s0ZUBCKjyc|E{$3Ezoaj(qi z{^_UgxI-|%D=8-#gbrT{-4t@^VJL4ud>FFno^W{br^Ug$2ZDkIdV&?cPgGBT(Aq&V zdUC}kk^C>gyvYw^9@COE>BTKYu`gf1DdPfCgbWo*{`?QU3|D+5ku*$esEIA&+?}+N zuUPC!)YL8P%aQNvmX&^}zCK;N{z2>s&rRRvdcQv$5VyUwhGf`_8(YM8chTK87Iq{z zg={{s3hAi`&Uw9dem(3Q?p8QAW#xY3$*aiUAVKp`;RMlw83YLPb5#H$qE~7H%X}rW z!7U_~VL}LI{KsU5gpXbo6^k)z_aP9X3KO@B` zAf%kj#G9fTBVUC=gsjwvupfcM_5ufatt3sWX>3p`Z|Gk#(SZkOQ>Z>DQPFBBw-^T8 zNTnxBPGE7skjskwUWwNZbZTh@-k?>l!GsoQ+|oQ}XT?m;3NB_s`^3@d_& z5vtb{BBN0@0}d^igvWc@GSh)Ctcn0U$6g90rwB8FTwbAqtO zRbpgOA0yEy66xrkyAFRMhOIYa%uomlkVzh>*AB7i>(>U#ryte`#R|a7*0=TRR+Ou*Om!)Nt~x)6TF@>CDFlLD4Iv`Xj{+2>1yC?x4xJ?i z6GS8oLF&?yPnZXS01Jd|fDpw)gosGVD=6XgLJd}j=i8A9K??C2of;sB(=p4|A+^dz zu>7gOMwG02(nT=$Y`q$QU1w%)t%}qsGPBCn$@-W|*V&py^{?I(T}G$J3=H&lwbT|^ zGXj=P8XP$E&I@&Rs~{Up{&p}~ayyNl|1bTME2zfbPpnWzR{`aUCZ&?3REEzg-N%0h zmocr1d|AwZLL0^!Osdk^icTnEu?qd@R+u&E&Ps+QqmAWPXhjdE1(+V}8u$MNa=E|; zW#7+o5Q1fP%=(6|2Ay4X)H;EkeXS$Ak_N@|NN8DTly$%61xA@hmLFv`pb@V~^*}vR z{X{FFSDHf_fsf(PTf@O3h-c1`m}(Gj=Z9&KeJGt9+B0g{4|I-0mu}BKj8>5Yb%5qO zu)XjsPuekauK645EQ9RHp@T|DK&4)=x-~Es8|L9*8^5!jT^(~i2U!FeG<@@iWfbX$ zhvc&t7xVfj_I+MfMrQEAcs4}lvpr|~YUr5719nZuhW0M1BN;^7LjdgWe?o`MUa?Tn z+$4y2zqpjQ1R|yn-tfCICe8uy$M4Ue5)x49nYXlD*-%jVTIn`q)#gRrix=tCf_qYcXZ z?0=2kwx9Dcf`rJ;hYeowqj3CqRaB36?2q*16x>am8leY#i1Duc=^y~shWf%_uL-Z* ze^2OT`~`4fJ>Mg~dJ>A-Vbj&? zCk`@x@)lJfPNed0{h-lXy>4Yz^!8*aZ$+h+DaSQlbd6q_?c9A^*?n;Q9MkEEpZ$OZ zV!%GgFXh{Rm5*yrs#o%<87X8))EzMe?4 z)D&J`3U!r<>h;FX83f232VE_ck$}|D@TVoHXi5HRK80kr4>s^sh@rLS7VT;j{X6?p zA;sH>DCpoH7u$BZY;+!pIZG)Z#ppSZ0(Ob>90r8VRo@I{cVpgSx?_o|hX63#w=K0> zvI9n2r_}a-zy#BF#KvZ~t?lmR8FAY7Et@Zw%Y0&SN%5{-kn$}kSfNr^e*N08VPQew zw$Gf=*B1u_g8Xn&Etc|8VgLZ`Sr6BMIy?R<2|j{`+UDKP+mGK`%g9+x?!h=DOboUq;Ug@3k*O%giVfJ~1^KezS zs(8Ydk=UM=@Q|t;61{MQS5eFesfzaWO&lR+Ci`uB%E#1-9RneV8K9uRfKR}E&j`F^ z&#n0Vdp6?NzXN(cg5T z%DL5%-3>CGATuTs=hDnmztjY9j0kc!F;DML=j;&eU1H&T=db8(qW8awGA7Shv+#j0 zedf_B!t~7SDTiXBi@3wqLM4gQ*SX?t$*Zm7V4d0@A8%+j$|TjnAHO|0FE_e=+oN>$ z#WgFj*mPk&LabEG6+cT{F0g5YtDV&rXE$e;pM8p37k;~G72!S;6LKe5?^gPZf824f z3q4IzY4>nWw=rdynLx@7iAG77nN%@L&SuQd-ylbn5|Ne5wGA&->a)GGeFt9`JjLBs zM?z?s*Z5Ozr0&3>iYR*5UF`f}gP=MsD>KXVJx>EjNOS+(&mSw^xJy4Ami;DBezoS# z9P6ws7h8rDy+WfT4%X9H@)MkBos0vjIe!bgJ}=$0paTDm=OlyTbeZNWFYfeqp`C%R zyUDx~xLRTherg}+&1w2T744@scxbZNLP6znZ;`}qmO+H1_STr%aq32!{T@ya#dMj) zvjFL&XbMfLYxC(Uj6*8&5HxK|$h%=v5IjyxF%gj%mglzi7GMmLmPH-K+~Ea)9GEX0V|ktD7*smnhY{uZz+*! z=j8_wnq~+t4O3K=2DrLUldE0jo#T7knsV~ptMG+S-BVT+Hn~lC^-+SUVtSh`E1T-J zcUvRuZYuY)!tZO&1_qH6Z%?h+6Y05~q*ask}SEnw#J=k&{)MzAfK~pFVq;@ouN3+NtJb8WZGP`dPt?rC7ly zOlPwY>$NXf`lD_2(YfbhNBZC=s`3jQ|bl0;i|1lW~FJ*9enolNmqb8Ez2klO~?1_wnp{1+L+dM2_aZ^lSzy2xu}GN zEKB2IQ2RxzK4{A69cce)0h81`!As`$dSEAY@pf{ruQX++6$a_tM*jk2xhXyGir?bZ zJOEF&!ihhXH1;qDQEFC1OBptotXbAMcWSP3D*PrJ{*c~%W6|R$vi{}}67aM~FEf|P zPOF3sKXi)jcWG3`p#ycq?bLX$vd{#Fb+*6Kt5jZ{_Z(eo*}#393+Ge2+2yC+l|M!1h)OF?A@yAasU&e_hQlzLy+jJkNIfd_!XP;5!C zJF?^p`t=S%gcceczV1}vQxU5Qi+30U!osg!f?|PRHS!f z70Kvfp}q+RM)tMv`o4X@dR3<`J%|Zogc>z?L%9odl23mGmxyTM`*;Y~t=kx8c+SV7 z?vyVFH!+@whNP9>c8o9!;^o&Twx*O68`}SvMO0XCsOZ&M?qM1sNvq8`jd4q}XkP(3 ztj5s2+Q&qc;g~p>=@M082);e4qNBjI78x`XOBXGQmv)JczPoe1rj{M0Vd}3pbzP&- zg55H2rB`E3C23QRSBS{9tQD6lM9} zpU`^r^eqLX)^E}B3y5FjQo3Yf^2X~auA>X|+*_{MuKKMxC0Im?>Hs1$o0_~Qd8bD; zgnCf_To?P1sYhPY^1GBp-%k;ZKF7P>UHtnIEO$Tjez%;SrIByFt5v5x z3z&Z9YwV?xz)B%FeJ3i@eM7x^j1h>YOf8k~&CJ8;JOugu9mvwA_?%jcP?2MsBm<_; z&Q&%yRSX9-!l1yxw!lEpwwD+R+nSrlIvs=jhu_F=YOW-CC}hxL&U+LLf8lK{@D~_z z*<#K;91{BI>GzQ*kKFCYLU)IS_JoFQk?A)7=MQAJ&m0=+$sZ`_sqDYYs@Q$wx+m9Y zfd6yPvHZ;m$*tOdE61v06`1&Q!PwX30+TN(j0}8(U=CsXrMa96S9u5rg z{nXY4K9#jLHgi{6rO%Sf9M?qK;b)75HUNdE@En1MYUT2(3$Hw&1#MKt=bDIz(GhF2BXbvApNS8cQ9* zq}K07$lUeca~_KeO;D?cwd|UO_g9s2n zO%;{~c(FUo#g$Ya5UW1gx&r00z;yyaV3%AT3xSNug-CdvT;}*yCw5AA14zAA=iwu* z8Vr)JN8L{k1cQOFphO((l1>LKC@p&c3W3E%IVvbzbdP_yZw6a0e$8wyj&%F->m6rg zdHasnb!WmAMZ)l+qHtl6BHU%SOXYs5<9$T)PR)S-4vz+w-ivi-W2bzQW|G{&)Butj z(jMk+;_XJE(kxL+#U7bIrXM$4-G-AhycylK{=cTCW|CuS^Go;k+~rGp@}bKf;Av$= znh9*>+`E-*l2%b^Ih@sOr>AFV_PjmpR8|JEed)M8av9opWL@A)0fDN0+p-%%$6l7n z%V&32Lh#gn0%Az511MyYgp@>*JkA_j?~iA2kT+Rg&#I_tZ=cN61*dS@?Cr)L9Iy>9g0h_Qw&N6^CS5Fgfe)V6${LRZNi^jYq z+4&L3c9{43D%Ol(ev@rC1>vY@M=vhURUFajaygDNB*#@0wBxCj!!^_p$CZpdkzru- zKjq^l90nEV0+^sG_e_jdgLOjRl?U2O!3DQ2T9m%i+Ub-iHo*`pN?ZUSFFBb#y=i-mkUw@R5Cc2M&(+@7?=Jpx!*JM27I}yelPoI{`BcSmVHM(9`ENs004lHfMkCb z325v+oqrSpeVTr(1=;GrZjb#cE3-hi1J^yuP;c)0cJcUlwG(D**P5kw_}LMu(*S(1 z=^^%EAEG8IqoS`Wt786X;B3hPW1fXW4)QkGy)9!iy1qCfnc3H`nH|V^_x^#8YTeW6 z`ln~nDRuYDAC$j0E#>c&^7{k_F@7n@4zMJlu007D^_9oZ&N0X@uaxADGRiMsRQo+t z=SM2&{qoDI99($%wYR#fDuHmZyTazIG*9wO-TW8 zJd$m;@zI(jo0oY}fTl-W09>mX9d9ckC|T>q%lJX2_ZeXHGBRAa%Re{y70;(4g_?O0d2Uf%a4st6;y!_1UWkE*46Z zU4^3z0#yIVtnEo7tlz@MI}?qBlTN-y;`&7L)?E>Xi=ARK!I=2YW`j~#z&1%W@A_^< zeS;M{@o0s!Vsy8&XSCnhe|#wOo%y40r9Y0=IA0ju=G-=VPI_+iqV&S(m~#)<7WF9P zyY^k#_xI(!({@fv{XV=hZ1OWl!T7C8tz!xU>JQ(^{Pry=e)#>cK@m6c+4edb7YL4dLLG~^IMFGU>sFeX-3%D{pfGflJ zzNtk;E1UQ1ZC<(0&WWSw5|BL;xlU=a(el7T(=DYB$o_TksBV4`m(@HlUQ($pt({yd z8ABMZvBO{pF*R1@JU{2Hx8~5!Jzt#z{jnBKO)Vn)(URJC*Iv82HvMFEEv+3gzR^wn z0sLT9P$fo4DcEo7 zbN|W3p{bt(6Y5lzOw7)LMwV(XH)oHe>s6P$jol;LU`srMP+81x~b=79u?{zx$E$Sah zG>~3WT&b!RiG*%!)^o$p`}x&zupIX=1jRHcAq0CUAEEBI>T&V+i5#?)VHA|WcFJdX zSDHb0j2Ic~kL-c^(Y=|fdi@*q9o$u6_MsDTeoxd34tbA58#h9U_`%Mul*bZZI$9WT zgK0v=MBySBH$y$b&Q?f0?|J4(reF_hnNtG1;9PlzWj?y4yffudk}m^&ZWxy)#PEVq z^?rOzKN6c3A^61A`G;UPxqHatJtEKyr*2Y|E!*+1^-HHJ4Pl!N75j}KC<>GQNnRoz_JLGM30e>(eMX4V)?O;zioSqm|$zq$ok z<0LoyB2%%)O)XBpv7bvj?xU$0L&iWn(odJ>d%LPZ73A|K?_w>ef^0S0Vopyj-K;3_ zREH`~X~p`qZXmw+`sz7wv_#0_f~l^|0hUVW7j0qAe zwh1>po(3<(Al+ZzZUyW1MP2OdJs+33tALi|PcQLJ^6Cf}#wLg_G=~)=34|^5G1m}c z7|Eo?%_vV479Ntx%jLp@;$L`GC3hZ{ay;l{yv922dFj8j*iY+jOaN;N7sHDcO9po( zq!9R*TVi^AUfrxl3`W2Nm%=G`WwW>9=Q#SzX&VYBDS2>bf|R7LnJHb>puI%BbPi2o{^-L1h>zSTy{Gcam{dlvZNPB&@ zg$_$NGJZ(7i>+;*yI#lQXxxdJnYa_THl}M8ZbE1iJlB*dJ=geYS@zXxS#AtyZEX!` zy%UH3pu3)DsvFz5yxjDmQ4dxEgO$L3?S0a8_gO1WuQ$LH8dtC<;nJM0wjKh@Fgm6k za5%O9Nkf2sH%d)!>CrC{D1rX2zi#@z5FNwN!gbpouHJ{n<>toMvAX7*9lECT75Daj z|39qM2v!=n4Kk-Y<6^;REYvh$hpy?3)J*|Lj%gcZzziB(hShPXqhFRmO`u1iCKE#o zI!1`EKD>7~?u%S~m+_)0^6{k-&Au*&LwNXUGaY!Tb;paNS%|b72rmT26VmNJQ-HDc zM9>fhhh?ZO&Nr)a3%}c3wDWKG?n}D1$GtMpZq&}`c}>6LFhi|A4y0da8kQI;6o$n{ z`O-q8Vnd@eqe2A$la_q~(u4ZM846*rk85nS4{78cT80az& z-WDX8z$N+bX3f!!a3Ay8rDUCLNgm9aIl)aeovti>UDy3tXVX>_Q;d+NDTtCRSMntw zHw5BnBXUt?l{|_-avy&GdolSmq2IfAlSPZl?gAb;N~EtGC4aK+JiA3By&D9}bv3O+T*29({ne9(P9&j3U*5R~27QPBT8! zV5)}KjsK#KPKBE65DJe2NW*(-i9cC|Y{rNRL6U4)kt|F@YH*;cAxx5gFxT^Nm%^5n zG)qqnhe*SV7K@N#=c2L!Qkz@azWpmXn@xr3!bp&*nO>t5+}3F|fB?{nk3c~5(_{?* zEjkBO`0fIV&Ve6m1d74a4F((7F~}U9Xwplag3ON~DuUZ?HcI!vw_ZuC+$WAjPTi1> zBgbzV$_J68LU$f);+A#Yom?#qk4_c7TKOYKJjI4eEAiGHaw5Ib-9nX8TbL~5$$WW~ z5^xJ-`6_Hd9Od_ZbD*3;wRh`c=&3u%j|Qu^7ww-e^_^;NyJsW`oH~z$kG^{!->LDpyI28u|E~7bNw9f?ML$V*y=7uD z2gZSAW!vj7JPy;O0y>qdiZs*JOuSa{svbdf0nJ!7^(u9did2=ZP9=X@&^MOF!eAVB z3L>!%LmKevbQ2P+|FP6jEmxPqOf*Cgt+m5&T@ULDSd-fP$_CV~8-^Ew^&5N253?!W41ePutY3 zc(vvBc-hql|*LES{D$)FU z?Lv7*u4xR-r;^{BmqRwwjk{w8Cnbw*>*`z~_gbn*{W->uNA*n`nEo*;{F2_?E5-%` zkKqQ(aU@ulzeP=E47nN>Y(gmJXh7zti3G;R*Y+8h)dnFs&Mrt^V2_FZ-Y1laD(pKf z?kyHOi^E>=1wSU43RJ z6La9;z|N8M32Wb1V{ua%E`z2~>3w2xX>sG)*7fPr749eT6Q@qUeZ#;8c|M71ZR^gM zlHZ0m%S&{So90;HI?v1{B!d{rflPJw`@1Z;C`p zrObEvvZ+aP^Lz&mh!a13S^>Q6oXbbBJ(adLi_J#AARzXep(61$xl9gE;o!zn3zwZ$ ziE6EeQ6syx+D!K^u1~{Q$zFYMMYb8Wd7-QwwsDyT)um+C{v0T%@$2&#qtR<_*8H!f zUaM;{T6$GeUfbnz!X(0Uuj0jTFw&R0*KCvgg$6L87A=D4B=u3qpN{s%Inl64+ZYdu zr8cJWDkTkN2s0%$ZHT{}w91@URyrp_LxhSx~NfGE+1MymvgSnMW zn}z;KZFp|hoR?mUo{l%mN@!(a=(y$|hd6@?jUIm*5$$2Q>VSjw4ky)VS#UhWffJrH z=b{DEI^~<QXDTdU~F7Xm*iX0D8Z4HNHse?4EDy% zMHt~Lcd>${0pLZYkRoNtkUJ5Z1_)m8-`b7bjA4bs>fHPp`Q4CzY5_c#YDU*=S69tBASe5|ZBHT4S!jUc5U{`!U1HvCPT0snG?gR9hFA{VIe z_77-Va@w`|VcS~${flP6#9Zr>6@>s1oMeIG0*Z2^WqcSuYnCc$1ju+%=I*5VQ}U57I(N0@{WD(*;cv=-0Fb5nPyZlC zCe4iovAsL$KZ3624&da{6&|TcQgAL$W$UruK`|Hjy>|dGkGF--GZ0HpL3=1fBHCYu z;baOC1@8*cf4DB!_APMoeI~ERs|?|EU>i=h%d-l#nxxl9S~t;viQ`1Koz*{8#P8wo+I8uE{nf@V$UWhAp_(vLk z8}+S6w}JB<%JJg3n1<*aRBSN!)_twLBo4}}B0i5V@FotvzjhGJp|3<$Pa!P^{L!}=95DOI;G>xz{fTLK!wfD0S1s8t{nwNLp`}fw literal 19672 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

&#we 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 diff --git a/srv/http/assets/js/features.js b/srv/http/assets/js/features.js index d46ae3cae..90d4e6124 100644 --- a/srv/http/assets/js/features.js +++ b/srv/http/assets/js/features.js @@ -70,10 +70,10 @@ var config = { } } , localbrowser : data => { - if ( S.localbrowser ) { - var footer = ico( 'redo', 'reload', 'tabindex' ) +'Reload '+ ico( 'screenoff', 'screenoff', 'tabindex' ) +'On/Off'; - if ( data.brightness ) footer += ' '+ ico( 'gear', 'brightness', 'tabindex' ) +'Brightness'; - } + var f = [ 'Reload', 'Screenoff' ]; + if ( data.brightness ) f.push( 'Brightness' ); + var footer = ''; + f.forEach( k => footer += ''+ ico( k.toLowerCase() ) + k +'' ); info( { ...SW , list : [ @@ -99,25 +99,27 @@ var config = { .prop( 'checked', false ); } } ); - $( '#brightness' ).on( 'click', function() { - info( { - ...SW - , list : [ 'Brightness', 'range' ] - , values : data.brightness - , beforeshow : () => { - $( '#infoList input' ).on( 'input', function() { - bash( [ 'brightness', +this.value, 'CMD VAL' ] ) - } ); - } - , okno : true - } ); - switchCancel(); - } ); - $( '#reload' ).on( 'click', function() { - bash( [ 'localbrowserreload' ], () => banner( SW.icon, SW.title, 'Reloaded.' ) ); - } ); - $( '#screenoff' ).on( 'click', function() { - bash( [ 'screentoggle' ], onoff => banner( SW.icon, SW.title, onoff ) ); + $( '.infofooter' ).toggleClass( 'disabled', ! S.localbrowser ); + $( '.infofooter span' ).on( 'click', function() { + var i = $( this ).index(); + if ( i === 0 ) { + bash( [ 'localbrowserreload' ], () => banner( SW.icon, SW.title, 'Reloaded.' ) ); + } else if ( i === 1 ) { + bash( [ 'screentoggle' ], onoff => banner( SW.icon, SW.title, onoff ) ); + } else { + info( { + ...SW + , list : [ 'Brightness', 'range' ] + , values : data.brightness + , beforeshow : () => { + $( '#infoList input' ).on( 'input', function() { + bash( [ 'brightness', +this.value, 'CMD VAL' ] ) + } ); + } + , okno : true + } ); + switchCancel(); + } } ); } , cancel : switchCancel From 763a18da0f0f76b1b01f3d67917c6c8311de2fdd Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 2 Jan 2025 09:44:22 +0700 Subject: [PATCH 44/88] u --- srv/http/assets/css/main.css | 3 --- srv/http/assets/js/context.js | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/srv/http/assets/css/main.css b/srv/http/assets/css/main.css index 5b2fee56c..16f81efaa 100644 --- a/srv/http/assets/css/main.css +++ b/srv/http/assets/css/main.css @@ -1928,9 +1928,6 @@ li.active .li2 bl { margin-left: 10px; text-align: left; } -.tagfooter { - line-height: 40px; -} .tagfooter div { display: inline-block; } diff --git a/srv/http/assets/js/context.js b/srv/http/assets/js/context.js index 165e40401..00bfae2bd 100644 --- a/srv/http/assets/js/context.js +++ b/srv/http/assets/js/context.js @@ -374,8 +374,8 @@ function tagEditor() { var message = ''+ file +'' +'

'+ ico( 'folder' ) +' '+ dir; message += V.list.licover ? '
' : '
'+ ico( fileicon ) +' '+ file.split( '/' ).pop() +''; - var footer = ico( 'help', '', 'tabindex' ) +'Label'; - if ( V.list.licover ) footer += ' *  Various values in tracks'; + var footer = ''+ ico( 'help', '', 'tabindex' ) +'Label'; + if ( V.list.licover ) footer += '* Various values in tracks'; info( { icon : V.playlist ? 'info' : 'tag' , title : V.playlist ? 'Track Info' : 'Tag Editor' @@ -396,7 +396,7 @@ function tagEditor() { $( '#infoList td i:not( .i-track, .i-title )' ).css( 'cursor', 'pointer' ); if ( V.playlist ) $( '#infoList input' ).prop( 'disabled', 1 ); var inputW = parseInt( $( '#infoList input' ).css( 'width' ) ); - $( '.infofooter i' ).on( 'click', function( e ) { + $( '.infofooter span' ).on( 'click', function( e ) { if ( $( '.taglabel' ).hasClass( 'hide' ) ) { $( '#infoList input' ).css( 'width', ( inputW - 92 ) +'px' ); $( '.taglabel' ).removeClass( 'hide' ); From 17acf4f85e934bef75d45867dd3db932a27ffc09 Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 2 Jan 2025 09:57:58 +0700 Subject: [PATCH 45/88] Update library.php --- srv/http/library.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/srv/http/library.php b/srv/http/library.php index 5d1a1f945..86a11b82c 100644 --- a/srv/http/library.php +++ b/srv/http/library.php @@ -622,8 +622,7 @@ function htmlTrack() { // track list - no sort ($string: cuefile or search) } else { $datamode = ' data-mode="'.$GMODE.'"'; $icon = i( 'music', 'file' ); - $trackname = $cue ? basename( $file0 ).' : ' : ''; - $trackname.= basename( $path ); + $trackname = $cue ? $artist.' - '.$album : basename( $path ); } $track1 = ( $i || $search || $hidecover ) ? '' : ' class="track1"'; $i++; From 1734878cf71438c938e672c962cecf39cbd7471e Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 2 Jan 2025 12:59:55 +0700 Subject: [PATCH 46/88] u --- srv/http/assets/js/common.js | 5 +++++ srv/http/assets/js/features.js | 14 ++++++++------ srv/http/assets/js/function.js | 29 ++++++++++++++++------------- srv/http/assets/js/system.js | 8 +++++--- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/srv/http/assets/js/common.js b/srv/http/assets/js/common.js index 5646c1b68..05d5516c2 100644 --- a/srv/http/assets/js/common.js +++ b/srv/http/assets/js/common.js @@ -964,6 +964,11 @@ function infoFileImageResize( ext, imgW, imgH ) { } } } +function infoFooterIcon( kv ) { + var footer = ''; + $.each( kv, ( l, i ) => footer += ''+ ico( i ) + l +'' ); + return footer +} function infoKey2array( key ) { if ( ! Array.isArray( I[ key ] ) ) I[ key ] = [ I[ key ] ]; } diff --git a/srv/http/assets/js/features.js b/srv/http/assets/js/features.js index 90d4e6124..b949e1903 100644 --- a/srv/http/assets/js/features.js +++ b/srv/http/assets/js/features.js @@ -70,10 +70,6 @@ var config = { } } , localbrowser : data => { - var f = [ 'Reload', 'Screenoff' ]; - if ( data.brightness ) f.push( 'Brightness' ); - var footer = ''; - f.forEach( k => footer += ''+ ico( k.toLowerCase() ) + k +'' ); info( { ...SW , list : [ @@ -83,7 +79,11 @@ var config = { , [ 'On while play', 'checkbox' ] , [ 'Mouse pointer', 'checkbox' ] ] - , footer : footer + , footer : infoFooterIcon( { + Reload : 'reload' + , Screenoff : 'screenoff' + , Brightness : 'brightness' + } ) , boxwidth : 110 , values : data.values , checkchanged : S.localbrowser @@ -100,7 +100,9 @@ var config = { } } ); $( '.infofooter' ).toggleClass( 'disabled', ! S.localbrowser ); - $( '.infofooter span' ).on( 'click', function() { + var $span = $( '.infofooter span' ); + $span.eq( 2 ).toggleClass( 'hide', ! data.brightness ); + $span.on( 'click', function() { var i = $( this ).index(); if ( i === 0 ) { bash( [ 'localbrowserreload' ], () => banner( SW.icon, SW.title, 'Reloaded.' ) ); diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 611b08539..4e7889655 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -741,24 +741,22 @@ function infoTitle() { var titlenoparen = title.replace( / $|\(.*$/, '' ); list.push( [ ico( 'music wh' ) +'Title includes: '+ title.replace( /^.*\(/, '(' ), 'checkbox' ] ); } - var footer = ''+ ico( 'lyrics' ) +'Lyrics' - +''+ ico( 'bio' ) +'Bio' - +''+ ico( 'lastfm' ) +'Add Similar' - +''+ ico( 'lastfm' ) +'Scrobble'; info( { icon : 'playback' , title : 'Current Track' , list : list - , footer : footer + , footer : infoFooterIcon( { + Lyrics : 'lyrics' + , Bio : 'bio' + , 'Add Similar' : 'lastfm' + , Scrobble : 'scrobble' + } ) , footeralign : 'left' , width : 460 , boxwidth : 'max' , values : paren ? [ artist, titlenoparen, album ] : [ artist, title, album ] , beforeshow : () => { $( '#infoList input' ).eq( 2 ).toggleClass( 'hide', album === '' ); - $( '.infofooter' ).css( 'padding-left', '35px' ); - $( '.infofooter .lyrics' ).toggleClass( 'hide', ! S.lyrics ); - $( '.infofooter .scrobble' ).toggleClass( 'hide', ! S.scrobble ); if ( S.scrobble ) $( '.infofooter .scrobble' ).toggleClass( 'disabled', ! artist || ! title || ! S.webradio || S.scrobbleconf[ S.player ] ); if ( paren ) { $( '#infoList input:checkbox' ).on( 'input', function() { @@ -769,20 +767,25 @@ function infoTitle() { var val = infoVal(); $( '#infoList .scrobble' ).toggleClass( 'disabled', val[ 0 ] === '' || val[ 1 ] === '' ); } ); - $( '#infoList' ).on( 'click', '.infofooter span', function() { + $( '.infofooter' ).css( 'padding-left', '35px' ); + var $span = $( '.infofooter span' ); + $span.eq( 0 ).toggleClass( 'hide', ! S.lyrics ); + $span.eq( 3 ).toggleClass( 'hide', ! S.scrobble ); + $span.on( 'click', function() { var values = infoVal(); var artist = values[ 0 ] var title = values[ 1 ] var $this = $( this ); - if ( $this.hasClass( 'lyrics' ) ) { + var i = $( this ).index(); + if ( i === 0 ) { V.lyricsartist = artist || S.Artist; V.lyricstitle = title || S.Title; lyricsGet(); - } else if ( $this.hasClass( 'bio' ) ) { + } else if ( i === 1 ) { bio( artist ); - } else if ( $this.hasClass( 'similar' ) ) { + } else if ( i === 2 ) { addSimilar(); - } else if ( $this.hasClass( 'scrobble' ) ) { + } else { bash( [ 'scrobble.sh', ...values, 'CMD ARTIST TITLE' ] ); banner( 'lastfm blink', 'Scrobble', 'Send ...' ); } diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 52517d179..2f78e0f4c 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -379,14 +379,16 @@ var util = { icon : 'lcdchar' , title : 'Character LCD' , tablabel : [ 'I²C', 'GPIO' ] - , footer : '' - +''+ ico( 'screenoff' ) +'Sleep' + , footer : infoFooterIcon( { + Logo : 'raudio' + , Sleep : 'screenoff' + } ) , beforeshow : () => { $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); $( '.infofooter span' ) .toggleClass( 'disabled', ! S.lcdchar ) .on( 'click', function() { - bash( [ 'lcdchar', $( this ).prop( 'class' ), 'CMD ACTION' ] ); + bash( [ 'lcdchar', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); } ); } , cancel : switchCancel From d5b6f4c93ed4fccdfa7107706816390adfc11ea8 Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 2 Jan 2025 13:29:37 +0700 Subject: [PATCH 47/88] Update common.css --- srv/http/assets/css/common.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 1495f75e3..324f4e73b 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -258,7 +258,8 @@ body { } i, .infobtn, -#debug { +#debug, +#lib-list .coverart { -webkit-user-select: none; user-select: none; } From bd604ec0dad6b7d6f3fae5dd1b83d68311e4ccfe Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 2 Jan 2025 20:58:44 +0700 Subject: [PATCH 48/88] Update system.sh --- srv/http/bash/settings/system.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index a57f6f158..147a73c84 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -248,9 +248,7 @@ mpdoled ) mpd_oled -o $chip -L ( [[ $ON ]] && sleep 10 - systemctl start mpd_oled - sleep 0.5 - systemctl stop mpd_oled + timeout 0.5 mpd_oled -o $chip ) & [[ $LOGO ]] && exit # -------------------------------------------------------------------- From 19c1d85b3692d41f5e8dff96a8973f5d1a392a32 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 3 Jan 2025 11:55:27 +0700 Subject: [PATCH 49/88] u --- install.sh | 5 +++++ srv/http/bash/settings/system.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 3ffe40828..e25152085 100644 --- a/install.sh +++ b/install.sh @@ -5,6 +5,11 @@ alias=r1 . /srv/http/bash/settings/addons.sh # 20250106 +if [[ $( pacman -Q audio_spectrum_oled 2> /dev/null ) ]]; then + pacman -R --noconfirm audio_spectrum_oled + pacman -Sy --noconfirm mpd_oled +fi + file=$dirsystem/lcdchar.conf if [[ -e $dirsystem/lcdchar.conf ]]; then conf2json $file | jq > ${file/conf/json} diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 147a73c84..205ed3ae1 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -248,7 +248,7 @@ mpdoled ) mpd_oled -o $chip -L ( [[ $ON ]] && sleep 10 - timeout 0.5 mpd_oled -o $chip + mpd_oled -o $chip -X ) & [[ $LOGO ]] && exit # -------------------------------------------------------------------- From d09e0594594242f6e03db5a02c52cdc284b7b105 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 09:18:08 +0700 Subject: [PATCH 50/88] u --- srv/http/assets/js/system.js | 1 + srv/http/bash/settings/data-config.sh | 6 ++-- srv/http/bash/settings/system.sh | 44 ++++++++++++++++----------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 2f78e0f4c..66db6b8dc 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -146,6 +146,7 @@ var config = { , list : [ [ 'Controller', 'select', chip ] , [ 'Refresh (baud)', 'select', { kv: { '800,000': 800000, '1,000,000': 1000000, '1,200,000': 1200000 } } ] + , [ 'Spectrum only', 'checkbox' ] ] , footer : ''+ ico( 'raudio' ) +'Logo' , values : values diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 42b17954d..37f6b79ef 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -96,10 +96,12 @@ localbrowser ) }' ;; mpdoled ) - chip=$( grep mpd_oled /etc/systemd/system/mpd_oled.service | cut -d' ' -f3 ) + file=/etc/default/mpd_oled + chip=$( cut -d' ' -f2 $file ) baud=$( grep baudrate /boot/config.txt | cut -d= -f3 ) + spectrum=$( grep -q '\-A' $file && echo false || echo true ) [[ ! $baud ]] && baud=800000 - echo '{ "CHIP": "'$chip'", "BAUD": '$baud' }' + echo '{ "CHIP": "'$chip'", "BAUD": '$baud', "SPECTRUM": '$spectrum' }' ;; packagelist ) filepackages=/tmp/packages diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 205ed3ae1..200c8d2c2 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -69,7 +69,7 @@ dtoverlay=gpio-shutdown,gpio_pin=17,active_low=0,gpio_pull=down" if [[ $reboot ]]; then pushData reboot $CMD appendSortUnique $CMD $dirshm/reboot - else + elif [[ -e $dirshm/reboot ]]; then sed -i "/$CMD/ d" $dirshm/reboot fi } @@ -243,31 +243,38 @@ mountunmount ) pushRefresh ;; mpdoled ) - systemctl stop mpd_oled - chip=$( awk '/^ExecStart/ {print $3}' /etc/systemd/system/mpd_oled.service ) - mpd_oled -o $chip -L - ( - [[ $ON ]] && sleep 10 - mpd_oled -o $chip -X - ) & - [[ $LOGO ]] && exit + filedef=/etc/default/mpd_oled + chip=$( cut -d' ' -f2 $filedef ) + if ! systemctl -q is-active mpd_oled; then + mpd_oled -o $chip -L + ( + [[ $ON ]] && sleep 10 + mpd_oled -o $chip -X + ) & + fi + [[ $LOGO ]] && systemctl stop mpd_oled && exit # -------------------------------------------------------------------- enableFlagSet if [[ $ON ]]; then - if [[ $chip != $CHIP ]]; then - sed -i 's/-o ./-o '$CHIP'/' /etc/systemd/system/mpd_oled.service - systemctl daemon-reload + ! grep -q '\-A' $filedef && spectrum=1 + if [[ $SPECTRUM ]]; then + [[ ! $spectrum ]] && sed -i 's/ -A//' $filedef + else + [[ $spectrum ]] && sed -i 's/"$/ -A"/' $filedef fi + [[ $chip != $CHIP ]] && sed -i 's/-o ./-o '$CHIP'/' $filedef + ln -sf $dirmpdconf/{conf/,}fifo.conf + else + rm -f $dirmpdconf/fifo.conf fi i2cset=1 configTxt - $dirsettings/player-conf.sh + systemctl try-restart mpd mpd_oled ;; ntp ) - file=/etc/systemd/timesyncd.conf echo "\ [Time] -NTP=$NTP" > $file +NTP=$NTP" > /etc/systemd/timesyncd.conf timedatectl set-ntp true pushRefresh ;; @@ -432,16 +439,17 @@ vuled ) enableFlagSet pins=$( cut -d= -f2 $dirsystem/vuled.conf ) if [[ $ON ]]; then - [[ ! -e $dirmpdconf/fifo.conf ]] && $dirsettings/player-conf.sh + ln -sf $dirmpdconf/{conf/,}fifo.conf grep -q 'state="*play' $dirshm/status && systemctl start cava else if [[ -e $dirsystem/vumeter ]]; then - systemctl restart cava + systemctl try-restart cava else systemctl stop cava - $dirsettings/player-conf.sh + rm -f $dirmpdconf/fifo.conf fi fi + systemctl restart mpd pushRefresh ;; wlan ) From da3f5a19a03bbef2d61f374c42630fef69751f1b Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 15:24:52 +0700 Subject: [PATCH 51/88] u --- srv/http/assets/js/system.js | 2 +- srv/http/bash/settings/system.sh | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 66db6b8dc..811233f73 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -159,7 +159,7 @@ var config = { $( '.infofooter span' ) .toggleClass( 'disabled', ! S.mpdoled ) .on( 'click', function() { - bash( [ 'mpdoled', true, 'CMD LOGO' ] ); + bash( [ 'mpdoledlogo' ] ); $( '#infoX' ).trigger( 'click' ); } ); $tr.eq( 0 ).on( 'input', function() { diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 200c8d2c2..3efd9cf85 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -248,11 +248,10 @@ mpdoled ) if ! systemctl -q is-active mpd_oled; then mpd_oled -o $chip -L ( - [[ $ON ]] && sleep 10 + [[ $ON ]] && sleep 10 || sleep 1 mpd_oled -o $chip -X ) & fi - [[ $LOGO ]] && systemctl stop mpd_oled && exit # -------------------------------------------------------------------- enableFlagSet if [[ $ON ]]; then @@ -271,6 +270,16 @@ mpdoled ) configTxt systemctl try-restart mpd mpd_oled ;; +mpdoledlogo ) + systemctl -q is-active mpd_oled && active=1 + systemctl stop mpd_oled + chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) + mpd_oled -o $chip -L + ( + sleep 10 + grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -X + ) & + ;; ntp ) echo "\ [Time] From 0b5c6bcba0c44e3fe027fc5c1f7decdebfb498d0 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 15:31:04 +0700 Subject: [PATCH 52/88] Update common.css --- srv/http/assets/css/common.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 324f4e73b..645c34c07 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -61,8 +61,8 @@ i { .i-star::before { content: '\F550' } .i-bluealsa::before, .i-bluetooth::before, -.i-brightness::before { content: '\F55F' } .i-btreceiver::before { content: '\F51A' } +.i-brightness::before { content: '\F55F' } .i-btsender::before { content: '\F51B' } .i-camilla::before, .i-camilladsp::before { content: '\F59D'; position: absolute; color: var( --cg60 ); } From c596225d3daf717f05c0b27af011444821b1ff5c Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 16:49:10 +0700 Subject: [PATCH 53/88] Update install.sh --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index e25152085..90770fddf 100644 --- a/install.sh +++ b/install.sh @@ -5,7 +5,7 @@ alias=r1 . /srv/http/bash/settings/addons.sh # 20250106 -if [[ $( pacman -Q audio_spectrum_oled 2> /dev/null ) ]]; then +if ! pacman -Q mpd_oled &> /dev/nul; then pacman -R --noconfirm audio_spectrum_oled pacman -Sy --noconfirm mpd_oled fi From c1f8691e20cc97a164fc53b0ec9eaac9874920c2 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 16:50:14 +0700 Subject: [PATCH 54/88] Update install.sh --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 90770fddf..fdbc2f0a5 100644 --- a/install.sh +++ b/install.sh @@ -6,7 +6,7 @@ alias=r1 # 20250106 if ! pacman -Q mpd_oled &> /dev/nul; then - pacman -R --noconfirm audio_spectrum_oled + pacman -R --noconfirm audio_spectrum_oled &> /dev/null pacman -Sy --noconfirm mpd_oled fi From b56ce2ef750baeb7128149673b33a8c2057724be Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 17:01:34 +0700 Subject: [PATCH 55/88] Update install.sh --- install.sh | 50 +++----------------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/install.sh b/install.sh index fdbc2f0a5..5f95aaa1b 100644 --- a/install.sh +++ b/install.sh @@ -4,9 +4,10 @@ alias=r1 . /srv/http/bash/settings/addons.sh -# 20250106 +# 20250110 if ! pacman -Q mpd_oled &> /dev/nul; then pacman -R --noconfirm audio_spectrum_oled &> /dev/null + rm -f /etc/systemd/system/mpd_oled.service pacman -Sy --noconfirm mpd_oled fi @@ -34,56 +35,11 @@ if [[ -e /boot/kernel7.img ]] && ! grep -q mesa $file; then sed -i '/^IgnorePkg/ s/$/ mesa/' $file fi -sed -i '/^brightness/ d' $dirsystem/localbrowser.conf +[[ ! -e /boot/kernel.img ]] && sed -i '/^brightness/ d' $dirsystem/localbrowser.conf # 20241130 systemctl -q is-active mediamtx && touch $dirsystem/dabradio -# 20241110 -if [[ ! -e /boot/kernel.img ]]; then - revision=$( grep ^Revision /proc/cpuinfo ) - if [[ ${revision: -3:2} < 11 ]]; then - file=/etc/modprobe.d/brcmfmac.conf - [[ ! -e $file ]] && echo 'options brcmfmac feature_disable=0x82000' > $file - fi -fi - -# 20241108 -[[ $( pacman -Q cava ) < 'cava 0.10.2-2' ]] && pacman -Sy --noconfirm cava - -file=$dirsystem/lcdchar.conf -if [[ -e $file ]] && grep -q -m1 ^0= $file; then - rm $dirsystem/lcdchar* -fi - -# 20241111 -if [[ ! -e /boot/kernel.img ]]; then - revision=$( grep ^Revision /proc/cpuinfo ) - [[ ${revision: -3:2} < 11 ]] && echo 'options brcmfmac feature_disable=0x82000' > /etc/modprobe.d/brcmfmac.conf -fi - -file=/etc/systemd/system/dab.service -if [[ -e $file ]] && grep -q Requires $file; then - sed -i '/^Requires\|^After/ d' $file - rm -rf /etc/systemd/system/mediamtx.service.d - systemctl daemon-reload - systemctl try-restart mediamtx -fi - -# 20241108 -[[ $( pacman -Q cava ) < 'cava 0.10.2-2' ]] && pacman -Sy --noconfirm cava - -rm -f $dirsystem/lcdmodel - -file=$dirsystem/lcdchar.conf -if [[ -e $file && $( sed -n -E '/^charmap/,/^p0/ p' $file | wc -l ) -gt 2 ]]; then - . $file - for k in inf cols charmap p0 pin_rs p1 pin_rw p2 pin_e p3 backlight; do - conf+="$k=${!k}\n" - done - echo -e $conf > $file -fi - #------------------------------------------------------------------------------- installstart "$1" From bba42f14eedd8c5835da47d37856649b88d8e8b0 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 4 Jan 2025 19:42:34 +0700 Subject: [PATCH 56/88] u --- srv/http/bash/common.sh | 7 +++++++ srv/http/bash/power.sh | 12 ++++++------ srv/http/bash/startup.sh | 4 +--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index f340b2c18..995e2a887 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -264,6 +264,13 @@ lineCount() { line2array() { [[ $1 ]] && tr '\n' , <<< $1 | sed 's/^/[ "/; s/,$/" ]/; s/,/", "/g' || echo false } +logoLcdOled() { + [[ -e $dirsystem/lcdchar ]] && $dirbash/lcdchar.py logo + if [[ -e $dirsystem/mpdoled ]]; then + chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) + mpd_oled -o $chip -L + fi +} mountpointSet() { umount -ql "$1" mkdir -p "$1" diff --git a/srv/http/bash/power.sh b/srv/http/bash/power.sh index 576573079..68b8a9450 100644 --- a/srv/http/bash/power.sh +++ b/srv/http/bash/power.sh @@ -32,11 +32,11 @@ elif [[ -e $filesharedip ]]; then fi [[ -e $dirshm/btreceiver ]] && cp $dirshm/btreceiver $dirsystem touch $dirshm/power -mpc -q stop -if [[ -e $dirsystem/lcdchar ]]; then - systemctl stop lcdchar - $dirbash/lcdchar.py logo -fi + +$dirbash/cmd.sh playerstop + +logoLcdOled + snapclientIP playerstop cdda=$( mpc -f %file%^%position% playlist | grep ^cdda: | cut -d^ -f2 ) [[ $cdda ]] && mpc -q del $cdda @@ -47,7 +47,7 @@ if mount | grep -q -m1 $dirnas; then fi if [[ -d /sys/class/backlight/rpi_backlight ]]; then echo 1 > /sys/class/backlight/rpi_backlight/bl_power -else +elif [[ -e $dirsystem/localbrowser ]]; then DISPLAY=:0 xset dpms force off fi [[ -e /boot/shutdown.sh ]] && /boot/shutdown.sh diff --git a/srv/http/bash/startup.sh b/srv/http/bash/startup.sh index 241e24cf4..2dae212f1 100644 --- a/srv/http/bash/startup.sh +++ b/srv/http/bash/startup.sh @@ -57,9 +57,7 @@ CMD ESSID" fi # pre-configure <<<----------------------------------------------------------- -[[ -e $dirsystem/lcdchar ]] && $dirbash/lcdchar.py logo - -[[ -e $dirsystem/mpdoled ]] && $dirsettings/system.sh mpdoledlogo +logoLcdOled [[ -e $dirsystem/soundprofile ]] && $dirsettings/system.sh soundprofileset From 39337cb704c15b03f9e2fd44e29567ca3b04f09e Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 6 Jan 2025 08:45:09 +0700 Subject: [PATCH 57/88] Update power.sh --- srv/http/bash/power.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srv/http/bash/power.sh b/srv/http/bash/power.sh index 68b8a9450..392e8cae4 100644 --- a/srv/http/bash/power.sh +++ b/srv/http/bash/power.sh @@ -2,6 +2,8 @@ . /srv/http/bash/common.sh +$dirbash/cmd.sh playerstop + [[ -e $dirshm/relayson ]] && $dirbash/relays.sh off if [[ $1 == reboot ]]; then reboot=1 @@ -33,8 +35,6 @@ fi [[ -e $dirshm/btreceiver ]] && cp $dirshm/btreceiver $dirsystem touch $dirshm/power -$dirbash/cmd.sh playerstop - logoLcdOled snapclientIP playerstop From 5250b829485d5dd9a176dbc31e84a6a94f0c6eff Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 6 Jan 2025 18:59:17 +0700 Subject: [PATCH 58/88] u --- srv/http/assets/js/common.js | 7 ++++--- srv/http/assets/js/passive.js | 2 ++ srv/http/bash/common.sh | 2 +- srv/http/bash/power.sh | 10 +++------- srv/http/bash/settings/data-config.sh | 8 ++++---- srv/http/bash/settings/system.sh | 24 +++++++++++------------- 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/srv/http/assets/js/common.js b/srv/http/assets/js/common.js index 05d5516c2..1048391d5 100644 --- a/srv/http/assets/js/common.js +++ b/srv/http/assets/js/common.js @@ -1193,7 +1193,6 @@ function infoPower() { } ); } function infoPowerCommand( action ) { - if( ! action ) action = ''; loader(); bash( [ 'power.sh', action ], nfs => { if ( nfs != -1 ) return @@ -1208,7 +1207,7 @@ function infoPowerCommand( action ) { +'

Continue?' , oklabel : action ? ico( 'reboot' ) +'Reboot' : ico( 'power' ) +'Off' , okcolor : action ? orange : red - , ok : () => bash( [ 'power.sh', action, 'confirm' ] ) + , ok : () => bash( [ 'power.sh', action || '', 'confirm' ] ) } ); } ); } @@ -1295,7 +1294,9 @@ function loader( fader ) { $( '#loader' ).removeClass( 'hide' ); } function loaderHide() { - if ( ! V.reboot ) $( '#loader' ).addClass( 'hide' ); + if ( 'off' in V || 'reboot' in V ) return + + $( '#loader' ).addClass( 'hide' ); } // ---------------------------------------------------------------------- diff --git a/srv/http/assets/js/passive.js b/srv/http/assets/js/passive.js index 37b29f299..e1f5bd482 100644 --- a/srv/http/assets/js/passive.js +++ b/srv/http/assets/js/passive.js @@ -71,6 +71,8 @@ W = { eqOptionPreset(); } , mpdplayer : data => { + if ( 'off' in V || 'reboot' in V ) return + clearTimeout( V.debounce ); V.debounce = setTimeout( () => { if ( ! data.control && data.volume == -1 ) { // fix - upmpdcli missing values on stop/pause diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index 995e2a887..201b53069 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -268,7 +268,7 @@ logoLcdOled() { [[ -e $dirsystem/lcdchar ]] && $dirbash/lcdchar.py logo if [[ -e $dirsystem/mpdoled ]]; then chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) - mpd_oled -o $chip -L + mpd_oled -o $chip -x logo fi } mountpointSet() { diff --git a/srv/http/bash/power.sh b/srv/http/bash/power.sh index 392e8cae4..b2cd2fd71 100644 --- a/srv/http/bash/power.sh +++ b/srv/http/bash/power.sh @@ -2,9 +2,6 @@ . /srv/http/bash/common.sh -$dirbash/cmd.sh playerstop - -[[ -e $dirshm/relayson ]] && $dirbash/relays.sh off if [[ $1 == reboot ]]; then reboot=1 audioCDplClear && $dirbash/status-push.sh @@ -14,8 +11,9 @@ else audioCDplClear pushData power '{ "type": "off" }' fi - -playerActive upnp && $dirbash/cmd.sh playerstop +$dirbash/cmd.sh playerstop +logoLcdOled +[[ -e $dirshm/relayson ]] && $dirbash/relays.sh off if systemctl -q is-active nfs-server; then # server rAudio ipserver=$( ipAddress ) @@ -35,8 +33,6 @@ fi [[ -e $dirshm/btreceiver ]] && cp $dirshm/btreceiver $dirsystem touch $dirshm/power -logoLcdOled - snapclientIP playerstop cdda=$( mpc -f %file%^%position% playlist | grep ^cdda: | cut -d^ -f2 ) [[ $cdda ]] && mpc -q del $cdda diff --git a/srv/http/bash/settings/data-config.sh b/srv/http/bash/settings/data-config.sh index 37f6b79ef..579b2d9c1 100644 --- a/srv/http/bash/settings/data-config.sh +++ b/srv/http/bash/settings/data-config.sh @@ -96,10 +96,10 @@ localbrowser ) }' ;; mpdoled ) - file=/etc/default/mpd_oled - chip=$( cut -d' ' -f2 $file ) - baud=$( grep baudrate /boot/config.txt | cut -d= -f3 ) - spectrum=$( grep -q '\-A' $file && echo false || echo true ) + opt=$( < /etc/default/mpd_oled ) + chip=$( cut -d' ' -f2 <<< $opt ) + spectrum=$( grep -q '\-X' <<< $opt && echo true || echo false ) + baud=$( sed -n '/baudrate/ {s/.*=//; p}' /boot/config.txt ) [[ ! $baud ]] && baud=800000 echo '{ "CHIP": "'$chip'", "BAUD": '$baud', "SPECTRUM": '$spectrum' }' ;; diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 3efd9cf85..8d29fd810 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -243,25 +243,23 @@ mountunmount ) pushRefresh ;; mpdoled ) - filedef=/etc/default/mpd_oled - chip=$( cut -d' ' -f2 $filedef ) + opt=$( sed 's/ -X//' /etc/default/mpd_oled ) + chip=$( cut -d' ' -f2 <<< $opt ) + baud=$( sed -n '/baudrate/ {s/.*=//; p}' /boot/config.txt ) if ! systemctl -q is-active mpd_oled; then - mpd_oled -o $chip -L + mpd_oled -o $chip -x logo ( [[ $ON ]] && sleep 10 || sleep 1 - mpd_oled -o $chip -X + mpd_oled -o $chip -x sleep ) & fi # -------------------------------------------------------------------- enableFlagSet if [[ $ON ]]; then - ! grep -q '\-A' $filedef && spectrum=1 - if [[ $SPECTRUM ]]; then - [[ ! $spectrum ]] && sed -i 's/ -A//' $filedef - else - [[ $spectrum ]] && sed -i 's/"$/ -A"/' $filedef - fi - [[ $chip != $CHIP ]] && sed -i 's/-o ./-o '$CHIP'/' $filedef + [[ $baud != $BAUD ]] && sed -i -E 's/(baudrate=).*/\1'$BAUD'/' /boot/config.txt + [[ $SPECTRUM ]] && opt=$( sed 's/"$/ -X"/' <<< $opt ) + [[ $chip != $CHIP ]] && opt=$( sed 's/-o ./-o '$CHIP'/' <<< $opt ) + echo "$opt" > /etc/default/mpd_oled ln -sf $dirmpdconf/{conf/,}fifo.conf else rm -f $dirmpdconf/fifo.conf @@ -274,10 +272,10 @@ mpdoledlogo ) systemctl -q is-active mpd_oled && active=1 systemctl stop mpd_oled chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) - mpd_oled -o $chip -L + mpd_oled -o $chip -x logo ( sleep 10 - grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -X + grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -x sleep ) & ;; ntp ) From 63c8aedcf84be8f1c428d65e7be2f2243d9cb08b Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 6 Jan 2025 20:12:52 +0700 Subject: [PATCH 59/88] u --- install.sh | 5 +++-- srv/http/bash/common.sh | 2 ++ srv/http/bash/status-push.sh | 1 + srv/http/bash/status-radio.sh | 2 -- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index 5f95aaa1b..bb79e21c7 100644 --- a/install.sh +++ b/install.sh @@ -5,9 +5,10 @@ alias=r1 . /srv/http/bash/settings/addons.sh # 20250110 -if ! pacman -Q mpd_oled &> /dev/nul; then +file=/etc/systemd/system/mpd_oled.service +if [[ -e $file ]]; then + rm -f $file pacman -R --noconfirm audio_spectrum_oled &> /dev/null - rm -f /etc/systemd/system/mpd_oled.service pacman -Sy --noconfirm mpd_oled fi diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index 201b53069..1d130d20f 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -393,6 +393,8 @@ elapsed='$elapsed' pllength='$pllength' state="play" Title="'$title'"' + [[ -e $dirsystem/mpdoled ]] && status+=' +volume='$( volumeGet ) echo "$status" > $dirshm/status $dirbash/status-push.sh statusradio & # for snapcast ssh - for: mpdoled, lcdchar, vumeter, snapclient(need to run in background) } diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index 84821755d..3fb25016f 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -15,6 +15,7 @@ else for k in Artist Album Composer elapsed file player station state Time timestamp Title webradio; do filter+='|^ "'$k done + [[ -e $dirsystem/mpdoled ]] && filter+='|^ "volume"' statuslines=$( grep -E "${filter:1}" <<< $status ) statusnew=$( sed -E 's/^ *"|,$//g; s/" *: */=/' <<< $statuslines | tee $dirshm/statusnew ) statusprev=$( < $dirshm/status ) diff --git a/srv/http/bash/status-radio.sh b/srv/http/bash/status-radio.sh index a1a2dcafa..89644fd7f 100644 --- a/srv/http/bash/status-radio.sh +++ b/srv/http/bash/status-radio.sh @@ -112,8 +112,6 @@ $( jq -r .albumTitle <<< $track )" title=$( quoteEscape ${metadata[1]} ) album=$( quoteEscape ${metadata[2]} ) coverurl=${metadata[3]} - jq .steps[$item] <<< $json - echo "$artist - $title - $album - $coverurl" if [[ ! $title || "$artist $title $album" == $dataprev ]]; then sleep 5 From b5d007b6ad4bc5761ee666563e90c81948561259 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 6 Jan 2025 20:54:53 +0700 Subject: [PATCH 60/88] Update system.sh --- srv/http/bash/settings/system.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 8d29fd810..67d274f35 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -246,6 +246,7 @@ mpdoled ) opt=$( sed 's/ -X//' /etc/default/mpd_oled ) chip=$( cut -d' ' -f2 <<< $opt ) baud=$( sed -n '/baudrate/ {s/.*=//; p}' /boot/config.txt ) + [[ ! $ON ]] && systemctl stop mpd_oled if ! systemctl -q is-active mpd_oled; then mpd_oled -o $chip -x logo ( @@ -255,18 +256,28 @@ mpdoled ) fi # -------------------------------------------------------------------- enableFlagSet + filefifo=$dirmpdconf/fifo.conf if [[ $ON ]]; then [[ $baud != $BAUD ]] && sed -i -E 's/(baudrate=).*/\1'$BAUD'/' /boot/config.txt [[ $SPECTRUM ]] && opt=$( sed 's/"$/ -X"/' <<< $opt ) [[ $chip != $CHIP ]] && opt=$( sed 's/-o ./-o '$CHIP'/' <<< $opt ) echo "$opt" > /etc/default/mpd_oled - ln -sf $dirmpdconf/{conf/,}fifo.conf + if [[ ! -e $filefifo ]]; then + ln -s $dirmpdconf/{conf/,}fifo.conf + restartmpd=1 + fi else - rm -f $dirmpdconf/fifo.conf + if [[ -e $filefifo ]]; then + rm $filefifo + restartmpd=1 + fi fi i2cset=1 configTxt - systemctl try-restart mpd mpd_oled + [[ $restartmpd ]] && systemctl restart mpd + if [[ $ON ]]; then + grep -q ^state.*play $dirshm/status && systemctl restart mpd_oled + fi ;; mpdoledlogo ) systemctl -q is-active mpd_oled && active=1 From 74ea71c0bbdfa17876d91484ebf9e0d9ed86c6d1 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 6 Jan 2025 21:43:10 +0700 Subject: [PATCH 61/88] Update system.sh --- srv/http/bash/settings/system.sh | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 67d274f35..611e272e1 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -246,17 +246,14 @@ mpdoled ) opt=$( sed 's/ -X//' /etc/default/mpd_oled ) chip=$( cut -d' ' -f2 <<< $opt ) baud=$( sed -n '/baudrate/ {s/.*=//; p}' /boot/config.txt ) - [[ ! $ON ]] && systemctl stop mpd_oled - if ! systemctl -q is-active mpd_oled; then - mpd_oled -o $chip -x logo - ( - [[ $ON ]] && sleep 10 || sleep 1 - mpd_oled -o $chip -x sleep - ) & - fi -# -------------------------------------------------------------------- enableFlagSet filefifo=$dirmpdconf/fifo.conf + if ls /dev/i2c* &> /dev/null; then + i2cactive=1 + [[ ! $CHIP ]] && CHIP=$chip + systemctl stop mpd_oled + mpd_oled -o $CHIP -x logo + fi if [[ $ON ]]; then [[ $baud != $BAUD ]] && sed -i -E 's/(baudrate=).*/\1'$BAUD'/' /boot/config.txt [[ $SPECTRUM ]] && opt=$( sed 's/"$/ -X"/' <<< $opt ) @@ -275,17 +272,23 @@ mpdoled ) i2cset=1 configTxt [[ $restartmpd ]] && systemctl restart mpd - if [[ $ON ]]; then - grep -q ^state.*play $dirshm/status && systemctl restart mpd_oled + [[ ! $i2cactive ]] && exit +# -------------------------------------------------------------------- + if [[ $ON ]] && grep -q ^state.*play $dirshm/status; then + systemctl restart mpd_oled + else + [[ $ON ]] && sleep 3 + mpd_oled -o $CHIP -x sleep fi ;; mpdoledlogo ) - systemctl -q is-active mpd_oled && active=1 + ! ls /dev/i2c* &> /dev/null && exit + systemctl stop mpd_oled chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) mpd_oled -o $chip -x logo ( - sleep 10 + sleep 3 grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -x sleep ) & ;; From f85834e9720118c85da2608db5f1cc7590980a79 Mon Sep 17 00:00:00 2001 From: rern Date: Mon, 6 Jan 2025 21:45:58 +0700 Subject: [PATCH 62/88] Update system.sh --- srv/http/bash/settings/system.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 611e272e1..2fffcde24 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -277,8 +277,8 @@ mpdoled ) if [[ $ON ]] && grep -q ^state.*play $dirshm/status; then systemctl restart mpd_oled else - [[ $ON ]] && sleep 3 - mpd_oled -o $CHIP -x sleep + ( [[ $ON ]] && sleep 3 + mpd_oled -o $CHIP -x sleep ) & fi ;; mpdoledlogo ) @@ -287,10 +287,8 @@ mpdoledlogo ) systemctl stop mpd_oled chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) mpd_oled -o $chip -x logo - ( - sleep 3 - grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -x sleep - ) & + ( sleep 3 + grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -x sleep ) & ;; ntp ) echo "\ From 688fdf035d4550a2d2efc325acd7d970e2803a4f Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 7 Jan 2025 08:03:25 +0700 Subject: [PATCH 63/88] u --- srv/http/assets/css/common.css | 3 ++- srv/http/assets/js/system.js | 24 +++---------------- srv/http/bash/settings/system.sh | 41 +++++++------------------------- 3 files changed, 14 insertions(+), 54 deletions(-) diff --git a/srv/http/assets/css/common.css b/srv/http/assets/css/common.css index 645c34c07..9b4710277 100644 --- a/srv/http/assets/css/common.css +++ b/srv/http/assets/css/common.css @@ -10,7 +10,7 @@ @font-face { font-family : rern; - src : url( '/assets/fonts/rern.woff2?v=1735640241' ); + src : url( '/assets/fonts/rern.woff2?v=1735997122' ); } @font-face { font-family : Lato; @@ -427,6 +427,7 @@ code { text-overflow: ellipsis; } #bannerTitle { + line-height: 22px; font-size: 18px; font-weight: 300; } diff --git a/srv/http/assets/js/system.js b/srv/http/assets/js/system.js index 811233f73..3b7cec664 100644 --- a/srv/http/assets/js/system.js +++ b/srv/http/assets/js/system.js @@ -1,5 +1,5 @@ -W.reboot = id => { - banner( id, $( '#div'+ id +' .col-l .label' ).text(), 'Reboot required', 5000 ); +W.reboot = data => { + banner( data.id, $( '#div'+ data.id +' .col-l .label' ).text(), 'Reboot required', 5000 ); } W.storage = data => { clearTimeout( V.debounce ); @@ -148,7 +148,6 @@ var config = { , [ 'Refresh (baud)', 'select', { kv: { '800,000': 800000, '1,000,000': 1000000, '1,200,000': 1200000 } } ] , [ 'Spectrum only', 'checkbox' ] ] - , footer : ''+ ico( 'raudio' ) +'Logo' , values : values , checkchanged : S.mpdoled , boxwidth : 140 @@ -156,12 +155,6 @@ var config = { var $tr = $( '#infoList tr' ); var $baud = $tr.eq( 1 ) $baud.toggleClass( 'hide', S.mpdoled && ( values.CHIP < 3 || values.CHIP > 6 ) ); - $( '.infofooter span' ) - .toggleClass( 'disabled', ! S.mpdoled ) - .on( 'click', function() { - bash( [ 'mpdoledlogo' ] ); - $( '#infoX' ).trigger( 'click' ); - } ); $tr.eq( 0 ).on( 'input', function() { var val = this.value; $baud.toggleClass( 'hide', val < 3 || val > 6 ); @@ -380,18 +373,7 @@ var util = { icon : 'lcdchar' , title : 'Character LCD' , tablabel : [ 'I²C', 'GPIO' ] - , footer : infoFooterIcon( { - Logo : 'raudio' - , Sleep : 'screenoff' - } ) - , beforeshow : () => { - $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ); - $( '.infofooter span' ) - .toggleClass( 'disabled', ! S.lcdchar ) - .on( 'click', function() { - bash( [ 'lcdchar', $( this ).index() ? 'off' : 'logo', 'CMD ACTION' ] ); - } ); - } + , beforeshow : () => $( '#infoList label' ).parents( 'td' ).prop( 'colspan', 3 ) , cancel : switchCancel , ok : () => { jsonSave( 'lcdchar', infoVal() ); diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index 2fffcde24..ee6da32c2 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -67,7 +67,7 @@ dtoverlay=gpio-shutdown,gpio_pin=17,active_low=0,gpio_pull=down" fi fi if [[ $reboot ]]; then - pushData reboot $CMD + pushData reboot '{ "id": "'$CMD'" }' appendSortUnique $CMD $dirshm/reboot elif [[ -e $dirshm/reboot ]]; then sed -i "/$CMD/ d" $dirshm/reboot @@ -243,52 +243,29 @@ mountunmount ) pushRefresh ;; mpdoled ) - opt=$( sed 's/ -X//' /etc/default/mpd_oled ) - chip=$( cut -d' ' -f2 <<< $opt ) - baud=$( sed -n '/baudrate/ {s/.*=//; p}' /boot/config.txt ) enableFlagSet filefifo=$dirmpdconf/fifo.conf - if ls /dev/i2c* &> /dev/null; then - i2cactive=1 - [[ ! $CHIP ]] && CHIP=$chip - systemctl stop mpd_oled - mpd_oled -o $CHIP -x logo - fi if [[ $ON ]]; then - [[ $baud != $BAUD ]] && sed -i -E 's/(baudrate=).*/\1'$BAUD'/' /boot/config.txt - [[ $SPECTRUM ]] && opt=$( sed 's/"$/ -X"/' <<< $opt ) + opt=$( sed 's/ -X//' /etc/default/mpd_oled ) + chip=$( cut -d' ' -f2 <<< $opt ) + baud=$( sed -n '/baudrate/ {s/.*=//; p}' /boot/config.txt ) [[ $chip != $CHIP ]] && opt=$( sed 's/-o ./-o '$CHIP'/' <<< $opt ) + [[ $SPECTRUM ]] && opt=$( sed 's/"$/ -X"/' <<< $opt ) + [[ $baud != $BAUD ]] && sed -i -E 's/(baudrate=).*/\1'$BAUD'/' /boot/config.txt echo "$opt" > /etc/default/mpd_oled if [[ ! -e $filefifo ]]; then ln -s $dirmpdconf/{conf/,}fifo.conf - restartmpd=1 + systemctl restart mpd fi else if [[ -e $filefifo ]]; then rm $filefifo - restartmpd=1 + systemctl restart mpd fi fi i2cset=1 configTxt - [[ $restartmpd ]] && systemctl restart mpd - [[ ! $i2cactive ]] && exit -# -------------------------------------------------------------------- - if [[ $ON ]] && grep -q ^state.*play $dirshm/status; then - systemctl restart mpd_oled - else - ( [[ $ON ]] && sleep 3 - mpd_oled -o $CHIP -x sleep ) & - fi - ;; -mpdoledlogo ) - ! ls /dev/i2c* &> /dev/null && exit - - systemctl stop mpd_oled - chip=$( cut -d' ' -f2 /etc/default/mpd_oled ) - mpd_oled -o $chip -x logo - ( sleep 3 - grep -q ^state.*play $dirshm/status && systemctl start mpd_oled || mpd_oled -o $chip -x sleep ) & + systemctl try-restart mpd_oled ;; ntp ) echo "\ From 66b3c00af889a9538405c5695390fde788ee411b Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 7 Jan 2025 09:36:36 +0700 Subject: [PATCH 64/88] Update common.sh --- srv/http/bash/common.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index 1d130d20f..201b53069 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -393,8 +393,6 @@ elapsed='$elapsed' pllength='$pllength' state="play" Title="'$title'"' - [[ -e $dirsystem/mpdoled ]] && status+=' -volume='$( volumeGet ) echo "$status" > $dirshm/status $dirbash/status-push.sh statusradio & # for snapcast ssh - for: mpdoled, lcdchar, vumeter, snapclient(need to run in background) } From cf02ff13d4e3127f4bc423b3b481bd4d1726185a Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 7 Jan 2025 09:44:52 +0700 Subject: [PATCH 65/88] Update status-push.sh --- srv/http/bash/status-push.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/srv/http/bash/status-push.sh b/srv/http/bash/status-push.sh index 3fb25016f..ca050b998 100644 --- a/srv/http/bash/status-push.sh +++ b/srv/http/bash/status-push.sh @@ -12,10 +12,9 @@ if [[ $1 == statusradio ]]; then # from status-radio.sh radioStatusFile statusradio=1 else status=$( $dirbash/status.sh | jq ) - for k in Artist Album Composer elapsed file player station state Time timestamp Title webradio; do - filter+='|^ "'$k + for k in Artist Album Composer Conductor elapsed file player station state Time timestamp Title volume webradio; do + filter+='|^ "'$k'"' done - [[ -e $dirsystem/mpdoled ]] && filter+='|^ "volume"' statuslines=$( grep -E "${filter:1}" <<< $status ) statusnew=$( sed -E 's/^ *"|,$//g; s/" *: */=/' <<< $statuslines | tee $dirshm/statusnew ) statusprev=$( < $dirshm/status ) From c07e7ea9bd75ce27eadf213ddf365777a8298243 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 7 Jan 2025 20:17:24 +0700 Subject: [PATCH 66/88] Update common.js --- srv/http/assets/js/common.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/srv/http/assets/js/common.js b/srv/http/assets/js/common.js index 1048391d5..234112300 100644 --- a/srv/http/assets/js/common.js +++ b/srv/http/assets/js/common.js @@ -178,7 +178,7 @@ function banner( icon, title, message, delay ) { }, delay || 3000 ); } function bannerHide() { - if ( V.bannerdelay || V.reboot || V.relays || $( '#banner .i-warning' ).length ) return + if ( V.bannerdelay || V.relays ) return $( '#banner' ) .addClass( 'hide' ) @@ -1452,8 +1452,11 @@ function websocketConnect( ip ) { if ( data === 'pong' ) { // on pageActive - reload if ws not response V.timeoutreload = false; } else { - var json = JSON.parse( data ); - if ( json.channel in W ) W[ json.channel ]( json.data ); + var json = JSON.parse( data ); + var channel = json.channel; + if ( V.off || V.reboot ) return + + if ( channel in W ) W[ channel ]( json.data ); } } } From e06a5be4a7e3f6e0f5cdaf4ff1aa9d9708b37567 Mon Sep 17 00:00:00 2001 From: rern Date: Tue, 7 Jan 2025 21:28:47 +0700 Subject: [PATCH 67/88] Update common.js --- srv/http/assets/js/common.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/srv/http/assets/js/common.js b/srv/http/assets/js/common.js index 234112300..158964189 100644 --- a/srv/http/assets/js/common.js +++ b/srv/http/assets/js/common.js @@ -63,7 +63,7 @@ W = { // ws push $( '#loader' ).css( 'opacity', 1 ); setTimeout( () => { $( '#loader svg' ).css( 'animation', 'none' ); - bannerHide(); + $( '#banner' ).addClass( 'hide' ); }, 10000 ); } else { // reconnect after reboot setTimeout( websocketReconnect, data.startup + 5000 ); // add shutdown 5s @@ -178,7 +178,7 @@ function banner( icon, title, message, delay ) { }, delay || 3000 ); } function bannerHide() { - if ( V.bannerdelay || V.relays ) return + if ( V.bannerdelay || V.relays || V.reboot || V.off ) return $( '#banner' ) .addClass( 'hide' ) @@ -1454,8 +1454,6 @@ function websocketConnect( ip ) { } else { var json = JSON.parse( data ); var channel = json.channel; - if ( V.off || V.reboot ) return - if ( channel in W ) W[ channel ]( json.data ); } } From ee950345eb0310a709a5edbfd967f6d1a446149e Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 8 Jan 2025 16:40:17 +0700 Subject: [PATCH 68/88] u --- srv/http/assets/js/function.js | 11 +++-------- srv/http/assets/js/passive.js | 6 +++++- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 4e7889655..2ed12efa8 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -1811,20 +1811,15 @@ function setPlaylistScroll() { $stationname.removeClass( 'hide' ); $name.html( S.Title || dots ); if ( S.coverart && S.coverart !== S.stationcover ) { - $liactive.find( 'img' ).on( 'lazyloaded', setPlaylistWebRadioCoverart ); // fix - lazysizes load stationcover - setPlaylistWebRadioCoverart(); // lazysizes already loaded + $liactive.find( 'img' ).on( 'lazyloaded', () => { + $( '#pl-list li.active img' ).attr( 'src', S.coverart ); + } ); } } setProgressElapsed(); } } } -function setPlaylistWebRadioCoverart() { - var coverart = S.state === 'play' ? S.coverart + versionHash() : S.stationcover; - $( '#pl-list li.active img' ) - .data( 'src', coverart ) - .attr( 'src', coverart); -} function setPlayPauseColor() { var pause = S.state === 'pause'; $( '#title' ).toggleClass( 'gr', pause ); diff --git a/srv/http/assets/js/passive.js b/srv/http/assets/js/passive.js index e1f5bd482..5673945f2 100644 --- a/srv/http/assets/js/passive.js +++ b/srv/http/assets/js/passive.js @@ -101,7 +101,11 @@ W = { setProgress( 0 ); setBlinkDot(); } - setPlaylistScroll(); + if ( V.playlist ) { + var $liactive = $( '#pl-list li.active' ); + $liactive.find( '.name' ).text( S.Title ); + $liactive.find( 'img' ).attr( 'src', S.coverart ); + } } , mpdupdate : data => { if ( 'counts' in data ) { From be442ceda547c09b37919bc0c5be44fd06e1b798 Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 8 Jan 2025 18:01:28 +0700 Subject: [PATCH 69/88] u --- srv/http/assets/css/main.css | 3 +++ srv/http/assets/js/function.js | 26 +++++++++++--------------- srv/http/playlist.php | 4 ++-- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/srv/http/assets/css/main.css b/srv/http/assets/css/main.css index 16f81efaa..5f6938257 100644 --- a/srv/http/assets/css/main.css +++ b/srv/http/assets/css/main.css @@ -1795,6 +1795,9 @@ li.active .li1 bl { font-size: 14px !important; color: var( --cg60 ); } +.li2 .stationname::after { + content: ' • '; +} #pl-savedlist .li2 { max-width: 100%; } diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 2ed12efa8..a66872be9 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -1778,7 +1778,6 @@ function setPlaylistScroll() { $( '#pl-list li' ).removeClass( 'active pause play updn' ); $liactive = $( '#pl-list li' ).eq( S.song ); $liactive.addClass( 'active' ); - S.webradio = $liactive.hasClass( 'webradio' ); if ( ! $( '.pl-remove' ).length && ! I.active ) { if ( $( '#pl-list li' ).length < 5 ) { var top = 0; @@ -1791,13 +1790,19 @@ function setPlaylistScroll() { var $elapsed = $liactive.find( '.elapsed' ); var $name = $liactive.find( '.li1 .name' ); var $stationname = $liactive.find( '.li2 .stationname' ); - $stationname.addClass( 'hide' ); - if ( S.state === 'stop' || S.player === 'snapcast' ) { + if ( S.state === 'stop' ) { if ( S.webradio ) { - $name.text( $liactive.find( '.liname' ).text() ); - setPlaylistWebRadioCoverart(); + var $img = $( '#pl-list li.active img' ); + $img.attr( 'src', $img.data( 'src' ) ); + $name.text( $stationname.text() ); + $stationname.addClass( 'hide' ); } } else { + if ( S.webradio && S.state === 'play' ) { + $stationname.removeClass( 'hide' ); + $name.html( S.Title || dots ); + if ( S.coverart && S.coverart !== S.stationcover ) $( '#pl-list li.active img' ).attr( 'src', S.coverart ); + } if ( S.elapsed === false ) return $liactive.addClass( S.state ); @@ -1806,16 +1811,7 @@ function setPlaylistScroll() { elapsedtxt = second2HMS( S.elapsed ); $elapsed.text( elapsedtxt ); setPlaylistInfoWidth(); - } else if ( S.state === 'play' ) { - if ( S.webradio ) { - $stationname.removeClass( 'hide' ); - $name.html( S.Title || dots ); - if ( S.coverart && S.coverart !== S.stationcover ) { - $liactive.find( 'img' ).on( 'lazyloaded', () => { - $( '#pl-list li.active img' ).attr( 'src', S.coverart ); - } ); - } - } + } else { setProgressElapsed(); } } diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 4f30a3726..8ff0eb3f4 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -187,13 +187,13 @@ function output() { $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); } $classnotsaved = $notsaved ? ' notsaved' : ''; - $namenotsaved = $notsaved ? '' : $stationname.' • '; + $namenotsaved = $notsaved ? '' : $stationname; $url = preg_replace( '/#charset=.*/', '', $file ); $path = preg_replace( '/\?.*$/', '', $file ); $html .= '
  • '. ''.$path.''. - $icon.''.$stationname.'
  • From bd257a49d88ae0a69a8ff55e6e2991bc8ab3b54d Mon Sep 17 00:00:00 2001 From: rern Date: Wed, 8 Jan 2025 20:32:45 +0700 Subject: [PATCH 70/88] u --- srv/http/assets/css/main.css | 4 +- srv/http/assets/js/function.js | 71 ++++++++++++++++++++-------------- srv/http/assets/js/main.js | 11 ++---- srv/http/assets/js/passive.js | 6 +-- srv/http/playlist.php | 30 +++++++------- 5 files changed, 65 insertions(+), 57 deletions(-) diff --git a/srv/http/assets/css/main.css b/srv/http/assets/css/main.css index 5f6938257..9f5a565a2 100644 --- a/srv/http/assets/css/main.css +++ b/srv/http/assets/css/main.css @@ -1795,7 +1795,9 @@ li.active .li1 bl { font-size: 14px !important; color: var( --cg60 ); } -.li2 .stationname::after { +.li2 .album::before, +.li2 .station::before, +.li2 .url::before { content: ' • '; } #pl-savedlist .li2 { diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index a66872be9..09e5e58be 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -1762,6 +1762,37 @@ function setPlaylistInfoWidth() { var cW = document.body.clientWidth; $title.css( 'max-width', iWdW + titleW < cW ? '' : cW - iWdW ); } +function setPlaylistRadioInfo( stop ) { + var $liactive = $( '#pl-list li.active' ); + var $img = $liactive.find( 'img' ); + var $name = $liactive.find( '.name' ); + var $li2 = $liactive.find( '.li2' ); + var $station = $li2.find( '.station' ); + var $album = $li2.find( '.album' ); + var $url = $li2.find( '.url' ); + if ( S.state === 'stop' || stop ) { + $img.attr( 'src', $img.data( 'src' ) ); + $name.text( $station.text() ); + $station.addClass( 'hide' ); + $album.addClass( 'hide' ); + $url.removeClass( 'hide' ); + } else { + if ( S.coverart ) $img + .removeClass( 'lazyload' ) + .attr( 'src', S.coverart ); + $name.html( S.Title || dots ); + if ( S.Album ) { + $album + .text( S.Album ) + .removeClass( 'hide' ); + $url.addClass( 'hide' ); + } else { + $album.addClass( 'hide' ); + $url.removeClass( 'hide' ); + } + $station.removeClass( 'hide' ); + } +} function setPlaylistScroll() { if ( ! V.playlist || ! V.playlisthome ) return @@ -1773,10 +1804,10 @@ function setPlaylistScroll() { return } - var litop = barVisible( 80, 40 ); + var litop = barVisible( 80, 40 ); $( '#menu-plaction' ).addClass( 'hide' ); $( '#pl-list li' ).removeClass( 'active pause play updn' ); - $liactive = $( '#pl-list li' ).eq( S.song ); + var $liactive = $( '#pl-list li' ).eq( S.song ); $liactive.addClass( 'active' ); if ( ! $( '.pl-remove' ).length && ! I.active ) { if ( $( '#pl-list li' ).length < 5 ) { @@ -1787,33 +1818,17 @@ function setPlaylistScroll() { pageScroll( top ); } $( '#pl-list .elapsed' ).empty(); - var $elapsed = $liactive.find( '.elapsed' ); - var $name = $liactive.find( '.li1 .name' ); - var $stationname = $liactive.find( '.li2 .stationname' ); - if ( S.state === 'stop' ) { - if ( S.webradio ) { - var $img = $( '#pl-list li.active img' ); - $img.attr( 'src', $img.data( 'src' ) ); - $name.text( $stationname.text() ); - $stationname.addClass( 'hide' ); - } + if ( S.webradio ) setPlaylistRadioInfo(); + if ( S.elapsed === false ) return + + $liactive.addClass( S.state ); + if ( S.player === 'upnp' ) $liactive.find( '.time' ).text( second2HMS( S.Time ) ); + if ( S.state === 'pause' ) { + elapsedtxt = second2HMS( S.elapsed ); + $liactive.find( '.elapsed' ).text( elapsedtxt ); + setPlaylistInfoWidth(); } else { - if ( S.webradio && S.state === 'play' ) { - $stationname.removeClass( 'hide' ); - $name.html( S.Title || dots ); - if ( S.coverart && S.coverart !== S.stationcover ) $( '#pl-list li.active img' ).attr( 'src', S.coverart ); - } - if ( S.elapsed === false ) return - - $liactive.addClass( S.state ); - if ( S.player === 'upnp' ) $liactive.find( '.time' ).text( second2HMS( S.Time ) ); - if ( S.state === 'pause' ) { - elapsedtxt = second2HMS( S.elapsed ); - $elapsed.text( elapsedtxt ); - setPlaylistInfoWidth(); - } else { - setProgressElapsed(); - } + setProgressElapsed(); } } function setPlayPauseColor() { diff --git a/srv/http/assets/js/main.js b/srv/http/assets/js/main.js index 07e2b1c1d..ad5c41ad8 100644 --- a/srv/http/assets/js/main.js +++ b/srv/http/assets/js/main.js @@ -1834,18 +1834,13 @@ $( '#pl-list' ).on( 'click', 'li', function( e ) { var $liactive = $( '#pl-list li.active' ); $( '#menu-plaction' ).addClass( 'hide' ); $liactive.find( '.song' ).empty(); - if ( $liactive.hasClass( 'webradio' ) ) { - if ( S.state == 'play' ) { - $liactive.find( '.li1 .name' ).text( $liactive.find( '.liname' ).text() ); - $liactive.find( '.li2 .stationname' ).addClass( 'hide' ); - $liactive.find( '.li2 .name' ).removeClass( 'hide' ); - } - } if ( $this.hasClass( 'active' ) ) { if ( S.state === 'play' ) { if ( S.webradio ) { + $liactive.removeClass( 'play' ); + $liactive.find( '.elapsed' ).empty(); + setPlaylistRadioInfo( 'stop' ); $( '#stop' ).trigger( 'click' ); - $this.find( '.elapsed' ).empty(); } else { $( '#pause' ).trigger( 'click' ); $this.find( '.elapsed i' ).toggleClass( 'i-play i-pause' ); diff --git a/srv/http/assets/js/passive.js b/srv/http/assets/js/passive.js index 5673945f2..25859878c 100644 --- a/srv/http/assets/js/passive.js +++ b/srv/http/assets/js/passive.js @@ -101,11 +101,7 @@ W = { setProgress( 0 ); setBlinkDot(); } - if ( V.playlist ) { - var $liactive = $( '#pl-list li.active' ); - $liactive.find( '.name' ).text( S.Title ); - $liactive.find( 'img' ).attr( 'src', S.coverart ); - } + if ( V.playlist ) setPlaylistRadioInfo(); } , mpdupdate : data => { if ( 'counts' in data ) { diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 8ff0eb3f4..b5c1b9a14 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -169,33 +169,33 @@ function output() { $count->upnp++; } else { if ( str_contains( $file, '://' ) ) { // webradio / dabradio - $urlname = str_replace( '/', '|', $file ); - $radio = str_contains( $file, ':8554' ) ? 'dabradio' : 'webradio'; - $fileradio = '/srv/http/data/'.$radio.'/'.$urlname; + $urlname = str_replace( '/', '|', $file ); + $radio = str_contains( $file, ':8554' ) ? 'dabradio' : 'webradio'; + $fileradio = '/srv/http/data/'.$radio.'/'.$urlname; if ( ! file_exists( $fileradio ) ) $fileradio = exec( 'find /srv/http/data/'.$radio.'/ -name "'.$urlname.'" | head -1' ); - $stationname = $fileradio ? exec( 'head -1 "'.$fileradio.'"' ) : ''; + $station = $fileradio ? exec( 'head -1 "'.$fileradio.'"' ) : ''; } else { - $urlname = str_replace( '#', '%23', $urlname ); - $stationname = ''; + $urlname = str_replace( '#', '%23', $urlname ); + $station = ''; } - if ( $stationname !== '' ) { - $notsaved = 0; - $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; - $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); + if ( $station !== '' ) { + $notsaved = 0; + $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; + $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); } else { - $notsaved = 1; - $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); + $notsaved = 1; + $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); } $classnotsaved = $notsaved ? ' notsaved' : ''; - $namenotsaved = $notsaved ? '' : $stationname; + $namenotsaved = $notsaved ? '' : $station; $url = preg_replace( '/#charset=.*/', '', $file ); $path = preg_replace( '/\?.*$/', '', $file ); $html .= '
  • '. ''.$path.''. - $icon.'
  • '; $count->radio++; From 0a9a78282e758e6b07ce5ccf3f4d8815033ae12e Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 08:21:31 +0700 Subject: [PATCH 71/88] u --- srv/http/assets/css/main.css | 6 +++--- srv/http/assets/js/function.js | 12 ++++++------ srv/http/playlist.php | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/srv/http/assets/css/main.css b/srv/http/assets/css/main.css index 9f5a565a2..f3297144b 100644 --- a/srv/http/assets/css/main.css +++ b/srv/http/assets/css/main.css @@ -1795,9 +1795,9 @@ li.active .li1 bl { font-size: 14px !important; color: var( --cg60 ); } -.li2 .album::before, -.li2 .station::before, -.li2 .url::before { +li.webradio .artist::before, +li.webradio .station::before, +li.webradio .url::before { content: ' • '; } #pl-savedlist .li2 { diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 09e5e58be..00b7c4b93 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -1768,26 +1768,26 @@ function setPlaylistRadioInfo( stop ) { var $name = $liactive.find( '.name' ); var $li2 = $liactive.find( '.li2' ); var $station = $li2.find( '.station' ); - var $album = $li2.find( '.album' ); + var $artist = $li2.find( '.artist' ); var $url = $li2.find( '.url' ); if ( S.state === 'stop' || stop ) { $img.attr( 'src', $img.data( 'src' ) ); $name.text( $station.text() ); $station.addClass( 'hide' ); - $album.addClass( 'hide' ); + $artist.addClass( 'hide' ); $url.removeClass( 'hide' ); } else { if ( S.coverart ) $img .removeClass( 'lazyload' ) .attr( 'src', S.coverart ); $name.html( S.Title || dots ); - if ( S.Album ) { - $album - .text( S.Album ) + if ( S.Artist ) { + $artist + .text( S.Artist + ( S.Album ? ' - '+ S.Album : '' ) ) .removeClass( 'hide' ); $url.addClass( 'hide' ); } else { - $album.addClass( 'hide' ); + $artist.addClass( 'hide' ); $url.removeClass( 'hide' ); } $station.removeClass( 'hide' ); diff --git a/srv/http/playlist.php b/srv/http/playlist.php index b5c1b9a14..4ef1df315 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -195,7 +195,7 @@ function output() { ''.$path.''. $icon.''. - ''. + ''. ' '; $count->radio++; From fe4f1283022f6f4d7cfa46a156fd070eab5c2c91 Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 10:49:32 +0700 Subject: [PATCH 72/88] u --- srv/http/bash/power.sh | 6 ++-- srv/http/playlist.php | 79 ++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 41 deletions(-) diff --git a/srv/http/bash/power.sh b/srv/http/bash/power.sh index b2cd2fd71..9377f7234 100644 --- a/srv/http/bash/power.sh +++ b/srv/http/bash/power.sh @@ -15,8 +15,8 @@ $dirbash/cmd.sh playerstop logoLcdOled [[ -e $dirshm/relayson ]] && $dirbash/relays.sh off +ipserver=$( ipAddress ) if systemctl -q is-active nfs-server; then # server rAudio - ipserver=$( ipAddress ) ipclients=$( grep -v $ipserver $filesharedip ) if [[ $ipclients ]]; then [[ ! $2 ]] && echo -1 && exit # $2 confirm proceed @@ -26,10 +26,8 @@ if systemctl -q is-active nfs-server; then # server rAudio notify -ip $ip 'networks blink' 'Server rAudio' "$msg" done fi - sed -i "/$ipserver/ d" $filesharedip -elif [[ -e $filesharedip ]]; then - sed -i "/$( ipAddress )/ d" $filesharedip fi +[[ -e $filesharedip ]] && sed -i "/$ipserver/ d" $filesharedip [[ -e $dirshm/btreceiver ]] && cp $dirshm/btreceiver $dirsystem touch $dirshm/power diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 4ef1df315..44061b19a 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -93,8 +93,8 @@ function output() { $pos++; $v = explode( '^^', $list ); for ( $i = 0; $i < $fL; $i++ ) ${$f[ $i ]} = $v[ $i ]; - $header = strtolower( substr( $file, 0, 4 ) ); - if ( ! in_array( $header, [ 'http', 'rtmp', 'rtp:', 'rtsp' ] ) ) { + $prefix = $file[ 0 ]; + if ( in_array( $prefix, [ 'U', 'N', 'S' ] ) ) { // USB, NAS, SD $sec = HMS2second( $time ); $li2 = ''; if ( $track ) { @@ -103,8 +103,9 @@ function output() { } $artist = $artist ?: $albumartist; $album = $album; - if ( $artist ) $li2.= ''.$artist.' - '; - if ( $album ) $li2.= ''.$album.''; + if ( $artist ) $li2.= ''.$artist.''; + if ( $artist && $album ) $li2.= ' - '; + if ( $album ) $li2.= ''.$album.''; if ( ! $artist && ! $album ) $li2.= $file; $datatrack = ''; if ( strpos( $file, '.cue/track' ) ) { @@ -151,46 +152,51 @@ function output() { '; $count->song++; $count->time += $sec; - } else if ( substr( $file, 0, 14 ) === 'http://192.168' ) { - $li2 = ''; - $artist = $artist; - $album = $album; - if ( $artist ) $li2.= ''.$artist.' - '; - if ( $album ) $li2.= ''.$album.''; + continue; + } + + $prefix = substr( $file, 0, 10 ); + if ( in_array( $prefix, [ 'http://192', 'http://127', 'http://loc' ] ) ) { // upnp + $li2 = ''; + if ( $artist ) $li2.= ''.$artist.''; + if ( $artist && $album ) $li2.= ' - '; + if ( $album ) $li2.= ''.$album.''; if ( ! $artist && ! $album ) $li2.= $file; - $html .= + $html .= '
  • '. i( 'upnp', 'filesavedpl' ). ''. - ''. + '
    '.$pos.' • '.$li2.'
    '. '
  • '; $count->upnp++; + continue; + } + // webradio / dabradio + if ( str_contains( $file, '://' ) ) { + $urlname = str_replace( '/', '|', $file ); + $radio = str_contains( $file, ':8554' ) ? 'dabradio' : 'webradio'; + $fileradio = '/srv/http/data/'.$radio.'/'.$urlname; + if ( ! file_exists( $fileradio ) ) $fileradio = exec( 'find /srv/http/data/'.$radio.'/ -name "'.$urlname.'" | head -1' ); + $station = $fileradio ? exec( 'head -1 "'.$fileradio.'"' ) : ''; } else { - if ( str_contains( $file, '://' ) ) { // webradio / dabradio - $urlname = str_replace( '/', '|', $file ); - $radio = str_contains( $file, ':8554' ) ? 'dabradio' : 'webradio'; - $fileradio = '/srv/http/data/'.$radio.'/'.$urlname; - if ( ! file_exists( $fileradio ) ) $fileradio = exec( 'find /srv/http/data/'.$radio.'/ -name "'.$urlname.'" | head -1' ); - $station = $fileradio ? exec( 'head -1 "'.$fileradio.'"' ) : ''; - } else { - $urlname = str_replace( '#', '%23', $urlname ); - $station = ''; - } - if ( $station !== '' ) { - $notsaved = 0; - $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; - $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); - } else { - $notsaved = 1; - $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); - } - $classnotsaved = $notsaved ? ' notsaved' : ''; - $namenotsaved = $notsaved ? '' : $station; - $url = preg_replace( '/#charset=.*/', '', $file ); - $path = preg_replace( '/\?.*$/', '', $file ); - $html .= + $urlname = str_replace( '#', '%23', $urlname ); + $station = ''; + } + if ( $station !== '' ) { + $notsaved = 0; + $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; + $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); + } else { + $notsaved = 1; + $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); + } + $classnotsaved = $notsaved ? ' notsaved' : ''; + $namenotsaved = $notsaved ? '' : $station; + $url = preg_replace( '/#charset=.*/', '', $file ); + $path = preg_replace( '/\?.*$/', '', $file ); + $html .= '
  • '. ''.$path.''. $icon.'
    '.( $notsaved ? '. . .' : $station ).''. @@ -198,8 +204,7 @@ function output() { ''. '
  • '; - $count->radio++; - } + $count->radio++; } $counthtml = ''; if ( $name ) { From 9e1012b1e773d3fa8b67cad602a8247462b582c5 Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 11:00:07 +0700 Subject: [PATCH 73/88] Update playlist.php --- srv/http/playlist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 44061b19a..769a1c3d9 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -155,8 +155,8 @@ function output() { continue; } - $prefix = substr( $file, 0, 10 ); - if ( in_array( $prefix, [ 'http://192', 'http://127', 'http://loc' ] ) ) { // upnp + $prefix = substr( $file, 0, 14 ); + if ( substr( $file, 0, 14 ) === 'http://192.168' ) { // upnp $li2 = ''; if ( $artist ) $li2.= ''.$artist.''; if ( $artist && $album ) $li2.= ' - '; From 38a599426b91138524a486bdbbfbd796d88c5b5e Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 11:34:46 +0700 Subject: [PATCH 74/88] Update playlist.php --- srv/http/playlist.php | 63 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 769a1c3d9..884c4addb 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -93,27 +93,9 @@ function output() { $pos++; $v = explode( '^^', $list ); for ( $i = 0; $i < $fL; $i++ ) ${$f[ $i ]} = $v[ $i ]; - $prefix = $file[ 0 ]; - if ( in_array( $prefix, [ 'U', 'N', 'S' ] ) ) { // USB, NAS, SD + if ( in_array( $file[ 0 ], [ 'U', 'N', 'S' ] ) ) { // USB, NAS, SD $sec = HMS2second( $time ); - $li2 = ''; - if ( $track ) { - $track = preg_replace( '/^#*0*/', '', $track ); - $li2 .= ''.$track.' - '; - } - $artist = $artist ?: $albumartist; - $album = $album; - if ( $artist ) $li2.= ''.$artist.''; - if ( $artist && $album ) $li2.= ' - '; - if ( $album ) $li2.= ''.$album.''; - if ( ! $artist && ! $album ) $li2.= $file; - $datatrack = ''; - if ( strpos( $file, '.cue/track' ) ) { - $datatrack = 'data-track="'.$track.'"'; // for cue in edit - $file = substr_replace( $file , '.cue', strrpos( $file , '.' ) ); - } - $title = $title ?: pathinfo( $file, PATHINFO_FILENAME ); - $ext = ''; + $li2 = $pos.' • '; if ( substr( $file, 0, 4 ) === 'cdda' ) { $discid = file( '/srv/http/data/shm/audiocd', FILE_IGNORE_NEW_LINES )[ 0 ]; $cdfile = '/srv/http/data/audiocd/'.$discid; @@ -128,14 +110,29 @@ function output() { $album = $audiocd[ 1 ]; $title = $audiocd[ 2 ]; $time = second2HMS( $audiocd[ 3 ] ); - $track = $track; - $li2 = ''.$track.' - '.$artist.' - '.$album.''; + $li2 = $track.' - '.$artist.' - '.$album.''; } $class = 'audiocd'; $datatrack = 'data-discid="'.$discid.'"'; // for cd tag editor $thumbsrc = '/data/audiocd/'.$discid.'.jpg'; $icon = imgIcon( $thumbsrc, 'filesavedpl', 'audiocd' ); } else { + if ( $track ) { + $track = preg_replace( '/^#*0*/', '', $track ); + $li2 .= $track.' - '; + } + $artist = $artist ?: $albumartist; + $album = $album; + if ( $artist ) $li2.= ''.$artist.''; + if ( $artist && $album ) $li2.= ' - '; + if ( $album ) $li2.= ''.$album.''; + if ( ! $artist && ! $album ) $li2.= $file; + $datatrack = ''; + if ( strpos( $file, '.cue/track' ) ) { + $datatrack = 'data-track="'.$track.'"'; // for cue in edit + $file = substr_replace( $file , '.cue', strrpos( $file , '.' ) ); + } + $title = $title ?: pathinfo( $file, PATHINFO_FILENAME ); $class = 'file'; $discid = ''; $path = pathinfo( $file, PATHINFO_DIRNAME ); @@ -147,7 +144,7 @@ function output() { ''.$file.''. $icon.''. - ''. + '
    '.$li2.'
    '. ' '; $count->song++; @@ -155,9 +152,8 @@ function output() { continue; } - $prefix = substr( $file, 0, 14 ); if ( substr( $file, 0, 14 ) === 'http://192.168' ) { // upnp - $li2 = ''; + $li2 = $pos.' • '; if ( $artist ) $li2.= ''.$artist.''; if ( $artist && $album ) $li2.= ' - '; if ( $album ) $li2.= ''.$album.''; @@ -167,7 +163,7 @@ function output() { i( 'upnp', 'filesavedpl' ). ''. - '
    '.$pos.' • '.$li2.'
    '. + '
    '.$li2.'
    '. ' '; $count->upnp++; @@ -184,24 +180,25 @@ function output() { $urlname = str_replace( '#', '%23', $urlname ); $station = ''; } + $li2 = $pos.''; if ( $station !== '' ) { - $notsaved = 0; + $notsaved = ''; + $li2 .= $station; $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); } else { - $notsaved = 1; + $notsaved = ' notsaved'; $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); } - $classnotsaved = $notsaved ? ' notsaved' : ''; - $namenotsaved = $notsaved ? '' : $station; - $url = preg_replace( '/#charset=.*/', '', $file ); $path = preg_replace( '/\?.*$/', '', $file ); + $url = preg_replace( '/#charset=.*/', '', $file ); + $li2 .= ''.$url.''; $html .= -'
  • '. +'
  • '. ''.$path.''. $icon.''. - ''. + '
    '.$li2.'
    '. '
  • '; $count->radio++; From 397b496114193ee49f3e727c9e386c2f77f78c5a Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 11:38:06 +0700 Subject: [PATCH 75/88] Update playlist.php --- srv/http/playlist.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 884c4addb..1ac6b2efe 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -186,9 +186,11 @@ function output() { $li2 .= $station; $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); + $name = $station; } else { $notsaved = ' notsaved'; $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); + $name = '. . .'; } $path = preg_replace( '/\?.*$/', '', $file ); $url = preg_replace( '/#charset=.*/', '', $file ); @@ -196,7 +198,7 @@ function output() { $html .= '
  • '. ''.$path.''. - $icon.'
    '.( $notsaved ? '. . .' : $station ).''. + $icon.''. '
    '.$li2.'
    '. '
  • From fa34c3b7b4d69d397f3ce172497c64a11a9e48f4 Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 11:41:23 +0700 Subject: [PATCH 76/88] Update playlist.php --- srv/http/playlist.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 1ac6b2efe..9fac74c76 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -142,7 +142,8 @@ function output() { $html .= '
  • '. ''.$file.''. - $icon.'
    '.$title.''. + $icon. + ''. '
    '.$li2.'
    '. '
  • @@ -198,7 +199,8 @@ function output() { $html .= '
  • '. ''.$path.''. - $icon.'
    '.$name.''. + $icon. + ''. '
    '.$li2.'
    '. '
  • From ec143f6637ecd4f5d7e72dc4efc05801de72e5ca Mon Sep 17 00:00:00 2001 From: rern Date: Thu, 9 Jan 2025 14:08:40 +0700 Subject: [PATCH 77/88] u --- srv/http/assets/js/context.js | 2 +- srv/http/assets/js/function.js | 1 - srv/http/assets/js/main.js | 2 -- srv/http/bash/cmd.sh | 10 ++++-- srv/http/bash/settings/features.sh | 10 +++--- srv/http/playlist.php | 50 +++++++++++++----------------- 6 files changed, 33 insertions(+), 42 deletions(-) diff --git a/srv/http/assets/js/context.js b/srv/http/assets/js/context.js index 00bfae2bd..af91591c8 100644 --- a/srv/http/assets/js/context.js +++ b/srv/http/assets/js/context.js @@ -2,7 +2,7 @@ function addSimilar() { var icon = 'lastfm'; var title = 'Add Similar'; banner( icon +' blink', title, 'Get similar tracks ...', -1 ); - bash( [ 'mpcsimilar', V.list.artist, V.list.name, V.apikeylastfm, 'CMD ARTIST TITLE APIKEY' ], error => { + bash( [ 'mpcsimilar', V.list.path, 'CMD FILE' ], error => { if ( error ) { bannerHide(); info( { diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 00b7c4b93..8e7e68500 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -259,7 +259,6 @@ function contextmenuLibrary( $li, $target ) { if ( V.mode.slice( -5 ) === 'radio' ) V.list.dir = $li.find( '.lidir' ).text(); if ( V.librarytrack && ! V.list.licover ) { V.list.name = $li.find( '.li1' ).html().replace( / $dirsystem/scrobblekey diff --git a/srv/http/playlist.php b/srv/http/playlist.php index 9fac74c76..e4f02aa05 100644 --- a/srv/http/playlist.php +++ b/srv/http/playlist.php @@ -72,6 +72,17 @@ function output() { //---------------------------------------------------------------------------------- } +function artistAlbum( $artist, $album, $file ) { + $ar_al = ''; + if ( $artist || $album ) { + if ( $artist ) $ar_al.= $artist; + if ( $artist && $album ) $ar_al.= ' - '; + if ( $album ) $ar_al.= $album; + return $ar_al; + } else { + return $file; + } +} $f = [ 'album', 'albumartist', 'artist', 'file', 'time', 'title', 'track' ]; $fL = count( $f ); $format = '%'.implode( '%^^%', $f ).'%'; @@ -95,7 +106,6 @@ function output() { for ( $i = 0; $i < $fL; $i++ ) ${$f[ $i ]} = $v[ $i ]; if ( in_array( $file[ 0 ], [ 'U', 'N', 'S' ] ) ) { // USB, NAS, SD $sec = HMS2second( $time ); - $li2 = $pos.' • '; if ( substr( $file, 0, 4 ) === 'cdda' ) { $discid = file( '/srv/http/data/shm/audiocd', FILE_IGNORE_NEW_LINES )[ 0 ]; $cdfile = '/srv/http/data/audiocd/'.$discid; @@ -110,23 +120,14 @@ function output() { $album = $audiocd[ 1 ]; $title = $audiocd[ 2 ]; $time = second2HMS( $audiocd[ 3 ] ); - $li2 = $track.' - '.$artist.' - '.$album.''; } $class = 'audiocd'; $datatrack = 'data-discid="'.$discid.'"'; // for cd tag editor $thumbsrc = '/data/audiocd/'.$discid.'.jpg'; $icon = imgIcon( $thumbsrc, 'filesavedpl', 'audiocd' ); } else { - if ( $track ) { - $track = preg_replace( '/^#*0*/', '', $track ); - $li2 .= $track.' - '; - } - $artist = $artist ?: $albumartist; - $album = $album; - if ( $artist ) $li2.= ''.$artist.''; - if ( $artist && $album ) $li2.= ' - '; - if ( $album ) $li2.= ''.$album.''; - if ( ! $artist && ! $album ) $li2.= $file; + if ( $track ) $track = preg_replace( '/^#*0*/', '', $track ); + if ( ! $artist ) $artist = $albumartist; $datatrack = ''; if ( strpos( $file, '.cue/track' ) ) { $datatrack = 'data-track="'.$track.'"'; // for cue in edit @@ -139,12 +140,12 @@ function output() { $thumbsrc = '/mnt/MPD/'.rawurlencode( $path ).'/thumb.jpg'; // replaced with icon on load error(faster than existing check) $icon = imgIcon( $thumbsrc, 'filesavedpl', 'music' ); } + $li2 = $pos.' • '.$track.' - '.artistAlbum( $artist, $album, $file ); $html .= '
  • '. ''.$file.''. $icon. - ''. + ''. '
    '.$li2.'
    '. '
  • '; @@ -154,16 +155,11 @@ function output() { } if ( substr( $file, 0, 14 ) === 'http://192.168' ) { // upnp - $li2 = $pos.' • '; - if ( $artist ) $li2.= ''.$artist.''; - if ( $artist && $album ) $li2.= ' - '; - if ( $album ) $li2.= ''.$album.''; - if ( ! $artist && ! $album ) $li2.= $file; + $li2 = $pos.' • '.artistAlbum( $artist, $album, $file ); $html .= '
  • '. i( 'upnp', 'filesavedpl' ). - ''. + ''. '
    '.$li2.'
    '. '
  • '; @@ -187,21 +183,17 @@ function output() { $li2 .= $station; $thumbsrc = '/data/'.$radio.'/img/'.$urlname.'-thumb.jpg'; $icon = imgIcon( $thumbsrc, 'filesavedpl', $radio ); - $name = $station; } else { $notsaved = ' notsaved'; $icon = i( 'save savewr' ).i( 'webradio', 'filesavedpl' ); - $name = '. . .'; + $station = '. . .'; } - $path = preg_replace( '/\?.*$/', '', $file ); - $url = preg_replace( '/#charset=.*/', '', $file ); - $li2 .= ''.$url.''; + $li2 .= ''.preg_replace( '/#charset=.*/', '', $file ).''; $html .= '
  • '. - ''.$path.''. + ''.preg_replace( '/\?.*$/', '', $file ).''. $icon. - '
    '.$name.''. - '
    '. + ''. '
    '.$li2.'
    '. '
  • '; From b2fa0a20c87f3474d29f653457a3d2a3b479272d Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 08:05:30 +0700 Subject: [PATCH 78/88] Update install.sh --- install.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/install.sh b/install.sh index bb79e21c7..ee2da9841 100644 --- a/install.sh +++ b/install.sh @@ -5,6 +5,11 @@ alias=r1 . /srv/http/bash/settings/addons.sh # 20250110 +if [[ $( pacman -Q python-rpi-gpio ) != 'python-rpi-gpio 0.7.1-3' ]]; then + pacman -R --noconfirm python-rpi-gpio + pacman -Sy --noconfirm python-rpi-gpio +fi + file=/etc/systemd/system/mpd_oled.service if [[ -e $file ]]; then rm -f $file From a00548ae38e3d8f2a5e055b46f00f7aa6217c455 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 09:25:01 +0700 Subject: [PATCH 79/88] u --- srv/http/bash/lcdchar.py | 5 +---- srv/http/bash/relays-timer.sh | 21 +++++++-------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/srv/http/bash/lcdchar.py b/srv/http/bash/lcdchar.py index 69302b72a..05b68ece8 100644 --- a/srv/http/bash/lcdchar.py +++ b/srv/http/bash/lcdchar.py @@ -158,10 +158,7 @@ def second2hhmmss( sec ): if not Title: Title = DOTS if not Album: Album = DOTS if rows == 2: - if state == 'play': - lines = Title - elif BACKLIGHT: - backlightOff() + if state == 'play': lines = Title else: lines = Artist + RN + Title + RN + Album diff --git a/srv/http/bash/relays-timer.sh b/srv/http/bash/relays-timer.sh index ea9c6c61a..0d99ceacb 100644 --- a/srv/http/bash/relays-timer.sh +++ b/srv/http/bash/relays-timer.sh @@ -8,18 +8,11 @@ echo $$ > $dirshm/pidrelaystimer timer=$( getVar timer $dirsystem/relays.conf ) i=$timer while sleep 60; do - if [[ -e $dirsystem/camilladsp ]]; then - running= - else - grep -q -m1 RUNNING /proc/asound/card*/pcm*p/sub*/status && running=1 || running= - fi - if grep -q -m1 '^state.*play' $dirshm/status || $running; then - i=$timer - else - (( i-- )) - case $i in - 1 ) pushData relays '{ "countdown": true }';; - 0 ) $dirbash/relays.sh off && break;; - esac - fi + grep -q -m1 '^state.*play' $dirshm/status && i=$timer && continue + + (( i-- )) + case $i in + 1 ) pushData relays '{ "countdown": true }';; + 0 ) $dirbash/relays.sh off && break;; + esac done From f101c40a527a1ac58db5aec5b78ebac2006d2cc1 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 11:45:39 +0700 Subject: [PATCH 80/88] u --- srv/http/assets/js/function.js | 1 + srv/http/bash/cmd.sh | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/srv/http/assets/js/function.js b/srv/http/assets/js/function.js index 8e7e68500..2f209719e 100644 --- a/srv/http/assets/js/function.js +++ b/srv/http/assets/js/function.js @@ -522,6 +522,7 @@ function displaySave() { } ); if ( values.tapreplaceplay ) values.plclear = false; jsonSave( 'display', values ); + bash( [ 'display' ] ); } function displaySubMenu() { $( '#dsp' ) diff --git a/srv/http/bash/cmd.sh b/srv/http/bash/cmd.sh index 146e79a32..8da753a14 100644 --- a/srv/http/bash/cmd.sh +++ b/srv/http/bash/cmd.sh @@ -383,20 +383,21 @@ dirrename ) pushRadioList ;; display ) - pushData display $( < $dirsystem/display.json ) - # temp - if grep -q albumyear.*true $dirsystem/display.json && [[ ! -e $dirmpd/albumbyartist-year ]]; then - pushData mpdupdate '{ "type": "mpd" }' - $dirbash/cmd-list.sh &> /dev/null & - fi - [[ -e $dirsystem/vumeter ]] && prevvumeter=1 - grep -q -m1 vumeter.*true $dirsystem/display.json && touch $dirsystem/vumeter && vumeter=1 + status=$( $dirbash/status.sh ) + pushData mpdplayer "$status" + display=$( < $dirsystem/display.json ) + pushData display "$display" + systemctl try-restart radio + [[ -e $dirsystem/vumeter ]] && prevvumeter=1 || prevvumeter= + grep -q -m1 vumeter.*true <<< $display && vumeter=1 || vumeter= [[ $prevvumeter == $vumeter ]] && exit # -------------------------------------------------------------------- if [[ $vumeter ]]; then + touch $dirsystem/vumeter [[ ! -e $dirmpdconf/fifo.conf ]] && $dirsettings/player-conf.sh else rm -f $dirsystem/vumeter + [[ -e $dirmpdconf/fifo.conf ]] && $dirsettings/player-conf.sh fi ;; equalizer ) From 04032d3bd52835debbc014568f65c0f4c2ccd806 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 11:54:52 +0700 Subject: [PATCH 81/88] Update common.sh --- srv/http/bash/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index 201b53069..e9c1c8ec4 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -384,7 +384,7 @@ quoteEscape() { } radioStatusFile() { local status - status=$( grep -vE '^Album|^Artist|^coverart|^elapsed|^state|^Title' $dirshm/status ) + status=$( grep -vE '^Album|^Artist|^coverart|^elapsed|^pllength|^state|^Title' $dirshm/status ) status+=' Artist="'$artist'" Album="'$album'" From 9fa98b21dfe97e113d57e28e4450b6d1b26c8960 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 12:38:32 +0700 Subject: [PATCH 82/88] Update cmd.sh --- srv/http/bash/cmd.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/srv/http/bash/cmd.sh b/srv/http/bash/cmd.sh index 8da753a14..4f5db963b 100644 --- a/srv/http/bash/cmd.sh +++ b/srv/http/bash/cmd.sh @@ -385,8 +385,6 @@ dirrename ) display ) status=$( $dirbash/status.sh ) pushData mpdplayer "$status" - display=$( < $dirsystem/display.json ) - pushData display "$display" systemctl try-restart radio [[ -e $dirsystem/vumeter ]] && prevvumeter=1 || prevvumeter= grep -q -m1 vumeter.*true <<< $display && vumeter=1 || vumeter= From 0360879d5cc5562e3659d1d9615f6d4d15b82500 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 12:40:17 +0700 Subject: [PATCH 83/88] Update cmd.sh --- srv/http/bash/cmd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/cmd.sh b/srv/http/bash/cmd.sh index 4f5db963b..f5da5a3ba 100644 --- a/srv/http/bash/cmd.sh +++ b/srv/http/bash/cmd.sh @@ -387,7 +387,7 @@ display ) pushData mpdplayer "$status" systemctl try-restart radio [[ -e $dirsystem/vumeter ]] && prevvumeter=1 || prevvumeter= - grep -q -m1 vumeter.*true <<< $display && vumeter=1 || vumeter= + grep -q -m1 vumeter.*true $dirsystem/display.json && vumeter=1 || vumeter= [[ $prevvumeter == $vumeter ]] && exit # -------------------------------------------------------------------- if [[ $vumeter ]]; then From e867926b0b0c1bab7ed94841379b906c5d45fb36 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 12:42:21 +0700 Subject: [PATCH 84/88] Update relays-timer.sh --- srv/http/bash/relays-timer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/http/bash/relays-timer.sh b/srv/http/bash/relays-timer.sh index 0d99ceacb..52abca65c 100644 --- a/srv/http/bash/relays-timer.sh +++ b/srv/http/bash/relays-timer.sh @@ -8,7 +8,7 @@ echo $$ > $dirshm/pidrelaystimer timer=$( getVar timer $dirsystem/relays.conf ) i=$timer while sleep 60; do - grep -q -m1 '^state.*play' $dirshm/status && i=$timer && continue + grep -q -m1 ^state.*play $dirshm/status && i=$timer && continue (( i-- )) case $i in From c50d32d1bede5d6df323d87f73ca6a62baba16f1 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 14:45:59 +0700 Subject: [PATCH 85/88] u --- srv/http/bash/cmd.sh | 12 +----------- srv/http/bash/common.sh | 31 +++++++++++++++++++++++++++++++ srv/http/bash/settings/system.sh | 26 ++------------------------ 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/srv/http/bash/cmd.sh b/srv/http/bash/cmd.sh index f5da5a3ba..c9f3e99f5 100644 --- a/srv/http/bash/cmd.sh +++ b/srv/http/bash/cmd.sh @@ -386,17 +386,7 @@ display ) status=$( $dirbash/status.sh ) pushData mpdplayer "$status" systemctl try-restart radio - [[ -e $dirsystem/vumeter ]] && prevvumeter=1 || prevvumeter= - grep -q -m1 vumeter.*true $dirsystem/display.json && vumeter=1 || vumeter= - [[ $prevvumeter == $vumeter ]] && exit -# -------------------------------------------------------------------- - if [[ $vumeter ]]; then - touch $dirsystem/vumeter - [[ ! -e $dirmpdconf/fifo.conf ]] && $dirsettings/player-conf.sh - else - rm -f $dirsystem/vumeter - [[ -e $dirmpdconf/fifo.conf ]] && $dirsettings/player-conf.sh - fi + fifoToggle ;; equalizer ) freq=( 31 63 125 250 500 1 2 4 8 16 ) diff --git a/srv/http/bash/common.sh b/srv/http/bash/common.sh index e9c1c8ec4..3e6213334 100644 --- a/srv/http/bash/common.sh +++ b/srv/http/bash/common.sh @@ -203,6 +203,37 @@ enableFlagSet() { exists() { [[ -e $1 ]] && echo true || echo false } +fifoToggle() { # mpdoled vuled vumeter + filefifo=$dirmpdconf/fifo.conf + [[ -e $dirsystem/mpdoled ]] && mpdoled=1 + [[ -e $dirsystem/vuled ]] && vuled=1 + if grep -q -m1 vumeter.*true $dirsystem/display.json; then + vumeter=1 + touch $dirsystem/vumeter + else + rm -f $dirsystem/vumeter + fi + if [[ $mpdoled || $vuled || $vumeter ]]; then + if [[ ! -e $filefifo ]]; then + ln -s $dirmpdconf/{conf/,}fifo.conf + systemctl restart mpd + [[ $vuled || $vumeter ]] && systemctl restart cava + fi + ! grep -q 'state="*play' $dirshm/status && return + + [[ $mpdoled ]] && systemctl restart mpd_oled + [[ $vuled || $vumeter ]] && systemctl restart cava + else + if [[ -e $filefifo ]]; then + [[ $mpdoled || $vuled || $vumeter ]] && return + + rm $filefifo + systemctl restart mpd + fi + [[ ! $mpdoled ]] && systemctl stop mpd_oled + [[ ! $vuled && ! $vumeter ]] && systemctl stop cava + fi +} getContent() { if [[ -e "$1" ]]; then cat "$1" diff --git a/srv/http/bash/settings/system.sh b/srv/http/bash/settings/system.sh index ee6da32c2..de1cec4d6 100644 --- a/srv/http/bash/settings/system.sh +++ b/srv/http/bash/settings/system.sh @@ -244,7 +244,6 @@ mountunmount ) ;; mpdoled ) enableFlagSet - filefifo=$dirmpdconf/fifo.conf if [[ $ON ]]; then opt=$( sed 's/ -X//' /etc/default/mpd_oled ) chip=$( cut -d' ' -f2 <<< $opt ) @@ -253,19 +252,10 @@ mpdoled ) [[ $SPECTRUM ]] && opt=$( sed 's/"$/ -X"/' <<< $opt ) [[ $baud != $BAUD ]] && sed -i -E 's/(baudrate=).*/\1'$BAUD'/' /boot/config.txt echo "$opt" > /etc/default/mpd_oled - if [[ ! -e $filefifo ]]; then - ln -s $dirmpdconf/{conf/,}fifo.conf - systemctl restart mpd - fi - else - if [[ -e $filefifo ]]; then - rm $filefifo - systemctl restart mpd - fi fi + fifoToggle i2cset=1 configTxt - systemctl try-restart mpd_oled ;; ntp ) echo "\ @@ -433,19 +423,7 @@ usbconnect | usbremove ) # for /etc/conf.d/devmon - devmon@http.service ;; vuled ) enableFlagSet - pins=$( cut -d= -f2 $dirsystem/vuled.conf ) - if [[ $ON ]]; then - ln -sf $dirmpdconf/{conf/,}fifo.conf - grep -q 'state="*play' $dirshm/status && systemctl start cava - else - if [[ -e $dirsystem/vumeter ]]; then - systemctl try-restart cava - else - systemctl stop cava - rm -f $dirmpdconf/fifo.conf - fi - fi - systemctl restart mpd + fifoToggle pushRefresh ;; wlan ) From 1738519ac5a181834a35c2194a5932830fbc1f2f Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 18:59:26 +0700 Subject: [PATCH 86/88] Update system.php --- srv/http/settings/system.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/srv/http/settings/system.php b/srv/http/settings/system.php index c1134aeab..1cfa9ad23 100644 --- a/srv/http/settings/system.php +++ b/srv/http/settings/system.php @@ -204,6 +204,7 @@ 'id' => 'mpdoled' , 'label' => 'Spectrum OLED' , 'sub' => 'mpd_oled' + , 'exist' => '/usr/bin/cava' , 'help' => <<OLED module - display audio level spectrum @@ -221,6 +222,7 @@ 'id' => 'vuled' , 'label' => 'VU LED' , 'sub' => 'cava' + , 'exist' => '/usr/bin/cava' , 'help' => <<< EOF LEDs - display audio level · LED resister calculator From 73aebe9b75f226d1caaf3ceeb3406b4811cd43a3 Mon Sep 17 00:00:00 2001 From: rern Date: Fri, 10 Jan 2025 20:02:13 +0700 Subject: [PATCH 87/88] Update system.php --- srv/http/settings/system.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/srv/http/settings/system.php b/srv/http/settings/system.php index 1cfa9ad23..c1134aeab 100644 --- a/srv/http/settings/system.php +++ b/srv/http/settings/system.php @@ -204,7 +204,6 @@ 'id' => 'mpdoled' , 'label' => 'Spectrum OLED' , 'sub' => 'mpd_oled' - , 'exist' => '/usr/bin/cava' , 'help' => <<OLED module - display audio level spectrum @@ -222,7 +221,6 @@ 'id' => 'vuled' , 'label' => 'VU LED' , 'sub' => 'cava' - , 'exist' => '/usr/bin/cava' , 'help' => <<< EOF LEDs - display audio level · LED resister calculator From dbaf0c26b7763426a8cafc385cf67f61c14b9e36 Mon Sep 17 00:00:00 2001 From: rern Date: Sat, 11 Jan 2025 07:00:13 +0700 Subject: [PATCH 88/88] Update install.sh --- install.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index ee2da9841..7259f02f5 100644 --- a/install.sh +++ b/install.sh @@ -4,7 +4,17 @@ alias=r1 . /srv/http/bash/settings/addons.sh -# 20250110 +# 20250111 +if [[ -e /boot/kernel.img ]]; then + if [[ $( pacman -Q cava ) != 'cava 0.7.4-1' ]]; then + wget https://github.com/rern/rern.github.io/raw/refs/heads/main/armv6h/cava-0.7.4-1-any.pkg.tar.xz + pacman -U --noconfirm cava-0.7.4-1-any.pkg.tar.xz + rm cava-0.7.4-1-any.pkg.tar.xz + fi +else + [[ $( pacman -Q cava ) != 'cava 0.10.3-2' ]] && pacman -Sy --noconfirm cava +fi + if [[ $( pacman -Q python-rpi-gpio ) != 'python-rpi-gpio 0.7.1-3' ]]; then pacman -R --noconfirm python-rpi-gpio pacman -Sy --noconfirm python-rpi-gpio