-
-
Notifications
You must be signed in to change notification settings - Fork 140
Expand file tree
/
Copy pathcron.html
More file actions
164 lines (145 loc) · 9.44 KB
/
Copy pathcron.html
File metadata and controls
164 lines (145 loc) · 9.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
{% extends "includes/layout.html" %}
{% block content %}
<div id="main-content-inner">
<section>
<div id="config-header">
<div class="config-title-group">
<h1>AudioMuse-AI - Scheduled Tasks</h1>
<p class="subtitle">Configure scheduled Analysis and Clustering runs using cron notation.</p>
</div>
<div class="header-controls">
<!-- Header controls intentionally empty; the save button is placed under the form. -->
</div>
</div>
<div style="max-width:100%; margin-top:1rem;">
<label style="display:block;margin-bottom:.5rem;" class="label-with-tooltip">
Analysis
<span class="info-tooltip" tabindex="0">
<span class="info-icon"></span>
<span class="tooltip-text">Schedule automatic song analysis. Uses cron notation: 5 fields (minute hour day month weekday). Example: "0 2 * * 0-5" = 2:00 AM every day except Saturday. "0 2 * * *" = 2:00 AM daily.</span>
</span>
</label>
<input id="analysis-cron" type="text" style="width:100%;" placeholder="cron expression (e.g. 0 2 * * 0-5)">
<div style="margin-top:.5rem;"><input id="analysis-enabled" type="checkbox"> Enable</div>
<hr style="margin:1rem 0;">
<label style="display:block;margin-bottom:.5rem;" class="label-with-tooltip">
Clustering
<span class="info-tooltip" tabindex="0">
<span class="info-icon"></span>
<span class="tooltip-text">Schedule automatic playlist clustering. Uses cron notation: 5 fields (minute hour day month weekday). Example: "0 2 * * 6" = 2:00 AM every Saturday. Run less frequently than analysis since it processes all analyzed songs.</span>
</span>
</label>
<input id="clustering-cron" type="text" style="width:100%;" placeholder="cron expression (e.g. 0 2 * * 6)">
<div style="margin-top:.5rem;"><input id="clustering-enabled" type="checkbox"> Enable</div>
<hr style="margin:1rem 0;">
<label style="display:block;margin-bottom:.5rem;" class="label-with-tooltip">
Sonic Fingerprint
<span class="info-tooltip" tabindex="0">
<span class="info-icon"></span>
<span class="tooltip-text">Schedule automatic generation of the Sonic Fingerprint playlist. Uses cron notation: 5 fields (minute hour day month weekday). Example: "0 1 * * 6" = 1:00 AM every Saturday. Uses default parameters.</span>
</span>
</label>
<input id="sonic-fingerprint-cron" type="text" style="width:100%;" placeholder="cron expression (e.g. 0 1 * * 6)">
<div style="margin-top:.5rem;"><input id="sonic-fingerprint-enabled" type="checkbox"> Enable</div>
<hr style="margin:1rem 0;">
<label for="alchemy-radio-cron" style="display:block;margin-bottom:.5rem;" class="label-with-tooltip">
Radio Playlists
<span class="info-tooltip" tabindex="0">
<span class="info-icon"></span>
<span class="tooltip-text">Schedule automatic creation of the Radio playlists defined in the Alchemy page (Radio tab). Each radio's existing playlist is updated in-place (preserving its server-side ID) to avoid duplicates on sync clients. Uses cron notation: 5 fields (minute hour day month weekday). Example: "0 3 * * 6" = 3:00 AM every Saturday.</span>
</span>
</label>
<input id="alchemy-radio-cron" type="text" style="width:100%;" placeholder="cron expression (e.g. 0 3 * * 6)">
<div style="margin-top:.5rem;"><input id="alchemy-radio-enabled" type="checkbox"> Enable</div>
<p style="margin-top:.5rem;font-size:0.9rem;color:var(--text-muted);">Defaults are disabled. Analysis default: each night (2:00) except Saturday. Clustering default: Saturday at 2:00. Sonic Fingerprint default: Saturday at 1:00. Radio Playlists default: Saturday at 3:00.</p>
<div style="margin-top:1rem;">
<button id="save-btn" class="btn btn-primary" style="width:100%;">Save Schedules</button>
</div>
</div>
</section>
</div>
{% endblock %}
{% block bodyAdditions %}
<script>
function saveCron(payload){
return fetch("{{ url_for('cron_bp.save_cron_entry') }}", {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify(payload)
});
}
document.addEventListener('DOMContentLoaded', load);
async function load(){
try{
const res = await fetch("{{ url_for('cron_bp.get_cron_entries') }}");
if(!res.ok) return;
const rows = await res.json();
// cache rows to avoid refetching on save
window.cronRows = rows;
// find entries
const a = rows.find(r=>r.task_type==='analysis');
const c = rows.find(r=>r.task_type==='clustering');
const s = rows.find(r=>r.task_type==='sonic_fingerprint');
const radio = rows.find(r=>r.task_type==='alchemy_radio');
if(a){ document.getElementById('analysis-cron').value = a.cron_expr; document.getElementById('analysis-enabled').checked = a.enabled }
else { document.getElementById('analysis-cron').value = '0 2 * * 0-5'; document.getElementById('analysis-enabled').checked = false }
if(c){ document.getElementById('clustering-cron').value = c.cron_expr; document.getElementById('clustering-enabled').checked = c.enabled }
else { document.getElementById('clustering-cron').value = '0 2 * * 6'; document.getElementById('clustering-enabled').checked = false }
if(s){ document.getElementById('sonic-fingerprint-cron').value = s.cron_expr; document.getElementById('sonic-fingerprint-enabled').checked = s.enabled }
else { document.getElementById('sonic-fingerprint-cron').value = '0 1 * * 6'; document.getElementById('sonic-fingerprint-enabled').checked = false }
if(radio){ document.getElementById('alchemy-radio-cron').value = radio.cron_expr; document.getElementById('alchemy-radio-enabled').checked = radio.enabled }
else { document.getElementById('alchemy-radio-cron').value = '0 3 * * 6'; document.getElementById('alchemy-radio-enabled').checked = false }
}catch(e){ console.error(e) }
}
document.getElementById('save-btn').addEventListener('click', async ()=>{
const saveBtn = document.getElementById('save-btn');
if (saveBtn.disabled) return; // prevent double-click
saveBtn.disabled = true;
const aexpr = document.getElementById('analysis-cron').value;
const aen = document.getElementById('analysis-enabled').checked;
const cexpr = document.getElementById('clustering-cron').value;
const cen = document.getElementById('clustering-enabled').checked;
// Use cached rows if available to avoid an extra GET
const rows = window.cronRows || [];
const an = rows.find(r=>r.task_type==='analysis');
const cn = rows.find(r=>r.task_type==='clustering');
const sn = rows.find(r=>r.task_type==='sonic_fingerprint');
const rn = rows.find(r=>r.task_type==='alchemy_radio');
try{
if (an) {
saveCron({id:an.id, name:'Analysis', task_type:'analysis', cron_expr:aexpr, enabled:aen})
} else {
saveCron({name:'Analysis', task_type:'analysis', cron_expr:aexpr, enabled:aen})
}
if (cn) {
saveCron({id:cn.id, name:'Clustering', task_type:'clustering', cron_expr:cexpr, enabled:cen})
} else {
saveCron({name:'Clustering', task_type:'clustering', cron_expr:cexpr, enabled:cen})
}
const sexpr = document.getElementById('sonic-fingerprint-cron').value;
const sen = document.getElementById('sonic-fingerprint-enabled').checked;
if (sn) {
saveCron({id:sn.id, name:'Sonic Fingerprint', task_type:'sonic_fingerprint', cron_expr:sexpr, enabled:sen})
} else {
saveCron({name:'Sonic Fingerprint', task_type:'sonic_fingerprint', cron_expr:sexpr, enabled:sen})
}
const rexpr = document.getElementById('alchemy-radio-cron').value;
const ren = document.getElementById('alchemy-radio-enabled').checked;
if (rn) {
saveCron({id:rn.id, name:'Radio Playlists', task_type:'alchemy_radio', cron_expr:rexpr, enabled:ren})
} else {
saveCron({name:'Radio Playlists', task_type:'alchemy_radio', cron_expr:rexpr, enabled:ren})
}
// refresh cached rows after saving
await load();
alert('Saved')
}catch(e){
console.error('Failed to save cron entries', e);
alert('Failed to save');
} finally{
saveBtn.disabled = false;
}
})
</script>
<script src="{{ url_for('static', filename='menu.js') }}"></script>
{% endblock %}