diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-04-09 00:04:15 +1000 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-04-09 00:04:15 +1000 |
| commit | ed25a8790c43555d58c3debfcc2ec951fd4516fb (patch) | |
| tree | cdf4ee5213d61b4324558e4f9018ef1b9933daaa /src/services/news.ts | |
| parent | players: fix duplicate players (diff) | |
| download | caelestia-shell-ed25a8790c43555d58c3debfcc2ec951fd4516fb.tar.gz caelestia-shell-ed25a8790c43555d58c3debfcc2ec951fd4516fb.tar.bz2 caelestia-shell-ed25a8790c43555d58c3debfcc2ec951fd4516fb.zip | |
feat: news service
Diffstat (limited to 'src/services/news.ts')
| -rw-r--r-- | src/services/news.ts | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/services/news.ts b/src/services/news.ts new file mode 100644 index 0000000..a08f19c --- /dev/null +++ b/src/services/news.ts @@ -0,0 +1,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)); + } +} |