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
|
import { notify } from "@/utils/system";
import { execAsync, GLib, GObject, property, readFileAsync, register, writeFileAsync } from "astal";
import { news as config } from "config";
export interface Article {
title: string;
link: string;
keywords: string;
creator: string;
description: string;
pubDate: string;
}
@register({ GTypeName: "News" })
export default class News extends GObject.Object {
static instance: News;
static get_default() {
if (!this.instance) this.instance = new News();
return this.instance;
}
readonly #cachePath = `${CACHE}/news.json`;
#loading: boolean = false;
#articles: Article[] = [];
@property(Boolean)
get loading() {
return this.#loading;
}
@property(Object)
get articles() {
return this.#articles;
}
async getNews() {
if (!config.apiKey.get()) {
notify({
summary: "A newsdata.io API key is required",
body: "You can get one by creating an account at https://newsdata.io",
icon: "dialog-error-symbolic",
urgency: "critical",
actions: {
"Get API key": () => execAsync("app2unit -O -- https://newsdata.io").catch(console.error),
},
});
return;
}
this.#loading = true;
this.notify("loading");
let countries = config.countries.get().join(",");
const categories = config.categories.get().join(",");
const languages = config.languages.get().join(",");
const domains = config.domains.get().join(",");
const timezone = config.timezone.get();
if (countries.includes("current")) {
const out = JSON.parse(await execAsync("curl ipinfo.io")).country.toLowerCase();
countries = countries.replace("current", out);
}
let args = "removeduplicate=1&prioritydomain=top";
if (countries) args += `&country=${countries}`;
if (categories) args += `&category=${categories}`;
if (languages) args += `&language=${languages}`;
if (domains) args += `&domain=${domains}`;
if (timezone) args += `&timezone=${timezone}`;
const url = `https://newsdata.io/api/1/latest?apikey=${config.apiKey.get()}&${args}`;
try {
const res = JSON.parse(await execAsync(["curl", url]));
this.#articles = res.results;
let page = res.nextPage;
for (let i = 0; i < 3; i++) {
const res = JSON.parse(await execAsync(["curl", `${url}&page=${page}`]));
this.#articles.push(...res.results);
page = res.nextPage;
}
writeFileAsync(this.#cachePath, JSON.stringify(this.#articles)).catch(console.error);
} catch (e) {
console.error(e);
if (GLib.file_test(this.#cachePath, GLib.FileTest.EXISTS))
this.#articles = JSON.parse(await readFileAsync(this.#cachePath));
}
this.notify("articles");
this.#loading = false;
this.notify("loading");
}
constructor() {
super();
this.getNews().catch(console.error);
config.apiKey.subscribe(() => this.getNews().catch(console.error));
config.countries.subscribe(() => this.getNews().catch(console.error));
config.categories.subscribe(() => this.getNews().catch(console.error));
config.languages.subscribe(() => this.getNews().catch(console.error));
config.domains.subscribe(() => this.getNews().catch(console.error));
config.timezone.subscribe(() => this.getNews().catch(console.error));
}
}
|