commit-10-2-25
This commit is contained in:
parent
343a7f7dd6
commit
4b75d0886e
@ -1,11 +1,12 @@
|
||||
{
|
||||
"url": "yahoo.com",
|
||||
"url": "www.ataphotobooths.com",
|
||||
"mediaFolder": "playlist",
|
||||
"imageDuration": "5",
|
||||
"player_type": "mpv",
|
||||
"mediaLocation": "/home/orangepi/Desktop/playlists/ATA",
|
||||
"autoStart": true,
|
||||
"autoStart": false,
|
||||
"autoStartDelay": 5,
|
||||
"autoPlayAtBoot": true,
|
||||
"browserPath": "chromium"
|
||||
"autoPlayAtBoot": false,
|
||||
"browserPath": "firefox",
|
||||
"browserOptions": "--private-window"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,3 +1,3 @@
|
||||
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-03-05T12:22:13.847182
|
||||
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-09-26T00:34:58.972446
|
||||
from pyarmor_runtime_000000 import __pyarmor__
|
||||
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00e\x03\x00\x00\x12\t\x04\x00:\x81\xd6u\x83\xf4\xacR\xbbSmm\x9d\xa9\xf2\x8c\x00\x00\x00\x00\x00\x00\x00\x00\x85\xb7 \xad\x80\xbb\x7f\x90\x1f\n\x9f7\xe4\xc2R\xae&s\x0c\x11\x97\x12\xa4\x1f\xd53\r\xbbU]\x82t\xfa\t\xd4\xbf\xd2oTl\xfe\xf7\x92\xea\x9c4\x94\x13b\xc9\xc9\xe6+,\x98\x81\xa3\xc8w\xb5"\xd3\x0e6j\x00\x01\x01\xcb\xce\xa3\x1bC\xcf\xb5\xec\x06|(a\xe5\xaf}.\xb1\xef\xfbC\xe7\xce\xcaqFA\xf5\xf7\x1d:\x13\x0b<\x86\r\x0cx\xb8))"\xbb!\xef\x18\xd9l\xe0\xf27\x97\xec\x8a}P>\xdd\xd1(\xd1>c\xaf\x96,C\x04\xacQ\xecZ\xf3x\xaf\xc3\xa1\xcf`\xb7y\xba\xad\xe0\x10\xb3Ni\x1e\xa9\xe2.\xfa5\xe5Nnl|c@\x9c\x8a\x95\x189\xc9\xcfbP\xca\xb0\xbf\xedr-rO$\xab\x05qH\xb2\x01\r\xeaC*f><\xfb\xa0E<Vd\x98\x8bt\xae\x1bU\xfepF\xf3H\xbe)\x94\xe6sM\xde8\xc9\xd7\xa6 \x06\x12D[9\xd8\xed\x0f\xa48\xc0\xa4\x80]$\xd8\x1c\x1a\xee\xde\\\xab\x1b\xd6\xb5\x8c,?\xae\x8f\xf4%\x7fh\xef.\x1c\xd1\xdc\xf2\x03"\xa0\xf4A\x00\xe0\xb5\xff\xfb8\xa1\xfe\xabN\t\xb0v\\/X\xff\xd3\n\xf6\t\'F\xa6M\xb5\xdb\xba\xc3\x00\xecO\xe0O\x8a\x04P8U\xb1\x8f\x14\xf4\xe3\x05\x0eP\xff\xae\xfc\xda\x1d\x1a\xa7?Y-\x8c1Z\xb6\xd9CX[\xef\x03\x0f\x86\xe1\xb69oz\x01\x05{{\xdcz,qt;\x88\xceL\xe3\xaa\xe8}\x83\x0f\xb6#\xf7\xfc8\xcc\xee\xc3\xd3\xed\x0f\x14\xe3\xf8\x8a\x95F*:\xa0)LG\x07\x13\x12\xef7qk\':\xd4Y\xe1\xd8\x8d`*\xf4\tvDeo\x10<\x8a\x94\xc6/\xd6\xd2P\xd6\xb4~\xd4N\xca\x1d\xb5\xf3\xae\xaa\x9a\xc5c\x15\xba\x97%G\x96\xf8g\xbaYv\xb0m\xe16\\\x80\xb5\x1a\xa1(B+\xdfq\xc6\xa9\xdc>gh\xce\xe3c\xe6t\xec\xed\x89\x82c\x12;(\tF\x15\xc1\x9e\xeer\x10\xde\x99\xe2\xe8\xaeS\x81\xb0\xa0\xb8\xd2\xbc\xf0v\xe5T\xe8\xc8\x00\x88|\x82\xb8\x03\xa2\x92\xd3\xd0\xdd#\xf5\xd5T\xcc\xd9\xe3%\xec\x83ZN\x98\xeer\xcc\x19<|\xbdh\xf1*:)j\xe9;/\'[\xe5\xcaA\x94p\xf2\xfd\xbb\xbe^RC\xc8\x9a\xb9\xf21\x06\xbd&\xe8u\x94\x19!\xdat6\xe9\x0f\x8c\xfc\x15\x06."\xe0\x1e\xeb\x1e\xf5\xbb\r\x01W\x83\x92sm\xb3m\xc8\xe9e\x01O\xba\xfa1oy-Lo\xd3R$I\xc4\x83\r\'t\xf1\xfc\x12\xda\\\n\xb1\xc67\xa3wq=\xa9\xda\x80\x06\xb2\x87\xbd\x90T\xc2\xf5m5\xd2qP\x00\x88u\xba\x8d\x7f\x8d\x95\x8f\x9e\x90\x879^\xd7\xe2)\xe3\x94X\xa1\xa4\x1a\x01\xe3\xc8\rB\xccI:\x93\x9fZ\xc2\xb4\xb4\x0b\xaa\xd5\xc7\x05\tf\xf5c\xb8&`\xd0\xa8\xa3\x82\x0coe]\x056\x8cu\x87\xd3\x82\t\x80\x846\xc7\xbb\xaf#\xcaam5w\x03`\x91n\'\xc8:\x94\x13\x89\xd9\x98s\x15]9\x90\xf1\xdd\xa9,\x98\xa3\x1f\xcf0_cK\x86\x84#\xb0\r\x19\xf9Z\xd0\xe3\x1c\x83.\xa1\xd9%e<^M\xa7/\x14\xf7\x89O\x89D\xa2*\xdd2\xd0\xcc\xad\x0f\xfa\xd2\x8c\x83\xb3\x94\xcb|p\xb2\xdb\xa3)\x9a\x8d\x03H\x07\xa3\x15\xfc\n<\\\x1d\xeb\x07\xfb\xbe\xd3\xbbc?qm\xee\x08\x89\xb5\x19|J\xab\xe7g}R\x11\xbb\xb4l\x93\xa3\x0f\xd2]\xa2>\xe3U\xcdh\xb0\x8e\xd3\xf5YS/Y\xc1/\xfa\xd8\xb8\xc5BP\xa4')
|
||||
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00e\x03\x00\x00\x12\t\x04\x00\x982\'p\xa04\x0f\x17B\x91\x9d\x8d\x82\xac\xf3.\x00\x00\x00\x00\x00\x00\x00\x00X#\xed\x0c\x92\xd5\xd0\xb3\xf8F\xce\x01\x0e\xa6b\x12y\xe4v\xd7l\xce\xd0\xaf\xc8-\\s\x9d0HAn\x8c2\x99\x16\xa2u\xca\xe1)\xe6\x9c\xb7+gZ\x1aE\x1c/\xfbySG\xf1\xee\xd6\x8c\xd4KK\xbf:\xc9\xd5\x14 \xe8\x8c\xf2\x7f\xb2\xba\xf1\xda\xc5\xc5/\xcfK\xd0M\xf8\x89\xf7\x9b\xc2\xe5\xfe\x9d.\x02(a\xa9\x0f\xee\xfb\x9e\x93\x897\xc8\x97\xa5\xf7#\xc7?\xa7\xe3\xaeZy\xe8\x1f\xd3\xfe\x1e\x0fV\x13e\x90hqi\xfd\x10\x1a\xc4c\x95\xbd\xde7\x16\x00\x1c\xac;%\xdd/\xe9\xc0\x91\x8e\x88\xca8\xd4\xc9l\x8bL\x0b!k{\xa4\xd1\xfb\x97`\xd8\xe2\xb5\x11\xabO\x13(,-@\x0f\xb2\\J\x94Gk\xa0\x9a\xed~S\xb4\x14\xf9`\xf7Z\xc7\xd06\xd3\x91\x05\x91\x8djn\xe8\xca\x80\xc8\x8c\xf3\xe6\x95\xd7\x05\xc6\xb9w\x87\xde\xd5S8\x13\xb8\x87\x1fP&\xee\xa5\x0f\xb2U\x16\xdeF\xb2\xe63\x12\x99Z\xef\xc5\xb0\xb48M|\x12\xf6m\xd6o>\x91B\xcei\x1f0u\xf2}#\xf0\x01~\x1c\xcc\xba\xcc\xba\x16\xe1\x90\xcd\x17c\x0fW\x19V\r\xb5\xd2{\xbf5LA\xcd\x8c%\xedi\xc6\x9e+d\xc8c\x921rP\xd7(\xc2F\xd7\xd1\x06rs\x9d\x17\'\xbb\xc2\x9fz\xfd\xe0a\xcb\xdb&)\x18`\x05\x8e\x05\xe4W\x07\xde\x88n\x04\xc7dV\x04j|\x92\xc3p\x8f\xd62\x04D\xcc\x84\'\xdd\xd6\xa2g\x1bs\xe3\xbc\xb3/{.\x1b\xf3.[\x15\xb9\x90\xcf{\n\x96\xee\xdb\xc1\x0e\x01\xf1z\xac\x88P\x0b\x13\x03\xca\xee\x10\x03W\xb2\x02JRD\xeb3\xf7y\xa8\xee3\xf6I\xc3^$@\xea\xbb\xe1T\xbaU\xa3\xe4F\xdaZJA\x13=H\xfcf\xc4\x03\xd3\nt\x81\xd0\xbfD\xcd\x8c\x00\x1bjlk\xa8*\x080\xf0\x85e\xdd\x9b\x02XS!^\x0f\x90\x0c\x04!\xe3\xa0\xaaC\x11\xee\xa7\xd4\x1a\xae4\x9d\xec\xec>C\xcc\xf3\x83\xd2|\x85A\xc8\xf3\xa6\x044\xa9\xcd\xdc\x96\xfd\xdd!\xff\x08\x9fx\x03\x8fA\x8f\xf89yN\xa4\xe0|\x07\x86\xef\x99\x99!\xa4\xc7\xda\xe0\xc3\xcbkm\xef\xfd\xf5\xa7\xb3]\xc7\xf5\xc8&\xfa]\x05\x12$\x97Q\xa7 o\xfbQ\xf9\xd2\x1c|a\xfc)O\x81\x8a\x18\x1d#\x90xud\x81\xb8{\xa7$9M\xc2M\'\xfd\x934\xd1df\rH\x1b\x8dg\xd8\xb2\xb1u\xfc;>[\xe3T\xda\x0b\xcf<\x7f\xbbe\xa7yRv_d)\xdcK\xbds\xe4\x98aK\xcd;\x0bbOg\xc7\x90\xc7\xd5\xd2\x9e\xf6Z\x9e(\'\xb3\xfe9\xa8\x80\xd0J\x0ca\x02P\x8c\xc5J\xf4G\xd7\xc6\xc9\xf5\xc0_\xedJ\x8cr"%\x04\xcd\x88\xe70\x87I\xfa\xbb\xa8*\xab\x13R\x15\x06\x16U\xa7\xd5\xf8L\xbeKU\x16\xfe\xc6K\xe6\xf2\xb2\x99;J\xef`!\xdblg\t\x99\xdc\x8e\xec\xbf\x8e\x02\xde\x8e\xafH\xcd\x02\xb3\xe9\xcf\xecH[\x9aF+\xd5\xf9.\xe8!\x16\xff._\xc1\xf4L}\x8f\xf6O~\xb7\xb4j\x05OX\x1e?\x97\x18\x14\x00\xfb\xaaP\xdd\xcc\xba\xe0;\xee\xc2K\x8bMa,;\'<w\xa3\x9bp1\xfe\xd2\x9cQF\xc5\xba\xd2\xc8\x02\xb3cY,\xca\xcdK2\x0f\x9d\xc2\x9c\x7f\x15W\xfe\xff\xees\xc0\xd0\x91\xe0\x1e\xfa\x83\x9a\x19\xd6\xe4K\xbb\xef\x9d\t-\xbb\x1f\x1f\xbb\x07\x03\xdc\x9bG\xe1\xadyPa\xe49\xa9\xba\x0c+][\x8e\xda\xb6\xf3/\x88\xc4\x95\x00\x85\xff+')
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
# Pyarmor 9.0.7 (trial), 000000, 2025-03-05T12:22:13.488747
|
||||
# Pyarmor 9.0.7 (trial), 000000, 2025-09-26T00:34:58.450603
|
||||
from .pyarmor_runtime import __pyarmor__
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1,3 +1,3 @@
|
||||
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-03-05T12:22:14.160307
|
||||
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-09-26T00:34:59.302633
|
||||
from pyarmor_runtime_000000 import __pyarmor__
|
||||
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\x0b\x03\x00\x00\x12\t\x04\x00\xa5\xad=\xdfl\x98\xc7s{G\x13\xa1\xc0i\r\xc9\x00\x00\x00\x00\x00\x00\x00\x00\xff\x8en<\x1c\x85K@\r\xfd\x04\xdbX\xb1f\x03\x17\x89\xb6\xf7\xf5}2\xfd[\x1b\x08\xd6s\x8a\xb4\xbd\xdaU\x94\x8e\xbb-<@b\x9a+\xdf\xac\xc7\xc1\x92\x1e\x8f\xf1At\xf6\xc7bh\'ly*\x9f\x94?MXOb\xf4\xa8\xc7\x07\xcdx$+U\xdf<a<\nN\xdb\xd6M\x03\xd8\xe2\x007h1\xb4\x8e\xe9\x8b^\x80XA\xd9\xd5\x97*\x860\x19\x97]\x1bI\xc2$95\x90\xe3\x91\xb6\xb6_\xc6\x80>8\xad\r\xe1\x83\x15)\x87\x9eq\xcfN\xc2GL\x83\x01d\xa1v6\x1a\xfe\xc6\xe7\x86\xc2\tZ,\xfa\xc6iv\x90\xcd1&\x1d\xb8\x18\x8b\x7fW!\x9a%\xf4;#\x12\xdd\xa9\x1c(w\xca\xb6\xc7\x85\xee60\xefI\x93\xd0x.$\\\x80n1\x9en\xde\x1e\xd6\xfc\x07\xed\x1b?\xa9\xc5F\xa9\nR\x16\xb1.\xa4\x87\xb67#\xd5;\x8a\xdbH\x02W\xf2\x83\x8eK\x1b\x8bP_\xdby\x82\xdc\x83\x13\x86w\xcf\x9di\x93\xbe`S\x96\x8bP\x93}X\xe7C\x02\xed1\x07b=<\xe7\xf9.\x96\x9c7\xa8\xb3\xc2\x0f\xe5mA\x87q\xbb\xb5\x16;\xe0\xf3\x13\xc3\x05\xd8\xbd\xd9\x07}\x17\x7fk\x82\x91\xe3\xfb- \\m\x05\x8d\xb5)\x0f\xa6\x00G\xb2\xa0\xc1\xca\xc1\xd0\x8bu\x87\xbf\x18K\xd9T\x8cs\te\xd4s`\xb2VG\xdc!\xb4\xed\x7f\xcc]N\x9f|{\xe8W\xfb@V%p=\x93,\xa4\xa9\xd3\\\xfc\xe7\x9e\xfbAG\x08\xb3\x0f\xd8\xf4\x8c\xb6\x80~\xaa\xd2\xf8)\n\x19\xaa?\x0eD\xd1\xb3\xf1\tJ\xf6\xa1 ^\x05\xcbbk\xea\x08\xa3\xb1T\x0f\xcb\xc7\x82\xcbD\xc7\x94<\x93\x17\x9a\x8f#\x16\xe6\xc6\r\x05i\x19\x8a\x08\xb5r\xf2 \xa1\x1f)\xd0\x81\xc3\xd339o\xeaY\x036?\xd5\x1c\x98W\xf1A\xd4\xfd\xba\xd5\x9a\x10\xfe\xd4 \x03\xe4\xd0F\xf3\x984\xb2F\xad1]\xb3}a\xd6\xa8{"\x16\xdan`\x0f\x8e\x81\'\xf6\x88\x9f_\x02\xce\xff\xd3\x12\x05\x17[9I\x11:W\x1f\x1a\xd2\xa8\x02\x97\x9cQ6\x9dP)\x1f\x8f\xa6P_pg\x98d\x84\x85&5\xc6b\xd6\xf9s\xcb\xd1x\x16\xb2[\xa7\xa8E\x8ed\xbasc;|h\x88\xa6\xae:\x0e\xb8\xf5\xbb \x01<{:\x04D/|t\xc9^\xfe\xb0\x1a\xc6\x85\x91\n<\x13[\xf0I\xe2\xc0\xfa\xa7\x7f\xc0\xc9U\xd1\xc1\xeb\xba\xc6d{\x07\xa9o\xc6\xac\x84\xdf,V\xd8\r\xa3\xbf\x1e\x9f\x93\xb7}b\xcd\x16\x85\xd5\x9b%\x86\x87\xaf\xd0\x83\xc4\xc7\xb6_aR\xa7-\xa5\xfd2e\xd3\xcb\xa7\xcd\xb2\xf8i\x8b\x03\x87\xa3\xa3\xbf\xea\x18\x95;\xd1W\xe0\xa4F\xf4\xa5(\xc5B]\x0b\xacP\x8d\x11\x9c\xb7\'\xa3X\x99\xa6\x9c\x88\xc7\x89V1O\xc7;wie\xc3\xc4\x82}l\xe5\x109\x8d\xcc\xb8\xda \xfc`\xec\x17*B\xbaR\xb8T8Y!\x86\xd8W":-&\xcc\xbd\x8b\xc3\xc9\x10M\xda,\x05\xc6"\xcaBK\xf4k{\xa64D\xc1\xda\x11\xe7\'\xbaF=e\xafB\xf0\xa4A\x8b0B\xf0F\x81$A\xd7N]\xbe\xc0\xa2')
|
||||
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\x0b\x03\x00\x00\x12\t\x04\x00\xdc\xe7\xc9U\xb18\xad\xd9\x16\x89\xabv\xc3\x89<\xd9\x00\x00\x00\x00\x00\x00\x00\x00\xba\xf8n\xc6i\xeb\x0c\xbe\x1d\xea\x012\xef]\x04\x9d7\xa2\xe1\xfe\x82Z\xaf_\xd2\x835\xd1\xba\xa0j\x97\xef\xe39\x18\xe4\x01\xfb\xa9\xf7a\xb2\xd1\xed\n\x9b%q\xf6\x7fm\x8f\xd7&\xa7d\x04A\x90D\x7f?\xc2*\xb2\x05\x87\xf4*4\xbf\xcca\x80\xc1\xd8\xe5\x0fR\x04,~%8u\xf5\xe9\x97\xe2\x89!\xd2\xeb\xf06\xe2\xbatLu\xbdd\xede:\x9bz\xf7b*(\xf6\x13g\x8f\xfd\xfd\xaa\xa0\xd9\xc1\x03v\x9f\x7f\xb1\xe7\x87\xcb\xad\x99\xb8w\xfe}\x17\xed\xa3\x90\x07\xa9<H\x04\xbd\x8c\xf21E]\xba\xc8!\xa5\xa1\x16\xb34\xbf2g<\xea\n\xfe^\x18\xfbm\xc2\xa4\xe5\x0c\x05qn\xcc\xce}P\xedG\xe8\\\x16\xa1\xe8\x8d\x99\xaf\xf5\xc6\xc7:\xa9\xdc\xd9\x9d\xd6\x1c\x02\xd2\x96\xe3\xfa\xb6\xf5J\xe0\x0bV\xb2\xdfL\xff\xd3\xca\xecr9\xe8!@9\x8e\xe9r \xdd\xedY\x0b\x0f\x9b\x9f\xa6\xb9\x96\xba\x17w\x1cF\xbfT\x135\x193N\xb3\xcd\x04j\x82\xe4\xab\x8f\xb8\x13.\x82X\xdf\xea)\xf9M\xa1\xd0\x1b\xc8\xd4m1\x0e\x83\x86\xc9\x98OD\xa3/?\x11Z&\xfc\xd4\xf5\x02ky.\x8a\xdc\xb2\xa52`\xb2\xefo\xb2\xf4\x05a0\xb6\xad]FU`\xe3\xf4\x91\xd7\xdd\\\x14\xa5\xfc\x82\xe9\xfa\x1aY\xd2Q|\':\x83Hm0\xf1\x99\xe7\xdf]\xf2\x17\xe4\x82\x8c\xcd\x94Yl\x12)\xde\x1bE\x9c\x1f>\xa883\x12"\x96\xa3\x04\x1b\xb3\xb3\xf4\x9e\xb8\x96ot\x9aMJ\xcb\x15\x7f\x00=\x95\xc6\xeeX\x95\xc3~\xa4>\x07\xae,s\xcf\xac<\x84;\x15/{\xdf \xab0u1\x01\xb4\x87Z{\xa8\ro\x87\xca\x82X\xdcl\xbb\x89\xb1\xf9Y\xce\xe2\xa1p\xbf\x80O;o>&\x06\x7f\x88\xa5uHO\xa4\x9dxd\x0e\xa7/\xc4\xb6\xfb6\xdd\xad\xfc\xf3\x1e\xb1T)\xd7\xfb\xf58\xfd\x83\x88\x8c\n\x93\x8e\xabiV\xb7\xf6\xe9#\xba4b\xc8\xae-\x8cn\xf1\xbf\xc5\xce\xad\xf0C\x97vD3\xe7R-\xc07R\x8e\xa5\x1a\xa8\xf8\xcel\xd0\x9a)\xfd\xca/!B\xf9\x94\x08\x81\x86C\x14\xeb\x9e\xcd\xccg\xb4\xc7\xe0\x88\xa1ye58\xcc\x84p\xf6X5\x90Uq\x1d\xcf\xf1{\xad\x83\xe5\xcdjaUl\x93\x10\xc8\x13d:\xc7(,"\xdeU\xb5QI!qF\x08\x97`\xaa\xfb\xa7:{\xd3q\x01#\xf2\xbc@)\tb\xe7\xb8\x81\n\xac\xe3\x05\x8e:\x08o}8A{*\xf0\xf1M\x15\x98\x06M?dm\xf2S\xd5M]O?\xd7m\x9fM\x1b3$\x88:\x95,\x9d\x1a\xb8\xa4W\xe7/!p\x9bF4\xbbf\xb5\x9a,\xd8\xce\xf0\xe3\xad\xc5\x80\x9b\xbe\xb6\x86\x85\x1e\n@w\xf2\xab\xb7B\xdd-\xabhL\xff\xeeCY\xa1\xee\xde,\x8a\x99\x06,0\xc6\xca\xb5\xe6\xb1\x07R\xef\xda\xdf\xd4\xec|\x02\x0f\x01u*f\xf5\xff\x8e\x7f\xd0c\x9b.El\xbb\x05\xaf\xa7\xa1\x19\x82\xdd\xef\xee\x14\x18z\xd1\xfa\xc4\x11=\xec\x95\xdf+\x08\xf6\xdc\xa3p\x02\x93"e\xeb\xc8\x14\x9b.9\xb5;]\xe5\xb9{A\x9b\x99')
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,3 +1,3 @@
|
||||
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-03-05T12:22:14.586715
|
||||
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-09-26T00:34:59.810850
|
||||
from pyarmor_runtime_000000 import __pyarmor__
|
||||
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\x9a\x01\x00\x00\x12\t\x04\x00\xc2\x16\xeb\xdb\x01#\xb1\xd9\xc2\xe2\xf6A^\xf4\xda\x89\x00\x00\x00\x00\x00\x00\x00\x00s\r\xc6\x00\xc4\xb3\x81\'\xb2|yB\xebs\x12\xecdEy\x82S(\xce\xce\x18\xb7\x9e\x08\x99\xf4\xf0]\x863\xe9h\xd8\x98n9O\xf5\xe2\xbf\x16\xd6\xcb\x18p\xc7\xf5\x9b- \x1aY\xdb\xa2Iu\xd5\xe14\xa4As\xb8\xa3t\x1a\xbfB\xce%\x8au\x84\x8b=\x85\x054\x14|\x8c\x00]\xe2)R\xed\xae\xda>\x04U\xceJ:\xd8\x1dW\xfdf\xb6\x1b\x81F\x0b\xd0Oany\xf3\x1e\xf3k\x9f\xbb\xf9\x10i[y\xdbP;\x89\x0c\xa7\xb2\xa2\x91\xf1e\xd5\xd9\xce9fz\xbe\x03\x8dfq\x064\xf4\x1a\x99s\xbf\x08X\x82W\x1ey`^^X\x1ai\xef\xa3\x0bx\xf3\x16K\x106T\x0eOA\x10\xa7{\x9fV\x95\x9d\xc7\xbc\x1d(\xe57\x95\xea\xc4\x02w\x8bu\xe3\x15\x8ea\x7f\xe77\x96\x03\x8c\x08"\xf6\x92\xc3;1\xa8\x919w\xf6g\x1a\x15\xa6Ci\xec=\xee_\x03\x03\x97\xcfl\x9b\xfb\x00\xee\xd0\x1b\xb7\xdb\x9bh\xbe\xa9\x8dJjK\xe4\xab\xe8\xa3<3\x82\x9f\xb2\xb2\x1d\xda\xfd\x13\xb3\xcc\xd8z\xfce\x13#~e\x9a\x11bD\xe8\x91\x82V\xff\x15\xb6\xf3\x8c\xe6zw\xf9\xf5U\x88$\xbc\xef-T\x01\x91R\xec-\xfb;\x8f\xc2\xbdtI\x7f\x98\x88\xbe+\xcd\xca\x9f\x01v\x99T\x9a\x10iJ\xfdo\xdf\x03\xe8\xec\xb8,\x99\xd7\xea\x1c0j\xbc\x18\x9fO;\xdf\x89X\x94>"\xe6\xa6\xd7U\t\xaa\xca\xef\xf0\xda\xd8\xdf\xd6\xc2*\xb9C\xf8\xfcm#z\xc9:\x85+{5\xa3<\xcd\xb2\x94M/\x80\x823u\x06\x7fI\xae\xf5\xc2\xc1\x15\xaf\x9c\xc4Yq\x86|\xd0\x8a')
|
||||
__pyarmor__(__name__, __file__, b"PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\x9a\x01\x00\x00\x12\t\x04\x00\xa9.\x02\x91|\x96\xea\x89\x92a\xc1\xc2p\xa2q&\x00\x00\x00\x00\x00\x00\x00\x00\xf3\x7f\x1bf\xe4\x1b\x00\xe7\x11\xe2\xd8g\xd5\x10\x1bHT\xd8+ok\xe9)6\xe9\xed\xf8X\xf6p\x08\xc9\x97\x00\xe7<o\x9a@\x1d\xb6&#\xb1\x01\xf5\xb6%\xb3\x84\x0c\xd5\xb5\xd8\x9b\x13\xb5\x8e\x89\xff\xe6[\x83]\xb3PrD\xc9\x86\x03\x83\xa3\xec\x96\xe2\x1a\x04\xeaX\xc4\x9fc\xb1Mx\x0183\xa0\xe1\x16G\x06EO\xe9:a/\xdb\x02\xb6\r\xe5\xde\x98@\x9a\xd0(\xd4\x0e0\xb4\xe3\xb4\xc6\x95[\xa9L{\xb2\xa7\x16\x17(\x86G\x13\xa8\xc6\xd6\xe5\xac\xe5\x13\x0f\x11 )\xe2K\x9c\x8c\xec\xda\x89w\xa3\x19$\xa7\xc1\xa4\xc8\x1e\x1d \x92\xeb\xe6\xc87E!\x87\x1c\xdd)<'\xa1A\x8b\xa1>\xeboW\xbe\x19&a\xa4\xb3\x0f\x1c\x05\xed\x80m\x05\xba.\xc8\xd8\xab\xb4\xf6s\x8e\x18C{\x97\x9dh*w\xe1\x1d%\xf7\x1f\x93\xe7\t\xefI\x1c\xef9#B\x82\xdb\x018\xfc\n\xd0\xe6\t\x9f+\x03\xe1\xf5:\x8b\x13\x8f\x19\x9e\x8f\x10l\xf8\xecsG\xbc\xa0\x1b\xe9\xbaWW\x8e\xfe\xe0\x1e\xa1\xb6)\n\xf9\xf1\xb9IR\xeb\x850\xc0D\x12\raJn\xe4\xe8n\xbd\xf5\x8c\xc5\x87\xcc\x97\x85\xf9\xbb,nxQ\xf7b6\xed\xa4\xb9\xaa\xe6\xc2\xb7R\x8f_P\xf7\xa4\x8c\xcd\xdb\xde\x89\x14\x94\xac\x1c\xcf\xd1\xa1\xf5`X7\xae\xf4\xc1f\xe3\xc2\x0e\xacO\xf0\xae\xef^9U\x8c\x82`\xac\xc8\x98\xbamg\xdb\xe1\xc0RY\xceU94\x08\xf0b+\xdc\x1b:N\xd5c\xae\xed\x06\xfd\xa1u\xcf|@\x8c\x89Q\xaag\xef\x7f\xcc(w\xf1\x97\x089\x15\\\xbf\xd4kNh\xcb\xb7\xb2f\x04")
|
||||
|
||||
440
templates/index _new.html
Normal file
440
templates/index _new.html
Normal file
@ -0,0 +1,440 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1"
|
||||
/>
|
||||
<title>Media Dashboard</title>
|
||||
<link rel="icon" type="image/x-icon" href="../static/images/favicon.ico" />
|
||||
<link rel="stylesheet" href="../static/css/styles.css" />
|
||||
<link rel="stylesheet" href="../static/fontawesome/css/all.min.css" />
|
||||
<style>
|
||||
/* High-contrast text everywhere */
|
||||
body,
|
||||
.content,
|
||||
h1, h2, h3, h4, h5, h6,
|
||||
p, label, .status,
|
||||
.checkbox-inline,
|
||||
.container,
|
||||
.form-group,
|
||||
.form-group * {
|
||||
color: #1f2937; /* gray-800 */
|
||||
}
|
||||
|
||||
*{ box-sizing: border-box; }
|
||||
html, body{ height: 100%; }
|
||||
body{
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
|
||||
line-height: 1.55;
|
||||
/* Page/background image/color is controlled by your existing CSS; unchanged */
|
||||
}
|
||||
|
||||
#navbar{ position: sticky; top: 0; z-index: 50; }
|
||||
|
||||
.content-wrapper{
|
||||
position: relative; /* anchor for the underlay image */
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 16px;
|
||||
z-index: 1; /* keep main content above the underlay */
|
||||
}
|
||||
@media (min-width: 980px){
|
||||
.content-wrapper{ padding: 24px; }
|
||||
}
|
||||
|
||||
.content{
|
||||
position: relative;
|
||||
z-index: 2; /* ensure UI is above the image */
|
||||
display: flex;
|
||||
flex-direction: column; /* stack containers vertically */
|
||||
align-items: center; /* center containers horizontally */
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* Ensure the main title spans full width and is centered above the panels */
|
||||
.content > h1{
|
||||
flex-basis: 100%;
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Underlay image: left-aligned, same size, no layout impact */
|
||||
.side-img{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 110px; /* adjust as you like */
|
||||
width: 230px; /* keep current size */
|
||||
height: auto;
|
||||
z-index: 0; /* behind everything */
|
||||
pointer-events: none; /* clicks go through */
|
||||
opacity: 1; /* fully visible; change if you want subtler */
|
||||
}
|
||||
|
||||
h1{
|
||||
margin: 0 0 8px;
|
||||
font-size: clamp(1.6rem, 2.2vw, 2.2rem);
|
||||
color: #333; /* explicit, high-contrast */
|
||||
}
|
||||
h2{
|
||||
margin: 0 0 10px;
|
||||
font-size: clamp(1.1rem, 1.8vw, 1.4rem);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Card containers – background color kept EXACTLY as before */
|
||||
.container{
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
margin: 0 0 16px;
|
||||
padding: 16px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 10px;
|
||||
background-color: #ffffffb6; /* unchanged */
|
||||
position: relative; /* creates its own stacking context above image */
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.form-group{ margin-bottom: 14px; }
|
||||
.form-group label{ display: block; margin-bottom: 6px; font-weight: 600; }
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea{
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
font-size: 1rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.checkbox-row{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.checkbox-inline{
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.button-group{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
margin: 12px 0 6px;
|
||||
}
|
||||
|
||||
.button-row{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.button-row .controls{ display:flex; gap:10px; }
|
||||
.button-row .actions{ margin-left: auto; }
|
||||
|
||||
.btn{
|
||||
appearance: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
padding: 10px 16px;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
color: #fff; /* keep buttons readable */
|
||||
background: #1e40af; /* blue-800 */
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn:hover{ background: #15327f; }
|
||||
.btn:focus-visible{
|
||||
outline: 3px solid #2563eb;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.btn[disabled]{ opacity: 0.6; cursor: not-allowed; }
|
||||
|
||||
.status{
|
||||
margin-top: 8px;
|
||||
font-size: 0.98rem;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
|
||||
.input-label{ text-align: left; }
|
||||
|
||||
.form-group textarea{
|
||||
resize: none;
|
||||
overflow-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* Optional: make sure the underlay doesn't collide on very small screens */
|
||||
@media (max-width: 480px){
|
||||
.side-img{ top: 140px; width: 190px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar"></div>
|
||||
<script>
|
||||
fetch('/static/html/nav.html')
|
||||
.then(r => r.ok ? r.text() : Promise.reject(r.status))
|
||||
.then(html => { document.getElementById('navbar').innerHTML = html; })
|
||||
.catch(() => { document.getElementById('navbar').innerHTML = '<div class="container" role="alert">Navigation failed to load.</div>'; });
|
||||
</script>
|
||||
|
||||
<div class="background-image"></div>
|
||||
|
||||
<main class="content-wrapper">
|
||||
<!-- Underlay image (beneath everything, left-aligned, fixed size) -->
|
||||
<img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img" />
|
||||
|
||||
<div class="content">
|
||||
<h1>Media Dashboard</h1>
|
||||
|
||||
<section class="container" aria-labelledby="playlist-heading">
|
||||
<h2 id="playlist-heading">Playlist Loop</h2>
|
||||
|
||||
<div class="checkbox-row">
|
||||
<label class="checkbox-inline" for="autoPlayAtBoot">
|
||||
<input type="checkbox" id="autoPlayAtBoot" name="autoPlayAtBoot">
|
||||
Autostart @ Boot
|
||||
</label>
|
||||
|
||||
<label class="checkbox-inline" for="saveSettings">
|
||||
<input type="checkbox" id="saveSettings" name="saveSettings">
|
||||
Save
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="mediaLocation">Media Sources</label>
|
||||
<select id="mediaLocation" name="mediaLocation" aria-describedby="mediaHelp">
|
||||
<option value="USB">No Media Available</option>
|
||||
</select>
|
||||
<div id="mediaHelp" class="sr-only">Choose a folder to loop through images.</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="imageDuration">Image Duration (secs)</label>
|
||||
<input type="number" id="imageDuration" name="imageDuration" min="1" max="60" inputmode="numeric">
|
||||
</div>
|
||||
|
||||
<div class="button-group" role="group" aria-label="Playlist loop controls">
|
||||
<button class="btn" id="btnStartLoop" onclick="startMediaLoop()">
|
||||
<i class="fa fa-play" aria-hidden="true"></i> Start
|
||||
</button>
|
||||
<button class="btn" id="btnStopLoop" onclick="stopMediaLoop()">
|
||||
<i class="fa fa-stop" aria-hidden="true"></i> Stop
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="status" id="mediaLoopStatus" role="status" aria-live="polite">status</div>
|
||||
</section>
|
||||
|
||||
<section class="container" aria-labelledby="gallery-heading">
|
||||
<h2 id="gallery-heading">Web Gallery</h2>
|
||||
|
||||
<div class="checkbox-row" style="justify-content:flex-start;">
|
||||
<label class="checkbox-inline" for="autoStart">
|
||||
<input type="checkbox" id="autoStart" name="autoStart">
|
||||
Autostart
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="galleryURL">URL</label>
|
||||
<textarea id="galleryURL" name="galleryURL" rows="3" placeholder="https://yahoo.com"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="button-row" role="group" aria-label="Web gallery controls">
|
||||
<div class="controls">
|
||||
<button class="btn" id="btnStartWeb" onclick="startWebGallery()">
|
||||
<i class="fa fa-play" aria-hidden="true"></i> Start
|
||||
</button>
|
||||
<button class="btn" id="btnStopWeb" onclick="stopWebGallery()">
|
||||
<i class="fa fa-stop" aria-hidden="true"></i> Stop
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" type="button" onclick="clearURL()">
|
||||
<i class="fa fa-eraser" aria-hidden="true"></i> Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status" id="webGalleryStatus" role="status" aria-live="polite">status</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function setBusy(el, busy){
|
||||
if (!el) return;
|
||||
el.disabled = !!busy;
|
||||
if (busy) el.setAttribute('aria-busy','true'); else el.removeAttribute('aria-busy');
|
||||
}
|
||||
function setText(id, text){
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = text || '';
|
||||
}
|
||||
|
||||
async function loadMediaSources(){
|
||||
try{
|
||||
const res = await fetch('../get_media_sources');
|
||||
const data = await res.json();
|
||||
const select = document.getElementById('mediaLocation');
|
||||
if (!select) return;
|
||||
// Clear existing
|
||||
select.innerHTML = '';
|
||||
const arr = Array.isArray(data?.folders) ? data.folders : [];
|
||||
if (arr.length === 0){
|
||||
const opt = document.createElement('option');
|
||||
opt.value = 'USB';
|
||||
opt.text = 'No Media Available';
|
||||
select.add(opt);
|
||||
return;
|
||||
}
|
||||
arr.forEach(m => {
|
||||
const opt = document.createElement('option');
|
||||
opt.text = m.folder_name_display;
|
||||
opt.value = m.folder_path;
|
||||
select.add(opt);
|
||||
});
|
||||
}catch(err){
|
||||
console.error('Error loading media sources:', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadLastUsedData(){
|
||||
try{
|
||||
const res = await fetch('../get_screen_settings');
|
||||
const data = await res.json();
|
||||
|
||||
// Only default if undefined (avoid forcing true when false)
|
||||
const apb = (data.autoPlayAtBoot === undefined) ? true : !!data.autoPlayAtBoot;
|
||||
const dur = (data.imageDuration === undefined) ? 5 : Number(data.imageDuration);
|
||||
const as = (data.autoStart === undefined) ? true : !!data.autoStart;
|
||||
const url = (data.url === undefined) ? 'google.com' : String(data.url);
|
||||
|
||||
document.getElementById('autoPlayAtBoot').checked = apb;
|
||||
document.getElementById('imageDuration').value = dur;
|
||||
document.getElementById('autoStart').checked = as;
|
||||
document.getElementById('galleryURL').value = url;
|
||||
document.getElementById('saveSettings').checked = false;
|
||||
}catch(err){
|
||||
console.error('Error loading screen settings:', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function startMediaLoop(){
|
||||
const mediaLocation = document.getElementById('mediaLocation').value;
|
||||
const imageDuration = document.getElementById('imageDuration').value;
|
||||
const autoPlayAtBoot = document.getElementById('autoPlayAtBoot').checked;
|
||||
const saveSettings = document.getElementById('saveSettings').checked;
|
||||
|
||||
// Reset the save toggle after reading
|
||||
document.getElementById('saveSettings').checked = false;
|
||||
|
||||
const btnStart = document.getElementById('btnStartLoop');
|
||||
const btnStop = document.getElementById('btnStopLoop');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('mediaLoopStatus', 'Starting media loop…');
|
||||
|
||||
try{
|
||||
const res = await fetch('../start_media_loop', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ mediaLocation, imageDuration, autoPlayAtBoot, saveSettings })
|
||||
});
|
||||
const data = await res.json();
|
||||
setText('mediaLoopStatus', data.message || 'Started.');
|
||||
}catch(err){
|
||||
console.error('Error during start media loop:', err);
|
||||
setText('mediaLoopStatus', 'Error during start media loop.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopMediaLoop(){
|
||||
const btnStart = document.getElementById('btnStartLoop');
|
||||
const btnStop = document.getElementById('btnStopLoop');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('mediaLoopStatus', 'Stopping media loop…');
|
||||
try{
|
||||
const res = await fetch('../stop_media_loop', { method: 'POST' });
|
||||
const data = await res.json();
|
||||
setText('mediaLoopStatus', data.message || 'Stopped.');
|
||||
}catch(err){
|
||||
console.error('Error during stop media loop:', err);
|
||||
setText('mediaLoopStatus', 'Error during stop media loop.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function startWebGallery(){
|
||||
const autoStart = document.getElementById('autoStart').checked;
|
||||
const url = document.getElementById('galleryURL').value;
|
||||
|
||||
const btnStart = document.getElementById('btnStartWeb');
|
||||
const btnStop = document.getElementById('btnStopWeb');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('webGalleryStatus', 'Starting web gallery…');
|
||||
|
||||
try{
|
||||
const res = await fetch('../start_web_gallery', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, autoStart })
|
||||
});
|
||||
const data = await res.json();
|
||||
setText('webGalleryStatus', data.message || 'Started.');
|
||||
}catch(err){
|
||||
console.error('Error during start web gallery:', err);
|
||||
setText('webGalleryStatus', 'Error during start web gallery.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopWebGallery(){
|
||||
const btnStart = document.getElementById('btnStartWeb');
|
||||
const btnStop = document.getElementById('btnStopWeb');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('webGalleryStatus', 'Stopping web gallery…');
|
||||
|
||||
try{
|
||||
const res = await fetch('../stop_web_gallery', { method: 'POST' });
|
||||
const data = await res.json();
|
||||
setText('webGalleryStatus', data.message || 'Stopped.');
|
||||
}catch(err){
|
||||
console.error('Error during stop web gallery:', err);
|
||||
setText('webGalleryStatus', 'Error during stop web gallery.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
function clearURL(){ document.getElementById('galleryURL').value = ''; }
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadLastUsedData();
|
||||
loadMediaSources();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,283 +1,451 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Media Dashboard</title>
|
||||
<link rel="icon" type="image/x-icon" href="../static/images/favicon.ico">
|
||||
<link rel="stylesheet" href="../static/css/styles.css">
|
||||
<link rel="stylesheet" href="../static/fontawesome/css/all.min.css">
|
||||
<style>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1"
|
||||
/>
|
||||
<title>Media Dashboard</title>
|
||||
<link rel="icon" type="image/x-icon" href="../static/images/favicon.ico" />
|
||||
<link rel="stylesheet" href="../static/css/styles.css" />
|
||||
<link rel="stylesheet" href="../static/fontawesome/css/all.min.css" />
|
||||
<style>
|
||||
/* High-contrast text everywhere */
|
||||
body,
|
||||
.content,
|
||||
h1, h2, h3, h4, h5, h6,
|
||||
p, label, .status,
|
||||
.checkbox-inline,
|
||||
.container,
|
||||
.form-group,
|
||||
.form-group * {
|
||||
color: #1f2937; /* gray-800 */
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 20px;
|
||||
font-size: 36px;
|
||||
color: #333;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 2px;
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
}
|
||||
.container {
|
||||
width: 80%;
|
||||
max-width: 300px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 10px;
|
||||
background-color: #ffffffb6;
|
||||
position: relative;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.form-group input, .form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.checkbox-group input {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.button-group .btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button-group .btn:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.status {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
.side-img {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
width: 230px; /* Set desired width */
|
||||
height: auto; /* Adjust height automatically to maintain aspect ratio */
|
||||
z-index: -1; /* Ensure image is behind other content */
|
||||
}
|
||||
.input-label{
|
||||
text-align: left;
|
||||
}
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
resize: none; /* Prevents the user from resizing the textarea */
|
||||
overflow-wrap: break-word; /* Ensures that long URLs wrap to the next line */
|
||||
white-space: pre-wrap; /* Preserves whitespace and wraps text as necessary */
|
||||
}
|
||||
</style>
|
||||
*{ box-sizing: border-box; }
|
||||
html, body{ height: 100%; }
|
||||
body{
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
|
||||
line-height: 1.55;
|
||||
/* Page/background image/color is controlled by your existing CSS; unchanged */
|
||||
}
|
||||
|
||||
#navbar{ position: sticky; top: 0; z-index: 50; }
|
||||
|
||||
.content-wrapper{
|
||||
position: relative; /* anchor for the underlay image */
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 16px;
|
||||
z-index: 1; /* keep main content above the underlay */
|
||||
}
|
||||
@media (min-width: 980px){
|
||||
.content-wrapper{ padding: 24px; }
|
||||
}
|
||||
|
||||
.content{
|
||||
position: relative;
|
||||
z-index: 2; /* ensure UI is above the image */
|
||||
display: flex;
|
||||
flex-direction: column; /* stack containers vertically */
|
||||
align-items: center; /* center containers horizontally */
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* Ensure the main title spans full width and is centered above the panels */
|
||||
.content > h1{
|
||||
flex-basis: 100%;
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Underlay image: left-aligned, same size, no layout impact */
|
||||
.side-img{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 110px; /* adjust as you like */
|
||||
width: 230px; /* keep current size */
|
||||
height: auto;
|
||||
z-index: 0; /* behind everything */
|
||||
pointer-events: none; /* clicks go through */
|
||||
opacity: 1; /* fully visible; change if you want subtler */
|
||||
}
|
||||
|
||||
h1{
|
||||
margin: 0 0 8px;
|
||||
font-size: clamp(1.6rem, 2.2vw, 2.2rem);
|
||||
color: #333; /* explicit, high-contrast */
|
||||
}
|
||||
h2{
|
||||
margin: 0 0 10px;
|
||||
font-size: clamp(1.1rem, 1.8vw, 1.4rem);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Card containers – background color kept EXACTLY as before */
|
||||
.container{
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
margin: 0 0 16px;
|
||||
padding: 16px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 10px;
|
||||
background-color: #ffffffb6; /* unchanged */
|
||||
position: relative; /* creates its own stacking context above image */
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.form-group{ margin-bottom: 14px; }
|
||||
.form-group label{ display: block; margin-bottom: 6px; font-weight: 600; }
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea{
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
font-size: 1rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.checkbox-row{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.checkbox-inline{
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
/* utility: push an inline checkbox/label to the far right inside a flex row */
|
||||
.checkbox-inline.right { margin-left: auto; }
|
||||
|
||||
.button-group{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
margin: 12px 0 6px;
|
||||
}
|
||||
|
||||
.button-row{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.button-row .controls{ display:flex; gap:10px; }
|
||||
.button-row .actions{ margin-left: auto; }
|
||||
|
||||
.btn{
|
||||
appearance: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
padding: 10px 16px;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
color: #fff; /* keep buttons readable */
|
||||
background: #1e40af; /* blue-800 */
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn:hover{ background: #15327f; }
|
||||
.btn:focus-visible{
|
||||
outline: 3px solid #2563eb;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.btn[disabled]{ opacity: 0.6; cursor: not-allowed; }
|
||||
|
||||
.status{
|
||||
margin-top: 8px;
|
||||
font-size: 0.98rem;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
|
||||
.input-label{ text-align: left; }
|
||||
|
||||
.form-group textarea{
|
||||
resize: none;
|
||||
overflow-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* Optional: make sure the underlay doesn't collide on very small screens */
|
||||
@media (max-width: 480px){
|
||||
.side-img{ top: 140px; width: 190px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar"></div>
|
||||
<script>
|
||||
fetch('/static/html/nav.html')
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
document.getElementById('navbar').innerHTML = data;
|
||||
});
|
||||
</script>
|
||||
<div id="navbar"></div>
|
||||
<script>
|
||||
fetch('/static/html/nav.html')
|
||||
.then(r => r.ok ? r.text() : Promise.reject(r.status))
|
||||
.then(html => { document.getElementById('navbar').innerHTML = html; })
|
||||
.catch(() => { document.getElementById('navbar').innerHTML = '<div class="container" role="alert">Navigation failed to load.</div>'; });
|
||||
</script>
|
||||
|
||||
<div class="background-image"></div>
|
||||
<div class="background-image"></div>
|
||||
|
||||
<!--<div><img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img"></div>-->
|
||||
<div class="content-wrapper">
|
||||
<div class="content">
|
||||
|
||||
<div>
|
||||
<img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img">
|
||||
</div>
|
||||
<h1>Media Dashboard</h1>
|
||||
<div class="container">
|
||||
<h2>Playlist Loop</h2>
|
||||
<div class="checkbox-group">
|
||||
<input type="checkbox" id="autoPlayAtBoot" name="autoPlayAtBoot" checked>
|
||||
<label for="autoPlayAtBoot">Autostart @Boot</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="mediaLocation">Media Sources:</label>
|
||||
<select id="mediaLocation" name="mediaLocation">
|
||||
<option value="USB">No Media Available</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="imageDuration">Image Duration in Secs:</label>
|
||||
<input type="number" id="imageDuration" name="imageDuration" min="1" max="60">
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button class="btn" onclick="startMediaLoop()">Start</button>
|
||||
<button class="btn" onclick="stopMediaLoop()">Stop</button>
|
||||
</div>
|
||||
<div class="status" id="mediaLoopStatus">status</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h2>Web Gallery</h2>
|
||||
<div class="checkbox-group">
|
||||
<input type="checkbox" id="autoStart" name="autoStart" checked>
|
||||
<label for="autoStart">Autostart</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn" onclick="clearURL()">Clear</button>
|
||||
<label class="input-label" for="galleryURL">URL:</label>
|
||||
<textarea id="galleryURL" name="galleryURL" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button class="btn" onclick="startWebGallery()">Start</button>
|
||||
<button class="btn" onclick="stopWebGallery()">Stop</button>
|
||||
</div>
|
||||
<div class="status" id="webGalleryStatus">status</div>
|
||||
</div>
|
||||
<main class="content-wrapper">
|
||||
<!-- Underlay image (beneath everything, left-aligned, fixed size) -->
|
||||
<img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img" />
|
||||
|
||||
<div class="content">
|
||||
<h1>Media Dashboard</h1>
|
||||
|
||||
<section class="container" aria-labelledby="playlist-heading">
|
||||
<h2 id="playlist-heading">Playlist Loop</h2>
|
||||
|
||||
<div class="checkbox-row">
|
||||
<label class="checkbox-inline" for="autoPlayAtBoot">
|
||||
<input type="checkbox" id="autoPlayAtBoot" name="autoPlayAtBoot">
|
||||
Autostart @ Boot
|
||||
</label>
|
||||
|
||||
<label class="checkbox-inline" for="saveSettings">
|
||||
<input type="checkbox" id="saveSettings" name="saveSettings">
|
||||
Save
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="mediaLocation">Media Sources</label>
|
||||
<select id="mediaLocation" name="mediaLocation" aria-describedby="mediaHelp">
|
||||
<option value="USB">No Media Available</option>
|
||||
</select>
|
||||
<div id="mediaHelp" class="sr-only">Choose a folder to loop through images.</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="imageDuration">Image Duration (secs)</label>
|
||||
<input type="number" id="imageDuration" name="imageDuration" min="1" max="60" inputmode="numeric">
|
||||
</div>
|
||||
|
||||
<div class="button-group" role="group" aria-label="Playlist loop controls">
|
||||
<button class="btn" id="btnStartLoop" onclick="startMediaLoop()">
|
||||
<i class="fa fa-play" aria-hidden="true"></i> Start
|
||||
</button>
|
||||
<button class="btn" id="btnStopLoop" onclick="stopMediaLoop()">
|
||||
<i class="fa fa-stop" aria-hidden="true"></i> Stop
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="status" id="mediaLoopStatus" role="status" aria-live="polite">status</div>
|
||||
</section>
|
||||
|
||||
<section class="container" aria-labelledby="gallery-heading">
|
||||
<h2 id="gallery-heading">Web Gallery</h2>
|
||||
|
||||
<div class="checkbox-row" style="justify-content:flex-start;">
|
||||
<label class="checkbox-inline" for="autoStart">
|
||||
<input type="checkbox" id="autoStart" name="autoStart">
|
||||
Autostart
|
||||
</label>
|
||||
|
||||
<label class="checkbox-inline right" for="saveWebSettings">
|
||||
<input type="checkbox" id="saveWebSettings" name="saveWebSettings">
|
||||
Save
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="galleryURL">URL</label>
|
||||
<textarea id="galleryURL" name="galleryURL" rows="3" placeholder="https://yahoo.com"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="button-row" role="group" aria-label="Web gallery controls">
|
||||
<div class="controls">
|
||||
<button class="btn" id="btnStartWeb" onclick="startWebGallery()">
|
||||
<i class="fa fa-play" aria-hidden="true"></i> Start
|
||||
</button>
|
||||
<button class="btn" id="btnStopWeb" onclick="stopWebGallery()">
|
||||
<i class="fa fa-stop" aria-hidden="true"></i> Stop
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" type="button" onclick="clearURL()">
|
||||
<i class="fa fa-eraser" aria-hidden="true"></i> Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status" id="webGalleryStatus" role="status" aria-live="polite">status</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function setBusy(el, busy){
|
||||
if (!el) return;
|
||||
el.disabled = !!busy;
|
||||
if (busy) el.setAttribute('aria-busy','true'); else el.removeAttribute('aria-busy');
|
||||
}
|
||||
function setText(id, text){
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = text || '';
|
||||
}
|
||||
|
||||
<script>
|
||||
function loadMediaSources() {
|
||||
fetch('../get_media_sources')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
media_sources = data.folders; // Access the "folders" array in the JSON
|
||||
const mediaLocationSelect = document.getElementById('mediaLocation');
|
||||
|
||||
// Clear any existing options
|
||||
while (mediaLocationSelect.options.length > 0) {
|
||||
mediaLocationSelect.remove(0);
|
||||
}
|
||||
|
||||
// Add new options
|
||||
media_sources.forEach(media => {
|
||||
var option = document.createElement('option');
|
||||
option.text = media.folder_name_display;
|
||||
option.value = media.folder_path;
|
||||
mediaLocationSelect.add(option);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error loading media sources:", error);
|
||||
});
|
||||
async function loadMediaSources(){
|
||||
try{
|
||||
const res = await fetch('../get_media_sources');
|
||||
const data = await res.json();
|
||||
const select = document.getElementById('mediaLocation');
|
||||
if (!select) return;
|
||||
// Clear existing
|
||||
select.innerHTML = '';
|
||||
const arr = Array.isArray(data?.folders) ? data.folders : [];
|
||||
if (arr.length === 0){
|
||||
const opt = document.createElement('option');
|
||||
opt.value = 'USB';
|
||||
opt.text = 'No Media Available';
|
||||
select.add(opt);
|
||||
return;
|
||||
}
|
||||
arr.forEach(m => {
|
||||
const opt = document.createElement('option');
|
||||
opt.text = m.folder_name_display;
|
||||
opt.value = m.folder_path;
|
||||
select.add(opt);
|
||||
});
|
||||
}catch(err){
|
||||
console.error('Error loading media sources:', err);
|
||||
}
|
||||
}
|
||||
|
||||
function loadLastUsedData() {
|
||||
fetch('../get_screen_settings')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.info(data)
|
||||
document.getElementById('autoPlayAtBoot').checked = data.autoPlayAtBoot || true;
|
||||
document.getElementById('imageDuration').value = data.imageDuration || 5;
|
||||
document.getElementById('autoStart').checked = data.autoStart || true;
|
||||
document.getElementById('galleryURL').value = data.url || 'google.com';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error loading screen settings:", error);
|
||||
});
|
||||
}
|
||||
async function loadLastUsedData(){
|
||||
try{
|
||||
const res = await fetch('../get_screen_settings');
|
||||
const data = await res.json();
|
||||
|
||||
function startMediaLoop() {
|
||||
const mediaLocation = document.getElementById('mediaLocation').value;
|
||||
const imageDuration = document.getElementById('imageDuration').value;
|
||||
const autoPlayAtBoot = document.getElementById('autoPlayAtBoot').checked;
|
||||
// Only default if undefined (avoid forcing true when false)
|
||||
const apb = (data.autoPlayAtBoot === undefined) ? true : !!data.autoPlayAtBoot;
|
||||
const dur = (data.imageDuration === undefined) ? 5 : Number(data.imageDuration);
|
||||
const as = (data.autoStart === undefined) ? true : !!data.autoStart;
|
||||
const url = (data.url === undefined) ? 'google.com' : String(data.url);
|
||||
|
||||
fetch('../start_media_loop', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ mediaLocation: mediaLocation, imageDuration: imageDuration , autoPlayAtBoot: autoPlayAtBoot})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('mediaLoopStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during start media loop:", error);
|
||||
document.getElementById('mediaLoopStatus').innerText = "Error during start media loop.";
|
||||
});
|
||||
}
|
||||
document.getElementById('autoPlayAtBoot').checked = apb;
|
||||
document.getElementById('imageDuration').value = dur;
|
||||
document.getElementById('autoStart').checked = as;
|
||||
document.getElementById('galleryURL').value = url;
|
||||
document.getElementById('saveSettings').checked = false;
|
||||
}catch(err){
|
||||
console.error('Error loading screen settings:', err);
|
||||
}
|
||||
}
|
||||
|
||||
function stopMediaLoop() {
|
||||
fetch('../stop_media_loop', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('mediaLoopStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during stop media loop:", error);
|
||||
document.getElementById('mediaLoopStatus').innerText = "Error during stop media loop.";
|
||||
});
|
||||
}
|
||||
async function startMediaLoop(){
|
||||
const mediaLocation = document.getElementById('mediaLocation').value;
|
||||
const imageDuration = document.getElementById('imageDuration').value;
|
||||
const autoPlayAtBoot = document.getElementById('autoPlayAtBoot').checked;
|
||||
const saveSettings = document.getElementById('saveSettings').checked;
|
||||
|
||||
function startWebGallery() {
|
||||
const autoStart = document.getElementById('autoStart').checked;
|
||||
const url = document.getElementById('galleryURL').value
|
||||
fetch('../start_web_gallery', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ url: url, autoStart: autoStart })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('webGalleryStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during start web gallery:", error);
|
||||
document.getElementById('webGalleryStatus').innerText = "Error during start web gallery.";
|
||||
});
|
||||
}
|
||||
// Reset the save toggle after reading
|
||||
document.getElementById('saveSettings').checked = false;
|
||||
|
||||
function stopWebGallery() {
|
||||
fetch('../stop_web_gallery', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('webGalleryStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during stop web gallery:", error);
|
||||
document.getElementById('webGalleryStatus').innerText = "Error during stop web gallery.";
|
||||
});
|
||||
}
|
||||
|
||||
function clearURL() {
|
||||
document.getElementById('galleryURL').value = '';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', loadLastUsedData);
|
||||
const btnStart = document.getElementById('btnStartLoop');
|
||||
const btnStop = document.getElementById('btnStopLoop');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('mediaLoopStatus', 'Starting media loop…');
|
||||
|
||||
// Call the function to load media sources when the page loads
|
||||
window.onload = loadMediaSources;
|
||||
</script>
|
||||
try{
|
||||
const res = await fetch('../start_media_loop', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ mediaLocation, imageDuration, autoPlayAtBoot, saveSettings })
|
||||
});
|
||||
const data = await res.json();
|
||||
setText('mediaLoopStatus', data.message || 'Started.');
|
||||
}catch(err){
|
||||
console.error('Error during start media loop:', err);
|
||||
setText('mediaLoopStatus', 'Error during start media loop.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopMediaLoop(){
|
||||
const btnStart = document.getElementById('btnStartLoop');
|
||||
const btnStop = document.getElementById('btnStopLoop');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('mediaLoopStatus', 'Stopping media loop…');
|
||||
try{
|
||||
const res = await fetch('../stop_media_loop', { method: 'POST' });
|
||||
const data = await res.json();
|
||||
setText('mediaLoopStatus', data.message || 'Stopped.');
|
||||
}catch(err){
|
||||
console.error('Error during stop media loop:', err);
|
||||
setText('mediaLoopStatus', 'Error during stop media loop.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function startWebGallery(){
|
||||
const autoStart = document.getElementById('autoStart').checked;
|
||||
const url = document.getElementById('galleryURL').value;
|
||||
|
||||
const btnStart = document.getElementById('btnStartWeb');
|
||||
const btnStop = document.getElementById('btnStopWeb');
|
||||
const saveWebSettings = document.getElementById('saveWebSettings').checked;
|
||||
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('webGalleryStatus', 'Starting web gallery…');
|
||||
|
||||
try{
|
||||
const res = await fetch('../start_web_gallery', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, autoStart, saveWebSettings })
|
||||
});
|
||||
const data = await res.json();
|
||||
setText('webGalleryStatus', data.message || 'Started.');
|
||||
}catch(err){
|
||||
console.error('Error during start web gallery:', err);
|
||||
setText('webGalleryStatus', 'Error during start web gallery.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
document.getElementById('saveWebSettings').checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function stopWebGallery(){
|
||||
const btnStart = document.getElementById('btnStartWeb');
|
||||
const btnStop = document.getElementById('btnStopWeb');
|
||||
setBusy(btnStart, true); setBusy(btnStop, true);
|
||||
setText('webGalleryStatus', 'Stopping web gallery…');
|
||||
|
||||
try{
|
||||
const res = await fetch('../stop_web_gallery', { method: 'POST' });
|
||||
const data = await res.json();
|
||||
setText('webGalleryStatus', data.message || 'Stopped.');
|
||||
}catch(err){
|
||||
console.error('Error during stop web gallery:', err);
|
||||
setText('webGalleryStatus', 'Error during stop web gallery.');
|
||||
}finally{
|
||||
setBusy(btnStart, false); setBusy(btnStop, false);
|
||||
}
|
||||
}
|
||||
|
||||
function clearURL(){ document.getElementById('galleryURL').value = ''; }
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadLastUsedData();
|
||||
loadMediaSources();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
313
templates/index_orig.html
Normal file
313
templates/index_orig.html
Normal file
@ -0,0 +1,313 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Media Dashboard</title>
|
||||
<link rel="icon" type="image/x-icon" href="../static/images/favicon.ico">
|
||||
<link rel="stylesheet" href="../static/css/styles.css">
|
||||
<link rel="stylesheet" href="../static/fontawesome/css/all.min.css">
|
||||
<style>
|
||||
|
||||
h1 {
|
||||
margin-top: 20px;
|
||||
font-size: 36px;
|
||||
color: #333;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 2px;
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
}
|
||||
.container {
|
||||
width: 80%;
|
||||
max-width: 300px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 10px;
|
||||
background-color: #ffffffb6;
|
||||
position: relative;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.form-group input, .form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.checkbox-group input {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.checkbox-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.checkbox-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.right-align {
|
||||
margin-left: auto;
|
||||
}
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.button-group .btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button-group .btn:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.status {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
.side-img {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
width: 230px; /* Set desired width */
|
||||
height: auto; /* Adjust height automatically to maintain aspect ratio */
|
||||
z-index: -1; /* Ensure image is behind other content */
|
||||
}
|
||||
.input-label{
|
||||
text-align: left;
|
||||
}
|
||||
.form-group textarea {
|
||||
/* Ensure the main title spans full width and is centered above the panels */
|
||||
.content > h1{
|
||||
flex-basis: 100%;
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
resize: none; /* Prevents the user from resizing the textarea */
|
||||
overflow-wrap: break-word; /* Ensures that long URLs wrap to the next line */
|
||||
white-space: pre-wrap; /* Preserves whitespace and wraps text as necessary */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar"></div>
|
||||
<script>
|
||||
fetch('/static/html/nav.html')
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
document.getElementById('navbar').innerHTML = data;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="background-image"></div>
|
||||
|
||||
<!--<div><img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img"></div>-->
|
||||
<div class="content-wrapper">
|
||||
<div class="content">
|
||||
|
||||
<div>
|
||||
<img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img">
|
||||
</div>
|
||||
<h1>Media Dashboard</h1>
|
||||
<div class="container">
|
||||
<h2>Playlist Loop</h2>
|
||||
|
||||
<div class="checkbox-row">
|
||||
<div class="checkbox-inline">
|
||||
<input type="checkbox" id="autoPlayAtBoot" name="autoPlayAtBoot" unchecked>
|
||||
<label for="autoPlayAtBoot">Autostart @Boot</label>
|
||||
</div>
|
||||
<div class="checkbox-inline right-align">
|
||||
<input type="checkbox" id="saveSettings" name="saveSettings" unchecked>
|
||||
<label for="saveSettings">Save</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="mediaLocation">Media Sources:</label>
|
||||
<select id="mediaLocation" name="mediaLocation">
|
||||
<option value="USB">No Media Available</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="imageDuration">Image Duration in Secs:</label>
|
||||
<input type="number" id="imageDuration" name="imageDuration" min="1" max="60">
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button class="btn" onclick="startMediaLoop()">Start</button>
|
||||
<button class="btn" onclick="stopMediaLoop()">Stop</button>
|
||||
</div>
|
||||
<div class="status" id="mediaLoopStatus">status</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h2>Web Gallery</h2>
|
||||
<div class="checkbox-group">
|
||||
<input type="checkbox" id="autoStart" name="autoStart" unchecked>
|
||||
<label for="autoStart">Autostart</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn" onclick="clearURL()">Clear</button>
|
||||
<label class="input-label" for="galleryURL">URL:</label>
|
||||
<textarea id="galleryURL" name="galleryURL" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button class="btn" onclick="startWebGallery()">Start</button>
|
||||
<button class="btn" onclick="stopWebGallery()">Stop</button>
|
||||
</div>
|
||||
<div class="status" id="webGalleryStatus">status</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function loadMediaSources() {
|
||||
fetch('../get_media_sources')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
media_sources = data.folders; // Access the "folders" array in the JSON
|
||||
const mediaLocationSelect = document.getElementById('mediaLocation');
|
||||
|
||||
// Clear any existing options
|
||||
while (mediaLocationSelect.options.length > 0) {
|
||||
mediaLocationSelect.remove(0);
|
||||
}
|
||||
|
||||
// Add new options
|
||||
media_sources.forEach(media => {
|
||||
var option = document.createElement('option');
|
||||
option.text = media.folder_name_display;
|
||||
option.value = media.folder_path;
|
||||
mediaLocationSelect.add(option);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error loading media sources:", error);
|
||||
});
|
||||
}
|
||||
|
||||
function loadLastUsedData() {
|
||||
fetch('../get_screen_settings')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.info(data)
|
||||
document.getElementById('autoPlayAtBoot').checked = data.autoPlayAtBoot || true;
|
||||
document.getElementById('imageDuration').value = data.imageDuration || 5;
|
||||
document.getElementById('autoStart').checked = data.autoStart || true;
|
||||
document.getElementById('galleryURL').value = data.url || 'google.com';
|
||||
document.getElementById('saveSettings').checked = false;
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error loading screen settings:", error);
|
||||
});
|
||||
}
|
||||
|
||||
function startMediaLoop() {
|
||||
const mediaLocation = document.getElementById('mediaLocation').value;
|
||||
const imageDuration = document.getElementById('imageDuration').value;
|
||||
const autoPlayAtBoot = document.getElementById('autoPlayAtBoot').checked;
|
||||
const saveSettings = document.getElementById('saveSettings').checked;
|
||||
document.getElementById('saveSettings').checked = false;
|
||||
|
||||
fetch('../start_media_loop', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ mediaLocation: mediaLocation, imageDuration: imageDuration , autoPlayAtBoot: autoPlayAtBoot, saveSettings: saveSettings})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('mediaLoopStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during start media loop:", error);
|
||||
document.getElementById('mediaLoopStatus').innerText = "Error during start media loop.";
|
||||
});
|
||||
}
|
||||
|
||||
function stopMediaLoop() {
|
||||
fetch('../stop_media_loop', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('mediaLoopStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during stop media loop:", error);
|
||||
document.getElementById('mediaLoopStatus').innerText = "Error during stop media loop.";
|
||||
});
|
||||
}
|
||||
|
||||
function startWebGallery() {
|
||||
const autoStart = document.getElementById('autoStart').checked;
|
||||
const url = document.getElementById('galleryURL').value
|
||||
fetch('../start_web_gallery', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ url: url, autoStart: autoStart })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('webGalleryStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during start web gallery:", error);
|
||||
document.getElementById('webGalleryStatus').innerText = "Error during start web gallery.";
|
||||
});
|
||||
}
|
||||
|
||||
function stopWebGallery() {
|
||||
fetch('../stop_web_gallery', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('webGalleryStatus').innerText = data.message;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error during stop web gallery:", error);
|
||||
document.getElementById('webGalleryStatus').innerText = "Error during stop web gallery.";
|
||||
});
|
||||
}
|
||||
|
||||
function clearURL() {
|
||||
document.getElementById('galleryURL').value = '';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', loadLastUsedData);
|
||||
|
||||
// Call the function to load media sources when the page loads
|
||||
window.onload = loadMediaSources;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user