Avatar

@bnorick

8 public vals
Joined January 11, 2023
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
import { check_reddit } from "https://esm.town/v/bnorick/check_reddit";
export async function reddit_alert_example({ lastRunAt }) {
console.log(`last run at ${lastRunAt.getTime() / 1000}`);
return await check_reddit({
check: {
username: "YOUR_VAL_TOWN",
last_run_at_utc: lastRunAt.getTime() / 1000,
filters: {
homelabsales: [
"wyse",
"optiplex",
"t6[23]0",
"thin client",
{ pattern: "usff", strategy: "wordmatch" },
],
hardwareswap: [
"b450",
"thin client",
{ pattern: "usff", strategy: "wordmatch" },
],
},
},
});
}
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
import { email } from "https://esm.town/v/std/email?v=9";
import { set } from "https://esm.town/v/std/set?v=11";
let { checkRedditState } = await import("https://esm.town/v/bnorick/checkRedditState");
import { reddit_matches } from "https://esm.town/v/bnorick/reddit_matches";
import { toggleSubreddits } from "https://esm.town/v/bnorick/toggleSubreddits";
export let check_reddit = async ({ check = null, toggle = null }) => {
if (check) {
check = Object.assign({
fetch_limit: 10,
force: false,
enable_toggle: Boolean(toggleSubreddits),
}, check);
// let before = @me.checkRedditState["x"].last;
let result = await reddit_matches({
username: check.username,
last_run_at_utc: check.last_run_at_utc,
filters: check.filters,
current_state: checkRedditState,
fetch_limit: check.fetch_limit,
enable_toggle: check.enable_toggle,
force: check.force,
});
// $me.redditAlertHistory.push({
// before: before,
// matches: result.matches,
// time: new Date().toLocaleString("en-US", {
// timeZone: "America/Los_Angeles",
// }),
// });
checkRedditState = result.state;
await set(
"checkRedditState",
checkRedditState,
);
if (result.email)
await email({
text: result.email.text,
subject: result.email.subject,
});
return result;
}
if (toggle) {
if (!checkRedditState) {
await set(
"checkRedditState",
checkRedditState,
);
return {};
}
if (typeof toggle === "string") {
toggle = [toggle];
}
let result = {};
for (let subreddit of toggle) {
let state = checkRedditState[subreddit];
if (state) {
state.disabled = !state.disabled;
}
result[subreddit] = state.disabled;
}
await set(
"checkRedditState",
checkRedditState,
);
return result;
}
};
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
import { load_new_subreddit_posts } from "https://esm.town/v/bnorick/load_new_subreddit_posts";
export let reddit_matches = async ({
username,
last_run_at_utc,
filters,
current_state,
fetch_limit,
enable_toggle,
force,
}) => {
let matches = {};
let new_state = current_state ? current_state : {};
current_state = current_state || {};
// TODO: handle >10 subreddits by raising and exception?
let fetch_budget = Math.floor(fetch_limit / Object.keys(filters).length);
let additional_fetches_required = {};
let fetch_total = 0;
for (const subreddit in filters) {
console.log(`processing subreddit ${subreddit}`);
let subreddit_filters = filters[subreddit];
if (!subreddit_filters) {
console.log(`no patterns for subreddit ${subreddit}, skipping`);
continue;
}
let state = current_state[subreddit] ? current_state[subreddit] : {};
if (state.disabled) {
if (!force) {
console.log(`subreddit ${subreddit} is disabled by state, skipping`);
continue;
} else {
console.log(
`subreddit ${subreddit} is disabled by state, processing because options.force == true`
);
}
}
let result = await load_new_subreddit_posts({
subreddit: subreddit,
filters: subreddit_filters,
after_utc: last_run_at_utc,
fetch_limit: fetch_budget,
});
fetch_total += result.fetches;
if (result.next_fetch_from) {
additional_fetches_required[subreddit] = result.next_fetch_from;
}
let extra_message = additional_fetches_required[subreddit]
? `, reached fetch limit (${fetch_budget}), loading more posts after other subreddits if possible`
: "";
console.log(`processed ${result.new_posts} posts${extra_message}`);
new_state[subreddit] = {
disabled: state.disabled,
last_run_at_utc: last_run_at_utc,
};
if (result.matches.length) {
matches[subreddit] = result.matches;
}
}
// TODO: handle additional_fetches_required
let text = [];
let total_matches = 0;
let first = true;
for (let subreddit in matches) {
if (!first) {
text.push("\n\n");
}
text.push(`${subreddit}`);
text.push(`found ${matches[subreddit].length} matches`);
if (enable_toggle) {
text.push(
`toggle: https://api.val.town/eval/@${username}.toggleSubreddits(%22${subreddit}%22)`
);
}
text.push("");
for (let match of matches[subreddit]) {
text.push(`${match.title}\n${match.url}\n`);
}
total_matches += matches[subreddit].length;
first = false;
}
return {
state: new_state,
matches: matches,
email: text.length
? {
text: text.join("\n"),
subject: `Reddit Notifier (${total_matches} matches)`,
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
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export let load_new_subreddit_posts = async ({
subreddit,
filters,
after_utc,
fetch_limit,
}) => {
let patterns = [];
for (const pattern_def of filters) {
let pattern_str, mode;
if (typeof pattern_def === "string") {
pattern_str = pattern_def;
mode = "gi";
} else {
pattern_str = pattern_def.pattern;
if (pattern_def.strategy == "wordmatch") {
pattern_str = `\\b${pattern_str}\\b`;
}
mode = pattern_def.mode || "gi";
}
patterns.push(RegExp(pattern_str, mode));
}
let next_fetch_from = null;
let matches = [];
let new_posts = 0;
let fetches = 1;
let data = await fetchJSON(
`https://www.reddit.com/r/${subreddit}/new/.json`
);
console.log(`got https://www.reddit.com/r/${subreddit}/new/.json`);
while (true) {
let done = false;
for (const post of data.data.children) {
let post_data = post.data;
let created_utc = post_data.created_utc;
if (created_utc <= after_utc) {
done = true;
break;
}
new_posts += 1;
let pattern_idx = 0;
for (const pattern of patterns) {
if (
post_data.title.match(pattern) ||
post_data.selftext.match(pattern)
) {
matches.push({
url: post_data.url,
title: post_data.title,
pattern_idx: pattern_idx,
});
console.log(
`found match created_utc=${created_utc} after_utc=${after_utc} url=${post_data.url}`
);
break;
}
pattern_idx += 1;
}
}
if (done) {
break;
}
let last_post_name = data.data.children.at(-1).data.name;
// mark this subreddit for additional fetches if it reached its budget
if (fetches == fetch_limit) {
next_fetch_from = last_post_name;
break;
}
fetches += 1;
data = await fetchJSON(
`https://www.reddit.com/r/${subreddit}/new/.json?after=${last_post_name}`
);
console.log(
`got https://www.reddit.com/r/${subreddit}/new/.json?after=${last_post_name}`
);
}
return {
new_posts: new_posts,
matches: matches,
fetches: fetches,
next_fetch_from: next_fetch_from,
};
};
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
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
import { redditNotifierState } from "https://esm.town/v/bnorick/redditNotifierState";
export async function redditAlertBackup({ lastRunAt }) {
let subreddit_matches = {};
for (const subreddit in redditNotifierState) {
console.log(`processing subreddit ${subreddit}`);
let state = redditNotifierState[subreddit];
let last = state.last;
let matches = [];
let data = await fetchJSON(
`https://www.reddit.com/r/${subreddit}/new/.json?before=${last}`
);
let new_posts = 0;
let count = data.data.dist;
while (count > 0) {
new_posts += count;
for (const post of data.data.children) {
let post_data = post.data;
for (const pattern_str of state.patterns) {
let pattern = RegExp(pattern_str, "gi");
if (
post_data.title.match(pattern) ||
post_data.selftext.match(pattern)
) {
matches.push({
url: post_data.url,
title: post_data.title,
pattern: pattern_str,
});
console.log(`found match ${post_data.url}`);
break;
}
}
}
last = data.data.children[0].data.name;
data = await fetchJSON(
`https://www.reddit.com/r/${subreddit}/new/.json?before=${last}`
);
count = data.data.dist;
}
console.log(`processed ${new_posts} posts`);
redditNotifierState[subreddit].last = last;
if (matches.length) {
subreddit_matches[subreddit] = matches;
}
}
let text = [];
let total_matches = 0;
let first = true;
for (let subreddit in subreddit_matches) {
if (!first) {
text.push("\n\n");
}
text.push(
`${subreddit}\nfound ${subreddit_matches[subreddit].length} matches\n`
);
for (let match of subreddit_matches[subreddit]) {
text.push(`${match.title}\n${match.url}\n`);
}
total_matches += subreddit_matches[subreddit].length;
first = false;
}
console.log(text.join("\n"));
if (text.length)
console.email(
text.join("\n"),
`Reddit Notifier (${total_matches} matches)`
);
}
1
2
3
4
5
6
7
8
9
10
11
12
import { checkReddit } from "https://esm.town/v/bnorick/checkReddit";
export let toggleSubreddits = async (subreddits) => {
let result = await checkReddit({ toggle: subreddits });
let messages = [];
for (let subreddit in result) {
messages.push(
`subreddit ${subreddit} is now ${result[subreddit] ? "dis" : "en"}abled`
);
}
return messages;
};
1
2
3
4
5
6
7
8
9
10
import { checkReddit } from "https://esm.town/v/bnorick/checkReddit";
export let exampleCheckReddit = checkReddit({
check: {
username: "bnorick",
filters: {
buildapcsales: ["case", "20[89]0", { pattern: "ssd", mode: "i" }],
},
},
});
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
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export let redditMatches = async ({ username, filters, current_state, options }) => {
let matches = {};
let new_state = current_state ? current_state : {};
current_state = current_state || {};
for (const subreddit in filters) {
console.log(`processing subreddit ${subreddit}`);
let subreddit_filters = filters[subreddit];
let state = current_state[subreddit] ? current_state[subreddit] : {};
if (state.disabled) {
if (!options.force) {
console.log(`subreddit ${subreddit} is disabled by state, skipping`);
continue;
} else {
console.log(
`subreddit ${subreddit} is disabled by state, processing because options.force == true`
);
}
}
let last = state.last;
let params = last ? `?before=${last}` : "";
let subreddit_matches = [];
let data = await fetchJSON(
`https://www.reddit.com/r/${subreddit}/new/.json${params}`
);
console.log(`got https://www.reddit.com/r/${subreddit}/new/.json${params}`);
let new_posts = 0;
let count = data.data.dist;
let patterns = [];
if (!subreddit_filters) {
console.log(`missing patterns for subreddit ${subreddit}`);
continue;
}
for (const pattern_def of subreddit_filters) {
let pattern_str, mode;
if (typeof pattern_def === "string") {
pattern_str = pattern_def;
mode = "gi";
} else {
pattern_str = pattern_def.pattern;
if (pattern_def.strategy == "wordmatch") {
pattern_str = `\\b${pattern_str}\\b`;
}
mode = pattern_def.mode || "gi";
}
patterns.push(RegExp(pattern_str, mode));
}
while (count > 0) {
new_posts += count;
for (const post of data.data.children) {
let post_data = post.data;
let pattern_idx = 0;
for (const pattern of patterns) {
if (
post_data.title.match(pattern) ||
post_data.selftext.match(pattern)
) {
subreddit_matches.push({
url: post_data.url,
title: post_data.title,
pattern_idx: pattern_idx,
});
console.log(`found match ${post_data.url}`);
break;
}
pattern_idx += 0;
}
}
last = data.data.children[0].data.name;
data = await fetchJSON(
`https://www.reddit.com/r/${subreddit}/new/.json?before=${last}`
);
console.log(
`got https://www.reddit.com/r/${subreddit}/new/.json?before=${last}`
);
count = data.data.dist;
}
console.log(`processed ${new_posts} posts`);
state.last = last; // mutates argument, is that bad?
new_state[subreddit] = state;
if (subreddit_matches.length) {
matches[subreddit] = subreddit_matches;
}
}
let text = [];
let total_matches = 0;
let first = true;
for (let subreddit in matches) {
if (!first) {
text.push("\n\n");
}
text.push(`${subreddit}`);
text.push(`found ${matches[subreddit].length} matches`);
Next