Skip to content

Commit 68e221c

Browse files
authored
feat(switcher): implement per-URL duration and refresh cycle configuration (#93)
* feature/parameterization * change config format * remove low-end-device flag
1 parent 45fa0d4 commit 68e221c

File tree

5 files changed

+215
-80
lines changed

5 files changed

+215
-80
lines changed

config.json.sample

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
11
{
2-
"urls": [
3-
{
4-
"url": "https://windy.com/"
5-
},
6-
{
7-
"url": "https://time.is/clock"
8-
},
9-
{
10-
"url": "https://github.com/trending"
11-
},
12-
{
13-
"url": "https://news.ycombinator.com/"
14-
},
15-
{
16-
"url": "https://huggingface.co/papers"
17-
},
18-
{
19-
"url": "https://www.perplexity.ai/discover"
20-
},
21-
{
22-
"url": "https://www.google.com/search?q=nasdaq+index"
23-
}
24-
]
25-
}
2+
"urls": [
3+
{
4+
"url": "https://windy.com/",
5+
"duration": 10,
6+
"cycles": 10
7+
},
8+
{
9+
"url": "https://time.is/clock",
10+
"duration": 10,
11+
"cycles": 10
12+
},
13+
{
14+
"url": "https://github.com/trending",
15+
"duration": 10,
16+
"cycles": 10
17+
},
18+
{
19+
"url": "https://news.ycombinator.com/",
20+
"duration": 10,
21+
"cycles": 10
22+
},
23+
{
24+
"url": "https://huggingface.co/papers",
25+
"duration": 10,
26+
"cycles": 10
27+
},
28+
{
29+
"url": "https://www.perplexity.ai/discover",
30+
"duration": 10,
31+
"cycles": 10
32+
},
33+
{
34+
"url": "https://www.google.com/search?q=nasdaq+index",
35+
"duration": 10,
36+
"cycles": 10
37+
}
38+
]
39+
}

scripts/runner.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ chromium-browser \
1111
--disable-smooth-scrolling \
1212
--enable-accelerated-video-decode \
1313
--enable-gpu-rasterization \
14-
--enable-low-end-device-mode \
1514
--enable-oop-rasterization \
1615
--force-device-scale-factor=1 \
1716
--ignore-gpu-blocklist \

scripts/switcher.sh

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,74 @@
11
#!/bin/bash
22

3-
# @TODO: fetch the user dynamically or from config
3+
# Ensure the script runs from the correct directory, where config.json is located.
4+
cd /opt/piosk
5+
46
export XDG_RUNTIME_DIR=/run/user/1000
57

