-
Notifications
You must be signed in to change notification settings - Fork 0
/
schedule.js
executable file
·133 lines (116 loc) · 3.46 KB
/
schedule.js
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
const path = require('path');
const fse = require('fs-extra');
const jobs = require('../conf/jobs');
const fm = require('./fm');
const Player = require('./player');
const cronParser = require('cron-parser');
const debug = require('debug')('RPIFM:schedule');
let currentPlayer;
let currentRunningJobIndex = -1;
let checkTimer;
async function runJob(index) {
debug(`Starting to run job ${index}`);
stopJob();
let job = jobs[index];
if (!job) return;
let runner = getJobRunner(job);
if (!runner) return;
currentPlayer = await runner(job);
debug(`Player ready for [${job.type}]${job.name}(${index})`);
currentRunningJobIndex = index;
try {
currentPlayer.play();
}
catch (err) {
debug('Player.play error', err);
}
fm.powerOn();
}
function stopJob() {
debug(`Stopping job ${currentRunningJobIndex}`);
if (currentPlayer) {
try {
currentPlayer.stop();
}
catch (err) {
debug('Player.stop error', err);
}
}
currentRunningJobIndex = -1;
fm.powerOff();
}
function getJobRunner(job) {
if (job.type === 'custom') {
return job.runner;
}
else if (job.type === 'playlist') {
return async function (job) {
let relPath = path.dirname(job.file);
let content = await fse.readFile(job.file, 'utf8');
let audios = content.split('\n')
.map(line => line.trim())
.filter(line => line && !line.startsWith('#'))
.map(name => name.startsWith('/') ? name : path.resolve(relPath, name));
return new Player(audios, job.playerOptions);
};
}
}
async function start() {
debug('Schedule Initing');
// await fm.init();
debug('Schedule started');
function loop() {
debug(`Current time: ${new Date()}`);
clearTimeout(checkTimer);
for (let i = 0; i < jobs.length; i++) {
let {name, trigger} = jobs[i];
if (isMatchTime(trigger.spec, trigger.duration)) {
debug(`Time matched for ${name}: "${trigger.spec}" ${trigger.duration}`);
if (currentRunningJobIndex !== i) {
runJob(i);
}
break;
}
else if (currentRunningJobIndex === i) {
stopJob();
}
}
// 匹配到 0 秒
checkTimer = setTimeout(loop, secondsToNextMinute() * 1000);
}
loop();
}
function secondsToNextMinute() {
let date = new Date();
return 60 - date.getSeconds();
}
function isMatchTime(spec, duration) {
let interval = cronParser.parseExpression(spec);
let prevDate = interval.prev();
let startTimestamp = prevDate.getTime() / 1000;
let endTimestamp= startTimestamp + duration;
let now = Date.now() / 1000;
return now >= startTimestamp && now < endTimestamp;
}
function stop() {
debug('Schedule stoped');
clearTimeout(checkTimer);
checkTimer = undefined;
stopJob();
}
function status() {
let resultJobs = jobs.map(function (job, index) {
return {
name: job.name,
type: job.type,
at: job.trigger.spec,
duration: job.trigger.duration,
isRunning: currentRunningJobIndex === index
};
});
return {
scheduled: !!checkTimer,
jobs: resultJobs
};
}
module.exports = {start, stop, status, runJob, stopJob};