-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheztv.rss.js
More file actions
129 lines (110 loc) · 3.56 KB
/
Copy patheztv.rss.js
File metadata and controls
129 lines (110 loc) · 3.56 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
const fs = require('fs');
const argparse = require('argparse');
const RSSParser = require('rss-parser');
const _ = require('lodash');
const parser = require('episode-parser');
const SimpleNodeLogger = require('simple-node-logger');
const log = SimpleNodeLogger.createSimpleLogger({
timestampFormat: 'YYYY-MM-DD HH:mm:ss.SSS'
});
log.setLevel('info');
const RSS_URL = 'https://myrss.org/eztv';
const DB_PATH = 'eztv.rss.json';
function isNewerEpisode(candidate, current) {
if (!current) {
return true;
}
// The RSS cache keeps one record per show, so a later season/episode replaces the older one.
const candidateSeason = Number(candidate.season || 0);
const currentSeason = Number(current.season || 0);
if (candidateSeason !== currentSeason) {
return candidateSeason > currentSeason;
}
const candidateEpisode = Number(candidate.episode || 0);
const currentEpisode = Number(current.episode || 0);
if (candidateEpisode !== currentEpisode) {
return candidateEpisode > currentEpisode;
}
return false;
}
async function run() {
const parserArg = new argparse.ArgumentParser({
description: 'Fetch EZTV RSS feed and maintain a local JSON database.'
});
parserArg.addArgument('--max-days', {
help: 'Number of days to keep entries',
type: 'int',
default: 7
});
const [args] = parserArg.parseKnownArgs(process.argv);
const maxDays = args.max_days;
const rssParser = new RSSParser();
let db = {};
try {
if (fs.existsSync(DB_PATH)) {
db = JSON.parse(fs.readFileSync(DB_PATH, 'utf8'));
}
} catch (err) {
log.error(`Failed to read database file: ${err.message}`);
process.exit(1);
}
let feed;
try {
log.info(`Fetching RSS feed from ${RSS_URL}`);
feed = await rssParser.parseURL(RSS_URL);
} catch (err) {
log.error(`Failed to fetch RSS feed: ${err.message}`);
process.exit(1);
}
const now = new Date();
const entries = feed.items;
log.info(`Found ${entries.length} entries in RSS feed.`);
for (const item of entries) {
const title = item.title;
const parsed = parser(title);
if (!parsed || !parsed.show) {
log.warn(`Could not parse title: ${title}`);
continue;
}
const { show, season, episode } = parsed;
const key = _.snakeCase(show);
const candidate = {
show,
season,
episode,
title,
last_seen: now.toISOString()
};
// Refresh recency on every sighting, but only replace the stored episode if this is newer.
if (isNewerEpisode(candidate, db[key])) {
log.debug(`${db[key] ? 'Updating' : 'Adding'} latest entry for: ${key}`);
db[key] = candidate;
} else if (db[key]) {
db[key].last_seen = now.toISOString();
}
}
// Eviction
const cutoff = new Date(now.getTime() - maxDays * 24 * 60 * 60 * 1000);
let evictedCount = 0;
for (const key in db) {
const lastSeen = new Date(db[key].last_seen);
if (lastSeen < cutoff) {
delete db[key];
evictedCount++;
}
}
if (evictedCount > 0) {
log.info(`Evicted ${evictedCount} old entries.`);
}
try {
fs.writeFileSync(DB_PATH, JSON.stringify(db, null, 2));
log.info(`Database updated successfully. Total entries: ${Object.keys(db).length}`);
} catch (err) {
log.error(`Failed to write database file: ${err.message}`);
process.exit(1);
}
}
run().catch(err => {
log.error(`Unhandled error: ${err.message}`);
process.exit(1);
});