@groovenet/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/build/bin/groovenet.d.ts +3 -0
  2. package/build/bin/groovenet.d.ts.map +1 -0
  3. package/build/bin/groovenet.js +28 -0
  4. package/build/bin/groovenet.js.map +1 -0
  5. package/build/commands/albums.d.ts +3 -0
  6. package/build/commands/albums.d.ts.map +1 -0
  7. package/build/commands/albums.js +181 -0
  8. package/build/commands/albums.js.map +1 -0
  9. package/build/commands/config.d.ts +3 -0
  10. package/build/commands/config.d.ts.map +1 -0
  11. package/build/commands/config.js +63 -0
  12. package/build/commands/config.js.map +1 -0
  13. package/build/commands/friends.d.ts +3 -0
  14. package/build/commands/friends.d.ts.map +1 -0
  15. package/build/commands/friends.js +39 -0
  16. package/build/commands/friends.js.map +1 -0
  17. package/build/commands/play.d.ts +3 -0
  18. package/build/commands/play.d.ts.map +1 -0
  19. package/build/commands/play.js +81 -0
  20. package/build/commands/play.js.map +1 -0
  21. package/build/commands/playlists.d.ts +3 -0
  22. package/build/commands/playlists.d.ts.map +1 -0
  23. package/build/commands/playlists.js +92 -0
  24. package/build/commands/playlists.js.map +1 -0
  25. package/build/commands/stats.d.ts +3 -0
  26. package/build/commands/stats.d.ts.map +1 -0
  27. package/build/commands/stats.js +33 -0
  28. package/build/commands/stats.js.map +1 -0
  29. package/build/commands/tracks.d.ts +3 -0
  30. package/build/commands/tracks.d.ts.map +1 -0
  31. package/build/commands/tracks.js +278 -0
  32. package/build/commands/tracks.js.map +1 -0
  33. package/build/output.d.ts +9 -0
  34. package/build/output.d.ts.map +1 -0
  35. package/build/output.js +126 -0
  36. package/build/output.js.map +1 -0
  37. package/package.json +29 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=groovenet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groovenet.d.ts","sourceRoot":"","sources":["../../src/bin/groovenet.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { createRequire } from "module";
