summaryrefslogtreecommitdiff
path: root/src/services/news.ts
blob: a08f19c341c1185493bcb16fa0df0dbb3ac07d46 (plain)
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));
    }
}