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
|
import { monitorDirectory } from "@/utils/system";
import Thumbnailer from "@/utils/thumbnailer";
import { execAsync, GObject, property, register } from "astal";
import { wallpapers as config } from "config";
export interface IWallpaper {
path: string;
thumbnail?: string;
}
export interface ICategory {
path: string;
wallpapers: IWallpaper[];
}
@register({ GTypeName: "Wallpapers" })
export default class Wallpapers extends GObject.Object {
static instance: Wallpapers;
static get_default() {
if (!this.instance) this.instance = new Wallpapers();
return this.instance;
}
#list: IWallpaper[] = [];
#categories: ICategory[] = [];
@property(Object)
get list() {
return this.#list;
}
@property(Object)
get categories() {
return this.#categories;
}
#listDir(path: { path: string; recursive: boolean }, type: "f" | "d") {
const absPath = path.path.replace("~", HOME);
const maxDepth = path.recursive ? "" : "-maxdepth 1";
return execAsync(`find ${absPath} ${maxDepth} -path '*/.*' -prune -o -type ${type} -print`);
}
async update() {
const results = await Promise.allSettled(
config.paths.get().map(async p => ({ path: p, files: await this.#listDir(p, "f") }))
);
const successes = results.filter(r => r.status === "fulfilled").map(r => r.value);
if (!successes.length) {
this.#list = [];
this.notify("list");
this.#categories = [];
this.notify("categories");
return;
}
const files = successes.map(r => r.files.replaceAll("\n", " ")).join(" ");
const list = (await execAsync(["fish", "-c", `identify -ping -format '%i\n' ${files} ; true`])).split("\n");
this.#list = await Promise.all(list.map(async p => ({ path: p, thumbnail: await Thumbnailer.thumbnail(p) })));
this.notify("list");
const categories = await Promise.all(successes.map(r => this.#listDir(r.path, "d")));
this.#categories = categories
.flatMap(c => c.split("\n"))
.map(c => ({ path: c, wallpapers: this.#list.filter(w => w.path.startsWith(c)) }))
.filter(c => c.wallpapers.length > 0);
this.notify("categories");
}
constructor() {
super();
this.update().catch(console.error);
let monitors = config.paths
.get()
.map(p => monitorDirectory(p.path, () => this.update().catch(console.error), p.recursive));
config.paths.subscribe(v => {
this.update().catch(console.error);
for (const m of monitors) m.cancel();
monitors = v.map(p => monitorDirectory(p.path, () => this.update().catch(console.error), p.recursive));
});
}
}
|