4
+ import { addConfigCommands } from "../commands/config.js";
5
+ import { addTracksCommands } from "../commands/tracks.js";
6
+ import { addAlbumsCommands } from "../commands/albums.js";
7
+ import { addPlaylistsCommands } from "../commands/playlists.js";
8
+ import { addPlayCommands } from "../commands/play.js";
9
+ import { addFriendsCommands } from "../commands/friends.js";
10
+ const require = createRequire(import.meta.url);
11
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
12
+ const { version } = require("../../package.json");
13
+ const program = new Command();
14
+ program
15
+ .name("groovenet")
16
+ .description("CLI for your Groovenet DJ collection")
17
+ .version(version);
18
+ addConfigCommands(program);
19
+ addTracksCommands(program);
20
+ addAlbumsCommands(program);
21
+ addPlaylistsCommands(program);
22
+ addPlayCommands(program);
23
+ addFriendsCommands(program);
24
+ program.parseAsync(process.argv).catch((err) => {
25
+ process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
26
+ process.exit(1);
27
+ });
28
+ //# sourceMappingURL=groovenet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groovenet.js","sourceRoot":"","sources":["../../src/bin/groovenet.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,sEAAsE;AACtE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAwB,CAAC;AAEzE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,sCAAsC,CAAC;KACnD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,eAAe,CAAC,OAAO,CAAC,CAAC;AACzB,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAE5B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAC/D,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addAlbumsCommands(program: Command): void;
3
+ //# sourceMappingURL=albums.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"albums.d.ts","sourceRoot":"","sources":["../../src/commands/albums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwJxD"}
@@ -0,0 +1,181 @@
1
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
2
+ import Table from "cli-table3";
3
+ import chalk from "chalk";
4
+ import { printJson, printSuccess, printError, printTracks } from "../output.js";
5
+ function makeClient() {
6
+ const cfg = loadConfig();
7
+ return new GroovenetClient({ baseUrl: cfg.api_base, apiKey: cfg.api_key, insecureTls: cfg.insecure_tls });
8
+ }
9
+ function defaultFriendId() {
10
+ return loadConfig().default_friend_id;
11
+ }
12
+ function printAlbums(albums, json) {
13
+ if (json) {
14
+ printJson(albums);
15
+ return;
16
+ }
17
+ if (albums.length === 0) {
18
+ console.log(chalk.yellow("No albums found."));
19
+ return;
20
+ }
21
+ const table = new Table({
22
+ head: [
23
+ chalk.cyan("Release ID"),
24
+ chalk.cyan("Title"),
25
+ chalk.cyan("Artist"),
26
+ chalk.cyan("Year"),
27
+ chalk.cyan("Tracks"),
28
+ chalk.cyan("Rating"),
29
+ ],
30
+ colWidths: [12, 34, 24, 6, 7, 7],
31
+ wordWrap: true,
32
+ });
33
+ for (const a of albums) {
34
+ table.push([
35
+ a.release_id,
36
+ a.title,
37
+ a.artist,
38
+ a.year ?? "-",
39
+ a.track_count,
40
+ a.album_rating != null ? `★${a.album_rating}` : "-",
41
+ ]);
42
+ }
43
+ console.log(table.toString());
44
+ }
45
+ export function addAlbumsCommands(program) {
46
+ const albums = program.command("albums").description("Browse and manage albums");
47
+ albums
48
+ .command("list")
49
+ .description("Search/list albums")
50
+ .argument("[query]", "Search query", "")
51
+ .option("--sort <s>", "Sort (date_added:desc, year:desc, title:asc, album_rating:desc)", "date_added:desc")
52
+ .option("--limit <n>", "Number of results", parseInt, 20)
53
+ .option("--offset <n>", "Offset", parseInt, 0)
54
+ .option("--friend-id <n>", "Friend ID", parseInt)
55
+ .option("--json", "Output as JSON")
56
+ .action(async (query, opts) => {
57
+ try {
58
+ const client = makeClient();
59
+ const result = await client.searchAlbums({
60
+ q: query,
61
+ sort: opts.sort,
62
+ limit: opts.limit,
63
+ offset: opts.offset,
64
+ friend_id: opts.friendId,
65
+ });
66
+ if (opts.json) {
67
+ printJson(result);
68
+ }
69
+ else {
70
+ console.log(`Found ${result.hits.length} album(s)` +
71
+ (result.estimatedTotalHits > result.hits.length
72
+ ? ` (${result.estimatedTotalHits} total)`
73
+ : ""));
74
+ printAlbums(result.hits, false);
75
+ }
76
+ }
77
+ catch (err) {
78
+ printError(err instanceof Error ? err.message : String(err));
79
+ process.exit(1);
80
+ }
81
+ });
82
+ albums
83
+ .command("show <release-id>")
84
+ .description("Show album details and track list")
85
+ .option("--friend-id <n>", "Friend ID", parseInt)
86
+ .option("--json", "Output as JSON")
87
+ .action(async (releaseId, opts) => {
88
+ try {
89
+ const client = makeClient();
90
+ const friendId = opts.friendId ?? defaultFriendId();
91
+ const detail = await client.getAlbum(releaseId, friendId);
92
+ if (opts.json) {
93
+ printJson(detail);
94
+ return;
95
+ }
96
+ const a = detail.album;
97
+ console.log(chalk.bold(a.title) + chalk.gray(` — ${a.artist}`));
98
+ if (a.year)
99
+ console.log(chalk.gray(`Year: ${a.year}`));
100
+ if (a.genres?.length)
101
+ console.log(chalk.gray(`Genres: ${a.genres.join(", ")}`));
102
+ if (a.styles?.length)
103
+ console.log(chalk.gray(`Styles: ${a.styles.join(", ")}`));
104
+ if (a.album_rating != null)
105
+ console.log(`Rating: ★${a.album_rating}/5`);
106
+ if (a.album_notes)
107
+ console.log(`Notes: ${a.album_notes}`);
108
+ if (a.condition)
109
+ console.log(`Condition: ${a.condition}`);
110
+ if (a.purchase_price != null)
111
+ console.log(`Purchase price: $${a.purchase_price}`);
112
+ if (a.library_identifier)
113
+ console.log(`Library ID: ${a.library_identifier}`);
114
+ console.log();
115
+ console.log(`Tracks (${detail.tracks.length}):`);
116
+ printTracks(detail.tracks, false);
117
+ }
118
+ catch (err) {
119
+ printError(err instanceof Error ? err.message : String(err));
120
+ process.exit(1);
121
+ }
122
+ });
123
+ albums
124
+ .command("update <release-id>")
125
+ .description("Update album metadata")
126
+ .option("--friend-id <n>", "Friend ID", parseInt)
127
+ .option("--rating <n>", "Album rating (0-5)", parseFloat)
128
+ .option("--notes <text>", "Album notes")
129
+ .option("--price <n>", "Purchase price", parseFloat)
130
+ .option("--condition <s>", "Condition (e.g. VG+, NM)")
131
+ .option("--library-id <s>", "Library identifier (e.g. LP001)")
132
+ .action(async (releaseId, opts) => {
133
+ try {
134
+ const client = makeClient();
135
+ const friendId = opts.friendId ?? defaultFriendId();
136
+ const updates = {};
137
+ if (opts.rating != null)
138
+ updates.album_rating = opts.rating;
139
+ if (opts.notes != null)
140
+ updates.album_notes = opts.notes;
141
+ if (opts.price != null)
142
+ updates.purchase_price = opts.price;
143
+ if (opts.condition != null)
144
+ updates.condition = opts.condition;
145
+ if (opts.libraryId != null)
146
+ updates.library_identifier = opts.libraryId;
147
+ if (Object.keys(updates).length === 0) {
148
+ printError("No fields to update. Use --rating, --notes, --price, --condition, or --library-id.");
149
+ process.exit(2);
150
+ }
151
+ await client.updateAlbum(releaseId, friendId, updates);
152
+ printSuccess("✓ Album updated.");
153
+ }
154
+ catch (err) {
155
+ printError(err instanceof Error ? err.message : String(err));
156
+ process.exit(1);
157
+ }
158
+ });
159
+ albums
160
+ .command("download <release-id>")
161
+ .description("Queue all missing tracks in an album for download")
162
+ .option("--friend-id <n>", "Friend ID", parseInt)
163
+ .action(async (releaseId, opts) => {
164
+ try {
165
+ const client = makeClient();
166
+ const friendId = opts.friendId ?? defaultFriendId();
167
+ const result = await client.downloadAlbum(releaseId, friendId);
168
+ if (result.tracksQueued === 0) {
169
+ console.log("No tracks need downloading (all already have audio files).");
170
+ }
171
+ else {
172
+ printSuccess(`✓ Queued ${result.tracksQueued} track(s) for download.`);
173
+ }
174
+ }
175
+ catch (err) {
176
+ printError(err instanceof Error ? err.message : String(err));
177
+ process.exit(1);
178
+ }
179
+ });
180
+ }
181
+ //# sourceMappingURL=albums.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"albums.js","sourceRoot":"","sources":["../../src/commands/albums.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addConfigCommands(program: Command): void;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmDxD"}
@@ -0,0 +1,63 @@
1
+ import { loadConfig, saveConfig } from "@groovenet/client";
2
+ import { printJson, printSuccess, printError } from "../output.js";
3
+ const VALID_KEYS = [
4
+ "api_base",
5
+ "api_key",
6
+ "default_friend_id",
7
+ "username",
8
+ "insecure_tls",
9
+ ];
10
+ export function addConfigCommands(program) {
11
+ const config = program.command("config").description("Manage CLI configuration");
12
+ config
13
+ .command("set <key> <value>")
14
+ .description(`Set a config value. Keys: ${VALID_KEYS.join(", ")}`)
15
+ .action((key, value) => {
16
+ if (!VALID_KEYS.includes(key)) {
17
+ printError(`Unknown config key "${key}". Valid keys: ${VALID_KEYS.join(", ")}`);
18
+ process.exit(2);
19
+ }
20
+ const update = {};
21
+ if (key === "default_friend_id") {
22
+ const num = parseInt(value, 10);
23
+ if (isNaN(num)) {
24
+ printError(`default_friend_id must be a number`);
25
+ process.exit(2);
26
+ }
27
+ update[key] = num;
28
+ }
29
+ else if (key === "insecure_tls") {
30
+ const truthy = ["true", "1", "yes", "on"];
31
+ const falsy = ["false", "0", "no", "off"];
32
+ const v = value.toLowerCase();
33
+ if (!truthy.includes(v) && !falsy.includes(v)) {
34
+ printError(`insecure_tls must be true or false`);
35
+ process.exit(2);
36
+ }
37
+ update[key] = truthy.includes(v);
38
+ }
39
+ else {
40
+ update[key] = value;
41
+ }
42
+ saveConfig(update);
43
+ printSuccess(`✓ Set ${key} = ${value}`);
44
+ });
45
+ config
46
+ .command("show")
47
+ .description("Show current configuration")
48
+ .option("--json", "Output as JSON")
49
+ .action((opts) => {
50
+ const cfg = loadConfig();
51
+ if (opts.json) {
52
+ printJson(cfg);
53
+ }
54
+ else {
55
+ console.log("Current configuration:");
56
+ for (const [k, v] of Object.entries(cfg)) {
57
+ const display = k === "api_key" && v ? "***" : v;
58
+ console.log(` ${k}: ${display}`);
59
+ }
60
+ }
61
+ });
62
+ }
63
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addFriendsCommands(program: Command): void;
3
+ //# sourceMappingURL=friends.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"friends.d.ts","sourceRoot":"","sources":["../../src/commands/friends.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+BzD"}
@@ -0,0 +1,39 @@
1
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
2
+ import { printFriends, printSuccess, printError } from "../output.js";
3
+ function makeClient() {
4
+ const cfg = loadConfig();
5
+ return new GroovenetClient({ baseUrl: cfg.api_base, apiKey: cfg.api_key, insecureTls: cfg.insecure_tls });
6
+ }
7
+ export function addFriendsCommands(program) {
8
+ const friends = program.command("friends").description("Manage friends");
9
+ friends
10
+ .command("list")
11
+ .description("List all friends")
12
+ .option("--json", "Output as JSON")
13
+ .action(async (opts) => {
14
+ try {
15
+ const client = makeClient();
16
+ const result = await client.getFriends();
17
+ printFriends(result, opts.json ?? false);
18
+ }
19
+ catch (err) {
20
+ printError(err instanceof Error ? err.message : String(err));
21
+ process.exit(1);
22
+ }
23
+ });
24
+ friends
25
+ .command("add <username>")
26
+ .description("Add a friend by username")
27
+ .action(async (username) => {
28
+ try {
29
+ const client = makeClient();
30
+ await client.addFriend(username);
31
+ printSuccess(`✓ Added ${username} as a friend.`);
32
+ }
33
+ catch (err) {
34
+ printError(err instanceof Error ? err.message : String(err));
35
+ process.exit(1);
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=friends.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"friends.js","sourceRoot":"","sources":["../../src/commands/friends.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEtE,SAAS,UAAU;IACjB,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,OAAO,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;AAC5G,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAEzE,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kBAAkB,CAAC;SAC/B,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,UAAU,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,0BAA0B,CAAC;SACvC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACjC,YAAY,CAAC,WAAW,QAAQ,eAAe,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,UAAU,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addPlayCommands(program: Command): void;
3
+ //# sourceMappingURL=play.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuEtD"}
@@ -0,0 +1,81 @@
1
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
2
+ import { printJson, printSuccess, printError } from "../output.js";
3
+ function makeClient() {
4
+ const cfg = loadConfig();
5
+ return new GroovenetClient({ baseUrl: cfg.api_base, apiKey: cfg.api_key, insecureTls: cfg.insecure_tls });
6
+ }
7
+ export function addPlayCommands(program) {
8
+ program
9
+ .command("play <track-id>")
10
+ .description("Play a track via MPD on the server (resolves local_audio_url, sends to MPD)")
11
+ .option("--friend-id <n>", "Friend ID (defaults to config default_friend_id)", parseInt)
12
+ .action(async (trackId, opts) => {
13
+ try {
14
+ const cfg = loadConfig();
15
+ const client = makeClient();
16
+ const track = await client.getTrack(trackId, opts.friendId ?? cfg.default_friend_id);
17
+ if (!track.local_audio_url) {
18
+ printError(`Track "${track.title}" has no local audio file. Download it first.`);
19
+ process.exit(1);
20
+ }
21
+ await client.play(track.local_audio_url);
22
+ printSuccess(`▶ Playing: ${track.title} — ${track.artist}`);
23
+ }
24
+ catch (err) {
25
+ printError(err instanceof Error ? err.message : String(err));
26
+ process.exit(1);
27
+ }
28
+ });
29
+ program
30
+ .command("pause")
31
+ .description("Pause playback")
32
+ .action(async () => {
33
+ try {
34
+ const client = makeClient();
35
+ await client.pause();
36
+ printSuccess("⏸ Paused.");
37
+ }
38
+ catch (err) {
39
+ printError(err instanceof Error ? err.message : String(err));
40
+ process.exit(1);
41
+ }
42
+ });
43
+ program
44
+ .command("stop")
45
+ .description("Stop playback")
46
+ .action(async () => {
47
+ try {
48
+ const client = makeClient();
49
+ await client.stop();
50
+ printSuccess("⏹ Stopped.");
51
+ }
52
+ catch (err) {
53
+ printError(err instanceof Error ? err.message : String(err));
54
+ process.exit(1);
55
+ }
56
+ });
57
+ program
58
+ .command("now-playing")
59
+ .description("Show current playback status")
60
+ .option("--json", "Output as JSON")
61
+ .action(async (opts) => {
62
+ try {
63
+ const client = makeClient();
64
+ const status = await client.getPlaybackStatus();
65
+ if (opts.json) {
66
+ printJson(status);
67
+ }
68
+ else {
69
+ console.log(`Playback enabled: ${status.enabled}`);
70
+ if (status.status) {
71
+ console.log("Status:", JSON.stringify(status.status, null, 2));
72
+ }
73
+ }
74
+ }
75
+ catch (err) {
76
+ printError(err instanceof Error ? err.message : String(err));
77
+ process.exit(1);
78
+ }
79
+ });
80
+ }
81
+ //# sourceMappingURL=play.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"play.js","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addPlaylistsCommands(program: Command): void;
3
+ //# sourceMappingURL=playlists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playlists.d.ts","sourceRoot":"","sources":["../../src/commands/playlists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkF3D"}
@@ -0,0 +1,92 @@
1
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
2
+ import { printPlaylists, printTracks, printJson, printSuccess, printError } from "../output.js";
3
+ function makeClient() {
4
+ const cfg = loadConfig();
5
+ return new GroovenetClient({ baseUrl: cfg.api_base, apiKey: cfg.api_key, insecureTls: cfg.insecure_tls });
6
+ }
7
+ export function addPlaylistsCommands(program) {
8
+ const playlists = program.command("playlists").description("Manage playlists");
9
+ playlists
10
+ .command("list")
11
+ .description("List all playlists")
12
+ .option("--json", "Output as JSON")
13
+ .action(async (opts) => {
14
+ try {
15
+ const client = makeClient();
16
+ const result = await client.listPlaylists();
17
+ printPlaylists(result, opts.json ?? false);
18
+ }
19
+ catch (err) {
20
+ printError(err instanceof Error ? err.message : String(err));
21
+ process.exit(1);
22
+ }
23
+ });
24
+ playlists
25
+ .command("show <id>")
26
+ .description("Show tracks in a playlist")
27
+ .option("--json", "Output as JSON")
28
+ .action(async (id, opts) => {
29
+ try {
30
+ const client = makeClient();
31
+ const { track_refs } = await client.getPlaylistTracks(id);
32
+ if (track_refs.length === 0) {
33
+ console.log("Playlist is empty.");
34
+ return;
35
+ }
36
+ const tracks = await client.batchGetTracks(track_refs);
37
+ if (opts.json) {
38
+ printJson(tracks);
39
+ }
40
+ else {
41
+ console.log(`Playlist tracks (${tracks.length}):`);
42
+ printTracks(tracks, false);
43
+ }
44
+ }
45
+ catch (err) {
46
+ printError(err instanceof Error ? err.message : String(err));
47
+ process.exit(1);
48
+ }
49
+ });
50
+ playlists
51
+ .command("create <name>")
52
+ .description("Create a new playlist")
53
+ .action(async (name) => {
54
+ try {
55
+ const client = makeClient();
56
+ await client.createPlaylist(name);
57
+ printSuccess(`✓ Playlist "${name}" created.`);
58
+ }
59
+ catch (err) {
60
+ printError(err instanceof Error ? err.message : String(err));
61
+ process.exit(1);
62
+ }
63
+ });
64
+ playlists
65
+ .command("generate <id>")
66
+ .description("Generate an optimized playlist from an existing playlist using the genetic algorithm")
67
+ .option("--json", "Output as JSON")
68
+ .action(async (id, opts) => {
69
+ try {
70
+ const client = makeClient();
71
+ const { track_refs } = await client.getPlaylistTracks(id);
72
+ if (track_refs.length === 0) {
73
+ printError("Playlist is empty — nothing to generate from.");
74
+ process.exit(1);
75
+ }
76
+ const seedTracks = await client.batchGetTracks(track_refs);
77
+ const optimized = await client.generatePlaylist(seedTracks);
78
+ if (opts.json) {
79
+ printJson(optimized);
80
+ }
81
+ else {
82
+ console.log(`Optimized playlist (${optimized.length} tracks):`);
83
+ printTracks(optimized, false);
84
+ }
85
+ }
86
+ catch (err) {
87
+ printError(err instanceof Error ? err.message : String(err));
88
+ process.exit(1);
89
+ }
90
+ });
91
+ }
92
+ //# sourceMappingURL=playlists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playlists.js","sourceRoot":"","sources":["../../src/commands/playlists.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addStatsCommands(program: Command): void;
3
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuBvD"}
@@ -0,0 +1,33 @@
1
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
2
+ import { printJson, printError } from "../output.js";
3
+ function makeClient() {
4
+ const cfg = loadConfig();
5
+ return new GroovenetClient({ baseUrl: cfg.api_base, apiKey: cfg.api_key });
6
+ }
7
+ export function addStatsCommands(program) {
8
+ program
9
+ .command("stats")
10
+ .description("Show collection statistics")
11
+ .option("--username <u>", "Username")
12
+ .option("--json", "Output as JSON")
13
+ .action(async (opts) => {
14
+ try {
15
+ const client = makeClient();
16
+ const stats = await client.getStats(opts.username);
17
+ if (opts.json) {
18
+ printJson(stats);
19
+ }
20
+ else {
21
+ console.log("Collection Statistics:");
22
+ for (const [k, v] of Object.entries(stats)) {
23
+ console.log(` ${k}: ${JSON.stringify(v)}`);
24
+ }
25
+ }
26
+ }
27
+ catch (err) {
28
+ printError(err instanceof Error ? err.message : String(err));
29
+ process.exit(1);
30
+ }
31
+ });
32
+ }
33
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAErD,SAAS,UAAU;IACjB,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,OAAO,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,gBAAgB,EAAE,UAAU,CAAC;SACpC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,KAAK,EAAE,IAA2C,EAAE,EAAE;QAC5D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;gBACtC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,UAAU,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function addTracksCommands(program: Command): void;
3
+ //# sourceMappingURL=tracks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracks.d.ts","sourceRoot":"","sources":["../../src/commands/tracks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuTxD"}
@@ -0,0 +1,278 @@
1
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
2
+ import { printTracks, printTrack, printJson, printSuccess, printError, } from "../output.js";
3
+ import chalk from "chalk";
4
+ function makeClient() {
5
+ const cfg = loadConfig();
6
+ return new GroovenetClient({ baseUrl: cfg.api_base, apiKey: cfg.api_key, insecureTls: cfg.insecure_tls });
7
+ }
8
+ export function addTracksCommands(program) {
9
+ const tracks = program.command("tracks").description("Search and manage tracks");
10
+ tracks
11
+ .command("search <query>")
12
+ .description("Search your collection")
13
+ .option("--bpm-min <n>", "Minimum BPM", parseFloat)
14
+ .option("--bpm-max <n>", "Maximum BPM", parseFloat)
15
+ .option("--key <k>", "Musical key (e.g. 'A minor')")
16
+ .option("--rating <n>", "Filter by star rating (0-5)", parseFloat)
17
+ .option("--limit <n>", "Number of results", parseInt, 20)
18
+ .option("--json", "Output as JSON")
19
+ .action(async (query, opts) => {
20
+ try {
21
+ const client = makeClient();
22
+ const filters = {};
23
+ if (opts.bpmMin != null)
24
+ filters.bpm_min = opts.bpmMin;
25
+ if (opts.bpmMax != null)
26
+ filters.bpm_max = opts.bpmMax;
27
+ if (opts.key)
28
+ filters.key = opts.key;
29
+ if (opts.rating != null)
30
+ filters.star_rating = opts.rating;
31
+ const result = await client.searchTracks({
32
+ query,
33
+ limit: opts.limit,
34
+ filters: Object.keys(filters).length > 0 ? filters : undefined,
35
+ });
36
+ if (opts.json) {
37
+ printJson(result);
38
+ }
39
+ else {
40
+ console.log(`Found ${result.tracks.length} track(s)` +
41
+ (result.estimatedTotalHits > result.tracks.length
42
+ ? ` (${result.estimatedTotalHits} total)`
43
+ : ""));
44
+ printTracks(result.tracks, false);
45
+ }
46
+ }
47
+ catch (err) {
48
+ printError(err instanceof Error ? err.message : String(err));
49
+ process.exit(1);
50
+ }
51
+ });
52
+ tracks
53
+ .command("show <id>")
54
+ .description("Show details for a track")
55
+ .option("--friend-id <n>", "Friend ID (defaults to config default_friend_id)", parseInt)
56
+ .option("--json", "Output as JSON")
57
+ .action(async (id, opts) => {
58
+ try {
59
+ const cfg = loadConfig();
60
+ const client = makeClient();
61
+ const track = await client.getTrack(id, opts.friendId ?? cfg.default_friend_id);
62
+ printTrack(track, opts.json ?? false);
63
+ }
64
+ catch (err) {
65
+ printError(err instanceof Error ? err.message : String(err));
66
+ process.exit(1);
67
+ }
68
+ });
69
+ tracks
70
+ .command("update <id>")
71
+ .description("Update track metadata")
72
+ .option("--rating <n>", "Star rating (0-5)", parseFloat)
73
+ .option("--notes <text>", "Notes")
74
+ .option("--tags <tags>", "Comma-separated tags")
75
+ .option("--apple-url <url>", "Apple Music URL")
76
+ .option("--spotify-url <url>", "Spotify URL")
77
+ .option("--youtube-url <url>", "YouTube URL")
78
+ .option("--soundcloud-url <url>", "SoundCloud URL")
79
+ .action(async (id, opts) => {
80
+ try {
81
+ const client = makeClient();
82
+ const updates = {};
83
+ if (opts.rating != null)
84
+ updates.star_rating = opts.rating;
85
+ if (opts.notes)
86
+ updates.notes = opts.notes;
87
+ if (opts.tags)
88
+ updates.local_tags = opts.tags;
89
+ if (opts.appleUrl)
90
+ updates.apple_music_url = opts.appleUrl;
91
+ if (opts.spotifyUrl)
92
+ updates.spotify_url = opts.spotifyUrl;
93
+ if (opts.youtubeUrl)
94
+ updates.youtube_url = opts.youtubeUrl;
95
+ if (opts.soundcloudUrl)
96
+ updates.soundcloud_url = opts.soundcloudUrl;
97
+ if (Object.keys(updates).length === 0) {
98
+ printError("No fields to update. Use --rating, --notes, --tags, etc.");
99
+ process.exit(2);
100
+ }
101
+ await client.updateTrack(id, updates);
102
+ printSuccess("✓ Track updated.");
103
+ }
104
+ catch (err) {
105
+ printError(err instanceof Error ? err.message : String(err));
106
+ process.exit(1);
107
+ }
108
+ });
109
+ tracks
110
+ .command("missing-apple-music")
111
+ .description("List tracks missing Apple Music URLs")
112
+ .option("--page <n>", "Page number", parseInt, 1)
113
+ .option("--page-size <n>", "Results per page", parseInt, 50)
114
+ .option("--username <u>", "Username")
115
+ .option("--json", "Output as JSON")
116
+ .action(async (opts) => {
117
+ try {
118
+ const client = makeClient();
119
+ const result = await client.getMissingAppleMusic(opts.page, opts.pageSize, opts.username);
120
+ if (opts.json) {
121
+ printJson(result);
122
+ }
123
+ else {
124
+ console.log(`Tracks missing Apple Music URLs: ${result.total} total`);
125
+ printTracks(result.tracks, false);
126
+ }
127
+ }
128
+ catch (err) {
129
+ printError(err instanceof Error ? err.message : String(err));
130
+ process.exit(1);
131
+ }
132
+ });
133
+ tracks
134
+ .command("deleted")
135
+ .description("List soft-deleted tracks")
136
+ .option("--friend-id <n>", "Filter by friend ID", parseInt)
137
+ .option("--limit <n>", "Max results", parseInt, 100)
138
+ .option("--offset <n>", "Offset", parseInt, 0)
139
+ .option("--json", "Output as JSON")
140
+ .action(async (opts) => {
141
+ try {
142
+ const client = makeClient();
143
+ const result = await client.listDeletedTracks(opts.friendId, {
144
+ limit: opts.limit,
145
+ offset: opts.offset,
146
+ });
147
+ if (opts.json) {
148
+ printJson(result);
149
+ }
150
+ else {
151
+ console.log(`Deleted tracks: ${result.total} total`);
152
+ printTracks(result.tracks, false);
153
+ }
154
+ }
155
+ catch (err) {
156
+ printError(err instanceof Error ? err.message : String(err));
157
+ process.exit(1);
158
+ }
159
+ });
160
+ tracks
161
+ .command("restore <id>")
162
+ .description("Restore a soft-deleted track")
163
+ .option("--friend-id <n>", "Friend ID (defaults to config default_friend_id)", parseInt)
164
+ .action(async (id, opts) => {
165
+ try {
166
+ const cfg = loadConfig();
167
+ const client = makeClient();
168
+ const friendId = opts.friendId ?? cfg.default_friend_id;
169
+ await client.restoreTrack(id, friendId);
170
+ printSuccess(`✓ Track ${id} restored.`);
171
+ }
172
+ catch (err) {
173
+ printError(err instanceof Error ? err.message : String(err));
174
+ process.exit(1);
175
+ }
176
+ });
177
+ tracks
178
+ .command("recommend <id>")
179
+ .description("Get combined recommendations using both identity and audio vibe embeddings")
180
+ .option("--limit <n>", "Number of candidates to return", parseInt, 20)
181
+ .option("--json", "Output as JSON")
182
+ .action(async (id, opts) => {
183
+ try {
184
+ const cfg = loadConfig();
185
+ const client = makeClient();
186
+ const result = await client.getRecommendationCandidates(id, cfg.default_friend_id, {
187
+ limit_identity: opts.limit,
188
+ limit_audio: opts.limit,
189
+ });
190
+ if (opts.json) {
191
+ printJson(result);
192
+ }
193
+ else {
194
+ console.log(`Recommendations for ${chalk.cyan(id)} — ${result.candidates.length} candidates` +
195
+ chalk.dim(` (identity:${result.stats.identityCount} vibe:${result.stats.audioCount} union:${result.stats.unionCount})`));
196
+ printRecommendationCandidates(result.candidates);
197
+ }
198
+ }
199
+ catch (err) {
200
+ printError(err instanceof Error ? err.message : String(err));
201
+ process.exit(1);
202
+ }
203
+ });
204
+ tracks
205
+ .command("similar-identity <id>")
206
+ .description("Find tracks with similar identity (genre, era, style, tags)")
207
+ .option("--limit <n>", "Number of results", parseInt, 10)
208
+ .option("--era <era>", "Filter by era (e.g. '1970s')")
209
+ .option("--country <country>", "Filter by country")
210
+ .option("--tags <tags>", "Comma-separated tags to filter by")
211
+ .option("--json", "Output as JSON")
212
+ .action(async (id, opts) => {
213
+ try {
214
+ const cfg = loadConfig();
215
+ const client = makeClient();
216
+ const result = await client.findSimilarIdentity(id, cfg.default_friend_id, {
217
+ limit: opts.limit,
218
+ era: opts.era,
219
+ country: opts.country,
220
+ tags: opts.tags,
221
+ });
222
+ if (opts.json) {
223
+ printJson(result);
224
+ }
225
+ else {
226
+ console.log(`Similar identity tracks for ${chalk.cyan(id)} (${result.count} results):`);
227
+ printSimilarTracks(result.tracks);
228
+ }
229
+ }
230
+ catch (err) {
231
+ printError(err instanceof Error ? err.message : String(err));
232
+ process.exit(1);
233
+ }
234
+ });
235
+ tracks
236
+ .command("similar-vibe <id>")
237
+ .description("Find tracks with similar audio vibe (BPM, mood, danceability)")
238
+ .option("--limit <n>", "Number of results", parseInt, 10)
239
+ .option("--json", "Output as JSON")
240
+ .action(async (id, opts) => {
241
+ try {
242
+ const cfg = loadConfig();
243
+ const client = makeClient();
244
+ const result = await client.findSimilarVibe(id, cfg.default_friend_id, {
245
+ limit: opts.limit,
246
+ });
247
+ if (opts.json) {
248
+ printJson(result);
249
+ }
250
+ else {
251
+ console.log(`Similar vibe tracks for ${chalk.cyan(id)} (${result.count} results):`);
252
+ printSimilarTracks(result.tracks);
253
+ }
254
+ }
255
+ catch (err) {
256
+ printError(err instanceof Error ? err.message : String(err));
257
+ process.exit(1);
258
+ }
259
+ });
260
+ }
261
+ function printRecommendationCandidates(candidates) {
262
+ for (const c of candidates) {
263
+ const bpm = c.metadata.bpm ? chalk.dim(` BPM:${c.metadata.bpm}`) : "";
264
+ const key = c.metadata.key ? chalk.dim(` Key:${c.metadata.key}`) : "";
265
+ const identity = c.simIdentity != null ? chalk.green(` id:${c.simIdentity.toFixed(3)}`) : "";
266
+ const audio = c.simAudio != null ? chalk.blue(` vibe:${c.simAudio.toFixed(3)}`) : "";
267
+ console.log(` ${chalk.cyan(c.trackId)} ${chalk.bold(c.metadata.title)} ${chalk.dim("—")} ${c.metadata.artist} ${chalk.dim("(" + c.metadata.album + ")")}${bpm}${key}${identity}${audio}`);
268
+ }
269
+ }
270
+ function printSimilarTracks(tracks) {
271
+ for (const t of tracks) {
272
+ const bpm = t.bpm ? chalk.dim(` BPM:${t.bpm}`) : "";
273
+ const key = t.key ? chalk.dim(` Key:${t.key}`) : "";
274
+ const dist = chalk.yellow(` [dist: ${Number(t.distance).toFixed(4)}]`);
275
+ console.log(` ${chalk.cyan(t.track_id)} ${chalk.bold(t.title)} ${chalk.dim("—")} ${t.artist} ${chalk.dim("(" + t.album + ")")}${bpm}${key}${dist}`);
276
+ }
277
+ }
278
+ //# sourceMappingURL=tracks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracks.js","sourceRoot":"","sources":["../../src/commands/tracks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Track, Playlist, Friend } from "@groovenet/client";
2
+ export declare function printJson(data: unknown): void;
3
+ export declare function printError(msg: string): void;
4
+ export declare function printSuccess(msg: string): void;
5
+ export declare function printTracks(tracks: Track[], json: boolean): void;
6
+ export declare function printTrack(track: Track, json: boolean): void;
7
+ export declare function printPlaylists(playlists: Playlist[], json: boolean): void;
8
+ export declare function printFriends(friends: Friend[], json: boolean): void;
9
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEjE,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAgChE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAoC5D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAsBzE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAiBnE"}
@@ -0,0 +1,126 @@
1
+ import chalk from "chalk";
2
+ import Table from "cli-table3";
3
+ export function printJson(data) {
4
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
5
+ }
6
+ export function printError(msg) {
7
+ process.stderr.write(chalk.red(`Error: ${msg}`) + "\n");
8
+ }
9
+ export function printSuccess(msg) {
10
+ process.stdout.write(chalk.green(msg) + "\n");
11
+ }
12
+ export function printTracks(tracks, json) {
13
+ if (json) {
14
+ printJson(tracks);
15
+ return;
16
+ }
17
+ if (tracks.length === 0) {
18
+ console.log(chalk.yellow("No tracks found."));
19
+ return;
20
+ }
21
+ const table = new Table({
22
+ head: [
23
+ chalk.cyan("ID"),
24
+ chalk.cyan("Title"),
25
+ chalk.cyan("Artist"),
26
+ chalk.cyan("BPM"),
27
+ chalk.cyan("Key"),
28
+ chalk.cyan("Rating"),
29
+ ],
30
+ colWidths: [36, 36, 24, 6, 12, 7],
31
+ wordWrap: true,
32
+ });
33
+ for (const t of tracks) {
34
+ table.push([
35
+ t.track_id,
36
+ t.title,
37
+ t.artist,
38
+ t.bpm ?? "-",
39
+ t.key ?? "-",
40
+ t.star_rating != null ? `★${t.star_rating}` : "-",
41
+ ]);
42
+ }
43
+ console.log(table.toString());
44
+ }
45
+ export function printTrack(track, json) {
46
+ if (json) {
47
+ printJson(track);
48
+ return;
49
+ }
50
+ console.log(chalk.bold(`${track.title}`) + chalk.gray(` — ${track.artist}`));
51
+ console.log(chalk.gray(`Album: ${track.album}${track.year ? ` (${track.year})` : ""}`));
52
+ console.log();
53
+ const fields = [
54
+ ["Track ID", track.track_id],
55
+ ["BPM", track.bpm],
56
+ ["Key", track.key],
57
+ ["Danceability", track.danceability],
58
+ ["Duration", track.duration_seconds ? formatDuration(track.duration_seconds) : track.duration],
59
+ ["Star Rating", track.star_rating != null ? `★${track.star_rating}/5` : undefined],
60
+ ["Genres", track.genres?.join(", ")],
61
+ ["Styles", track.styles?.join(", ")],
62
+ ["Tags", track.local_tags],
63
+ ["Notes", track.notes],
64
+ ["Mood — Happy", track.mood_happy],
65
+ ["Mood — Sad", track.mood_sad],
66
+ ["Mood — Relaxed", track.mood_relaxed],
67
+ ["Mood — Aggressive", track.mood_aggressive],
68
+ ["Apple Music", track.apple_music_url],
69
+ ["Spotify", track.spotify_url],
70
+ ["YouTube", track.youtube_url],
71
+ ["SoundCloud", track.soundcloud_url],
72
+ ["Discogs", track.discogs_url],
73
+ ];
74
+ for (const [label, value] of fields) {
75
+ if (value != null && value !== "" && value !== "-") {
76
+ console.log(` ${chalk.gray(label + ":")} ${value}`);
77
+ }
78
+ }
79
+ }
80
+ export function printPlaylists(playlists, json) {
81
+ if (json) {
82
+ printJson(playlists);
83
+ return;
84
+ }
85
+ if (playlists.length === 0) {
86
+ console.log(chalk.yellow("No playlists found."));
87
+ return;
88
+ }
89
+ const table = new Table({
90
+ head: [chalk.cyan("ID"), chalk.cyan("Name"), chalk.cyan("Tracks"), chalk.cyan("Created")],
91
+ colWidths: [6, 40, 8, 22],
92
+ });
93
+ for (const p of playlists) {
94
+ table.push([
95
+ p.id,
96
+ p.name,
97
+ p.tracks?.length ?? 0,
98
+ p.created_at ? new Date(p.created_at).toLocaleDateString() : "-",
99
+ ]);
100
+ }
101
+ console.log(table.toString());
102
+ }
103
+ export function printFriends(friends, json) {
104
+ if (json) {
105
+ printJson(friends);
106
+ return;
107
+ }
108
+ if (friends.length === 0) {
109
+ console.log(chalk.yellow("No friends added yet."));
110
+ return;
111
+ }
112
+ const table = new Table({
113
+ head: [chalk.cyan("ID"), chalk.cyan("Username")],
114
+ colWidths: [6, 40],
115
+ });
116
+ for (const f of friends) {
117
+ table.push([f.id, f.username]);
118
+ }
119
+ console.log(table.toString());
120
+ }
121
+ function formatDuration(seconds) {
122
+ const m = Math.floor(seconds / 60);
123
+ const s = String(seconds % 60).padStart(2, "0");
124
+ return `${m}:${s}`;
125
+ }
126
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@groovenet/cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI for managing your Groovenet DJ collection",
5
+ "type": "module",
6
+ "engines": { "node": ">=22.12.0" },
7
+ "bin": {
8
+ "groovenet": "build/bin/groovenet.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node build/bin/groovenet.js"
14
+ },
15
+ "files": ["build/"],
16
+ "publishConfig": { "access": "public" },
17
+ "keywords": ["groovenet", "dj", "music", "playlist", "cli"],
18
+ "license": "MIT",
19
+ "dependencies": {
20
+ "@groovenet/client": "^1.0.0",
21
+ "chalk": "^6",
22
+ "cli-table3": "^0.6",
23
+ "commander": "^15"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^26",
27
+ "typescript": "^7.0"
28
+ }
29
+ }