6-
# THIS IS NOT THE BEST WAY TO SWITCH & REFRESH TABS BUT IT WORKS
7-
# should parameterize cycle count & sleep delay with config.json
8-
9-
# count the number of URLs, that are configured to cycle through
10-
URLS=$(jq -r '.urls | length' /opt/piosk/config.json)
11-
12-
# swich tabs each 10s, refresh tabs each 10th cycle & then reset
13-
for ((TURN=1; TURN<=$((10*URLS)); TURN++)) do
14-
if [ $TURN -le $((10*URLS)) ]; then
15-
wtype -M ctrl -P Tab
16-
if [ $TURN -gt $((9*URLS)) ]; then
17-
wtype -M ctrl r
18-
if [ $TURN -eq $((10*URLS)) ]; then
19-
(( TURN=0 ))
20-
fi
21-
fi
22-
fi
23-
sleep 10
8+
# --- Read Configuration using jq ---
9+
# Create a Bash array of durations for each URL.
10+
mapfile -t DURATIONS < <(jq -r '.urls[].duration' ./config.json)
11+
12+
# Create a Bash array of cycle counts before a refresh is triggered.
13+
mapfile -t CYCLES < <(jq -r '.urls[].cycles' ./config.json)
14+
15+
# Count the total number of URLs to manage.
16+
URL_COUNT=${#DURATIONS[@]}
17+
18+
# If no URLs are configured, exit gracefully.
19+
if [ "$URL_COUNT" -eq 0 ]; then
20+
echo "No URLs configured. Exiting switcher."
21+
exit 0
22+
fi
23+
24+
# --- Initialize State ---
25+
# Create and initialize an array to track the display count for each tab.
26+
REFRESH_COUNTS=()
27+
for ((i=0; i<URL_COUNT; i++)); do
28+
REFRESH_COUNTS+=(0)
2429
done
30+
31+
CURRENT_TAB_INDEX=0
32+
33+
# Give Chromium a moment to start up on boot before we start sending keys.
34+
echo "Switcher waiting for browser to initialize..."
35+
sleep 15
36+
37+
echo "PiOSK switcher started. Managing $URL_COUNT tabs."
38+
39+
# --- Main Loop ---
40+
while true; do
41+
# --- Get Settings for the Current Tab ---
42+
duration=${DURATIONS[$CURRENT_TAB_INDEX]}
43+
cycle_target=${CYCLES[$CURRENT_TAB_INDEX]}
44+
45+
# --- Handle Refresh Logic ---
46+
# Increment the display counter for the current tab.
47+
((REFRESH_COUNTS[$CURRENT_TAB_INDEX]++))
48+
echo "Tab $((CURRENT_TAB_INDEX + 1)): Display cycle ${REFRESH_COUNTS[$CURRENT_TAB_INDEX]} of $cycle_target."
49+
50+
# Check if it's time to refresh this specific tab.
51+
if [ "${REFRESH_COUNTS[$CURRENT_TAB_INDEX]}" -ge "$cycle_target" ]; then
52+
echo "Refreshing Tab $((CURRENT_TAB_INDEX + 1))."
53+
54+
# Send Ctrl+r to refresh the current tab using wtype.
55+
wtype -M ctrl r -m ctrl
56+
57+
# Reset the counter for this tab.
58+
REFRESH_COUNTS[$CURRENT_TAB_INDEX]=0
59+
fi
60+
61+
# --- Wait for the specified duration ---
62+
echo "Waiting for $duration seconds."
63+
sleep "$duration"
64+
65+
# --- Switch to the Next Tab ---
66+
echo "Switching to next tab."
67+
# Send Ctrl+Tab to switch to the next tab using wtype.
68+
wtype -M ctrl -P Tab -m ctrl
69+
70+
# --- Update Tab Index ---
71+
# Move to the next index, wrapping around to 0 if at the end.
72+
CURRENT_TAB_INDEX=$(( (CURRENT_TAB_INDEX + 1) % URL_COUNT ))
73+
74+
done

web/index.html

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,26 @@
77
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
88

99
<title>PiOSK</title>
10+
<style>
11+
.input-changed {
12+
background-color: rgba(255, 193, 7, 0.2) !important;
13+
border-color: #ffc107 !important;
14+
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.25) !important;
15+
transition: all 0.3s ease;
16+
}
17+
.input-changed:focus {
18+
background-color: rgba(255, 193, 7, 0.3) !important;
19+
border-color: #ffc107 !important;
20+
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5) !important;
21+
}
22+
</style>
1023
</head>
1124
<body>
1225
<nav id="navs" class="navbar bg-body-tertiary">
1326
<div class="container-md d-flex justify-content-between">
1427
<h1 class="my-1">Pi<span class="bg-danger mx-1 px-1 rounded">OSK</span></h1>
1528
<div class="input-group w-75">
16-
<input id="new-url" type="text" class="form-control form-control-lg" placeholder="...add URLs of webpages as screens">
29+
<input id="new-url" type="text" class="form-control form-control-lg" placeholder="...add URLs of webpages as screens">
1730
<button id="add-url" type="button" class="btn btn-secondary">ADD</button>
1831
<button id="execute" type="button" class="btn btn-danger">APPLY <span class="align-text-bottom"></span></button>
1932
</div>
@@ -33,9 +46,24 @@ <h1 class="my-1">Pi<span class="bg-danger mx-1 px-1 rounded">OSK</span></h1>
3346
</footer>
3447

3548
<template id="template-url">
36-
<li class="list-group-item text-truncate fs-3">
37-
<button type="button" class="btn btn-close mx-3" aria-label="Remove"></button>
38-
<a class="link-underline-dark"></a>
49+
<li class="list-group-item fs-3">
50+
<div class="d-flex justify-content-between align-items-center">
51+
<div class="d-flex align-items-center flex-grow-1">
52+
<button type="button" class="btn btn-close mx-3" aria-label="Remove"></button>
53+
<a class="link-underline-dark text-truncate"></a>
54+
</div>
55+
<div class="d-flex align-items-center gap-2 ms-3">
56+
<div class="input-group input-group-sm" style="width: 150px;">
57+
<span class="input-group-text">Duration</span>
58+
<input type="number" class="form-control duration-input" min="1" max="300" value="10">
59+
<span class="input-group-text">s</span>
60+
</div>
61+
<div class="input-group input-group-sm" style="width: 120px;">
62+
<span class="input-group-text">Cycles</span>
63+
<input type="number" class="form-control cycles-input" min="1" max="100" value="10">
64+
</div>
65+
</div>
66+
</div>
3967
</li>
4068
</template>
4169

@@ -45,6 +73,22 @@ <h1 class="my-1">Pi<span class="bg-danger mx-1 px-1 rounded">OSK</span></h1>
4573

4674
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
4775
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
76+
77+
<script>
78+
$(document).ready(function() {
79+
// Use event delegation to highlight inputs when they are changed.
80+
$('#urls').on('change', '.duration-input, .cycles-input', function() {
81+
$(this).addClass('input-changed');
82+
});
83+
84+
// Add a separate click listener to the Apply button just to remove the highlight.
85+
// This will fire alongside the listener in script.js that saves the data.
86+
$('#execute').on('click', function() {
87+
$('.input-changed').removeClass('input-changed');
88+
});
89+
});
90+
</script>
91+
4892
<script src="script.js"></script>
4993
</body>
5094
</html>

web/script.js

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,76 @@
11
let piosk = {
2-
addNewUrl () {
3-
let newUrl = $('#new-url').val()
4-
if (!newUrl) return
2+
addNewUrl() {
3+
let newUrl = $('#new-url').val();
4+
if (!newUrl) return;
55

6-
piosk.appendUrl(newUrl)
7-
$('#new-url').val('')
6+
// Call appendUrl with just the URL, so it uses default settings (10s, 10 cycles)
7+
piosk.appendUrl(newUrl);
8+
$('#new-url').val('');
89
},
9-
appendUrl (url) {
10-
let tmpUrl = $('#template-url').contents().clone()
1110

12-
$(tmpUrl).find('a').attr('href', url).html(url)
13-
$('#urls .list-group').append(tmpUrl)
11+
// MODIFIED: Now accepts duration and cycles as arguments
12+
appendUrl(url, duration, cycles) {
13+
let tmpUrl = $('#template-url').contents().clone();
14+
15+
$(tmpUrl).find('a').attr('href', url).html(url);
16+
17+
// If duration and cycles are provided from config, set them.
18+
if (duration) {
19+
$(tmpUrl).find('.duration-input').val(duration);
20+
}
21+
if (cycles) {
22+
$(tmpUrl).find('.cycles-input').val(cycles);
23+
}
24+
25+
$('#urls .list-group').append(tmpUrl);
1426
},
15-
renderPage (data) {
16-
$.each(data.urls, (index, item) => {
17-
piosk.appendUrl(item.url)
18-
})
27+
28+
// MODIFIED: Now passes the full item data to appendUrl
29+
renderPage(data) {
30+
if (data && data.urls) {
31+
$.each(data.urls, (index, item) => {
32+
// Pass all the data (url, duration, cycles) to the updated function
33+
piosk.appendUrl(item.url, item.duration, item.cycles);
34+
});
35+
}
1936
},
20-
showStatus (xhr) {
21-
let tmpErr = $('#template-err').contents().clone()
22-
tmpErr.html(xhr.responseText)
23-
$('#urls').append(tmpErr)
24-
setTimeout(_ => { $('.alert-danger').remove() }, 5000)
37+
38+
showStatus(xhr) {
39+
let tmpErr = $('#template-err').contents().clone();
40+
tmpErr.html(xhr.responseText);
41+
$('#urls').append(tmpErr);
42+
setTimeout(_ => { $('.alert-danger').remove() }, 5000);
2543
}
26-
}
44+
};
2745

2846
$(document).ready(() => {
2947
$.getJSON('/config')
30-
.done(piosk.renderPage)
31-
.fail(piosk.showStatus)
48+
.done(piosk.renderPage)
49+
.fail(piosk.showStatus);
3250

33-
$('#add-url').on('click', piosk.addNewUrl)
34-
$('#new-url').on('keyup', (e) => { if (e.key === 'Enter') piosk.addNewUrl() })
51+
$('#add-url').on('click', piosk.addNewUrl);
52+
$('#new-url').on('keyup', (e) => { if (e.key === 'Enter') piosk.addNewUrl(); });
3553

3654
$('#urls').on('click', 'button.btn-close', (e) => {
37-
$(e.target).parent().remove()
38-
})
55+
$(e.target).closest('li.list-group-item').remove();
56+
});
3957

58+
// MODIFIED: The #execute handler now saves all settings correctly
4059
$('#execute').on('click', (e) => {
41-
let config = {}
42-
config.urls = []
60+
let config = {};
61+
config.urls = [];
4362
$('li.list-group-item').each((index, item) => {
44-
config.urls.push({ url: $(item).find('a').attr('href') })
45-
})
63+
// Now collecting all data: url, duration, and cycles
64+
const url = $(item).find('a').attr('href');
65+
const duration = parseInt($(item).find('.duration-input').val()) || 10;
66+
const cycles = parseInt($(item).find('.cycles-input').val()) || 10;
67+
68+
config.urls.push({
69+
url: url,
70+
duration: duration,
71+
cycles: cycles
72+
});
73+
});
4674

4775
$.ajax({
4876
url: '/config',
@@ -52,6 +80,6 @@ $(document).ready(() => {
5280
dataType: "json",
5381
success: piosk.showStatus,
5482
error: piosk.showStatus
55-
})
56-
})
57-
})
83+
});
84+
});
85+
});

0 commit comments

Comments
 (0)