feat: news service
This commit is contained in:
parent
b43a576615
commit
ed25a8790c
4 changed files with 124 additions and 0 deletions
|
|
@ -164,4 +164,12 @@ export default {
|
|||
exact: true,
|
||||
},
|
||||
},
|
||||
news: {
|
||||
apiKey: "", // An API key from https://newsdata.io for accessing news
|
||||
countries: ["current"], // A list of country codes or "current" for the current location
|
||||
categories: [] as string[], // A list of news categories to filter by
|
||||
languages: ["en"], // A list of languages codes to filter by
|
||||
domains: [] as string[], // A list of news domains to pull from
|
||||
timezone: "", // A timezone to filter by, e.g. "America/New_York"
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,5 +21,6 @@ export const {
|
|||
wallpapers,
|
||||
calendar,
|
||||
thumbnailer,
|
||||
news,
|
||||
} = config;
|
||||
export default config;
|
||||
|
|
|
|||
|
|
@ -94,4 +94,10 @@ export default {
|
|||
"thumbnailer.defaults.width": NUM,
|
||||
"thumbnailer.defaults.height": NUM,
|
||||
"thumbnailer.defaults.exact": BOOL,
|
||||
"news.apiKey": STR,
|
||||
"news.countries": ARR(STR),
|
||||
"news.categories": ARR(STR),
|
||||
"news.languages": ARR(STR),
|
||||
"news.domains": ARR(STR),
|
||||
"news.timezone": STR,
|
||||
} as { [k: string]: string | string[] | number[] };
|
||||
|
|
|
|||
109
src/services/news.ts
Normal file
109
src/services/news.ts
Normal file
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue