@bzenky/spoti 0.2.0 → 0.4.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 (70) hide show
  1. package/README.md +122 -4
  2. package/dist/app.d.ts +23 -1
  3. package/dist/app.js +397 -36
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth/config.d.ts +1 -1
  6. package/dist/auth/config.js +3 -3
  7. package/dist/auth/config.js.map +1 -1
  8. package/dist/cli.js +54 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/services/auth.service.d.ts +1 -1
  11. package/dist/services/auth.service.js +9 -3
  12. package/dist/services/auth.service.js.map +1 -1
  13. package/dist/services/catalog.service.d.ts +9 -0
  14. package/dist/services/catalog.service.js +22 -0
  15. package/dist/services/catalog.service.js.map +1 -0
  16. package/dist/services/device.service.js +22 -2
  17. package/dist/services/device.service.js.map +1 -1
  18. package/dist/services/library.service.d.ts +13 -0
  19. package/dist/services/library.service.js +46 -0
  20. package/dist/services/library.service.js.map +1 -0
  21. package/dist/services/mappers.d.ts +10 -0
  22. package/dist/services/mappers.js +104 -0
  23. package/dist/services/mappers.js.map +1 -0
  24. package/dist/services/models.d.ts +45 -0
  25. package/dist/services/player.service.d.ts +4 -1
  26. package/dist/services/player.service.js +21 -14
  27. package/dist/services/player.service.js.map +1 -1
  28. package/dist/services/playlist.service.d.ts +9 -0
  29. package/dist/services/playlist.service.js +33 -0
  30. package/dist/services/playlist.service.js.map +1 -0
  31. package/dist/services/recent.service.d.ts +7 -0
  32. package/dist/services/recent.service.js +24 -0
  33. package/dist/services/recent.service.js.map +1 -0
  34. package/dist/services/search.service.d.ts +5 -1
  35. package/dist/services/search.service.js +32 -17
  36. package/dist/services/search.service.js.map +1 -1
  37. package/dist/services/update.service.d.ts +57 -0
  38. package/dist/services/update.service.js +313 -0
  39. package/dist/services/update.service.js.map +1 -0
  40. package/dist/spotify/client.js +14 -1
  41. package/dist/spotify/client.js.map +1 -1
  42. package/dist/spotify/scopes.d.ts +1 -1
  43. package/dist/spotify/scopes.js +4 -0
  44. package/dist/spotify/scopes.js.map +1 -1
  45. package/dist/spotify/types.d.ts +110 -8
  46. package/dist/storage/config.d.ts +5 -1
  47. package/dist/storage/config.js +21 -1
  48. package/dist/storage/config.js.map +1 -1
  49. package/dist/storage/update-cache.d.ts +29 -0
  50. package/dist/storage/update-cache.js +135 -0
  51. package/dist/storage/update-cache.js.map +1 -0
  52. package/dist/ui/completions.d.ts +3 -0
  53. package/dist/ui/completions.js +237 -0
  54. package/dist/ui/completions.js.map +1 -0
  55. package/dist/ui/interactive-search.d.ts +33 -0
  56. package/dist/ui/interactive-search.js +174 -0
  57. package/dist/ui/interactive-search.js.map +1 -0
  58. package/dist/ui/output.d.ts +10 -1
  59. package/dist/ui/output.js +60 -0
  60. package/dist/ui/output.js.map +1 -1
  61. package/dist/ui/progress.d.ts +6 -0
  62. package/dist/ui/progress.js +25 -0
  63. package/dist/ui/progress.js.map +1 -0
  64. package/dist/ui/prompts.d.ts +12 -1
  65. package/dist/ui/prompts.js +73 -6
  66. package/dist/ui/prompts.js.map +1 -1
  67. package/dist/update-worker.d.ts +9 -0
  68. package/dist/update-worker.js +91 -0
  69. package/dist/update-worker.js.map +1 -0
  70. package/package.json +1 -1
@@ -5,5 +5,9 @@ export const LEGACY_SPOTIFY_SCOPES = [
5
5
  export const SPOTIFY_SCOPES = [
6
6
  ...LEGACY_SPOTIFY_SCOPES,
7
7
  'user-read-currently-playing',
8
+ 'playlist-read-private',
9
+ 'user-library-read',
10
+ 'user-library-modify',
11
+ 'user-read-recently-played',
8
12
  ];
9
13
  //# sourceMappingURL=scopes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../src/spotify/scopes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,0BAA0B;IAC1B,4BAA4B;CACpB,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,qBAAqB;IACxB,6BAA6B;CACrB,CAAC"}
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../src/spotify/scopes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,0BAA0B;IAC1B,4BAA4B;CACpB,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,qBAAqB;IACxB,6BAA6B;IAC7B,uBAAuB;IACvB,mBAAmB;IACnB,qBAAqB;IACrB,2BAA2B;CACnB,CAAC"}
@@ -3,6 +3,9 @@ export interface SpotifyImage {
3
3
  height: number | null;
4
4
  width: number | null;
5
5
  }
6
+ export interface SpotifyExternalUrls {
7
+ spotify?: string;
8
+ }
6
9
  export interface SpotifyUserProfile {
7
10
  id: string;
8
11
  display_name: string | null;
@@ -10,26 +13,117 @@ export interface SpotifyUserProfile {
10
13
  }
11
14
  export interface SpotifyArtist {
12
15
  id: string;
16
+ uri?: string;
17
+ name: string;
18
+ external_urls?: SpotifyExternalUrls;
19
+ }
20
+ export interface SpotifyFullArtist extends SpotifyArtist {
21
+ uri: string;
22
+ images: SpotifyImage[];
23
+ }
24
+ export interface SpotifySimplifiedAlbum {
25
+ id?: string;
26
+ uri?: string;
13
27
  name: string;
28
+ album_type?: string;
29
+ artists?: SpotifyArtist[];
30
+ images: SpotifyImage[];
31
+ release_date?: string;
32
+ total_tracks?: number;
33
+ external_urls?: SpotifyExternalUrls;
14
34
  }
15
35
  export interface SpotifyTrack {
16
- id: string;
36
+ type?: 'track';
37
+ id: string | null;
17
38
  uri: string;
18
39
  name: string;
19
40
  duration_ms: number;
20
41
  artists: SpotifyArtist[];
21
- album: {
22
- name: string;
23
- images: SpotifyImage[];
42
+ album: SpotifySimplifiedAlbum;
43
+ is_local?: boolean;
44
+ is_playable?: boolean;
45
+ external_urls?: SpotifyExternalUrls;
46
+ }
47
+ export interface SpotifySimplifiedTrack {
48
+ type?: 'track';
49
+ id: string | null;
50
+ uri: string;
51
+ name: string;
52
+ duration_ms: number;
53
+ artists: SpotifyArtist[];
54
+ is_local?: boolean;
55
+ is_playable?: boolean;
56
+ external_urls?: SpotifyExternalUrls;
57
+ }
58
+ export interface SpotifyAlbum extends SpotifySimplifiedAlbum {
59
+ id: string;
60
+ uri: string;
61
+ artists: SpotifyArtist[];
62
+ tracks: SpotifyPaging<SpotifySimplifiedTrack>;
63
+ }
64
+ export interface SpotifyPlaylistOwner {
65
+ id: string;
66
+ display_name: string | null;
67
+ }
68
+ export interface SpotifySimplifiedPlaylist {
69
+ id: string;
70
+ uri: string;
71
+ name: string;
72
+ description: string | null;
73
+ public: boolean | null;
74
+ collaborative: boolean;
75
+ owner: SpotifyPlaylistOwner;
76
+ images: SpotifyImage[] | null;
77
+ external_urls?: SpotifyExternalUrls;
78
+ items: {
79
+ total: number;
24
80
  };
25
- external_urls?: {
26
- spotify?: string;
81
+ }
82
+ export interface SpotifyPlaylist extends SpotifySimplifiedPlaylist {
83
+ followers?: {
84
+ total: number;
85
+ };
86
+ }
87
+ export interface SpotifyEpisode {
88
+ type: 'episode';
89
+ id?: string | null;
90
+ uri?: string;
91
+ name?: string;
92
+ }
93
+ export type SpotifyPlaybackItem = SpotifyTrack | SpotifyEpisode | Record<string, unknown>;
94
+ export interface SpotifyPlaylistItem {
95
+ added_at: string | null;
96
+ is_local: boolean;
97
+ item: SpotifyPlaybackItem | null;
98
+ }
99
+ export interface SpotifyRecentlyPlayedItem {
100
+ track: SpotifyPlaybackItem | null;
101
+ played_at: string;
102
+ context: {
103
+ uri: string;
104
+ } | null;
105
+ }
106
+ export interface SpotifyPaging<T> {
107
+ items: T[];
108
+ limit: number;
109
+ offset: number;
110
+ total: number;
111
+ next: string | null;
112
+ previous: string | null;
113
+ }
114
+ export interface SpotifyCursorPaging<T> {
115
+ items: T[];
116
+ limit: number;
117
+ next: string | null;
118
+ cursors?: {
119
+ after?: string;
120
+ before?: string;
27
121
  };
28
122
  }
29
123
  export interface SpotifyPlaybackState {
30
124
  is_playing: boolean;
31
125
  progress_ms: number | null;
32
- item: SpotifyTrack | null;
126
+ item: SpotifyPlaybackItem | null;
33
127
  device: {
34
128
  id: string | null;
35
129
  name: string;
@@ -39,10 +133,18 @@ export interface SpotifyPlaybackState {
39
133
  };
40
134
  }
41
135
  export interface SpotifySearchResponse {
42
- tracks: {
136
+ tracks?: SpotifyPaging<SpotifyTrack> | {
43
137
  items: SpotifyTrack[];
44
138
  };
139
+ albums?: SpotifyPaging<SpotifySimplifiedAlbum>;
140
+ artists?: SpotifyPaging<SpotifyFullArtist>;
141
+ playlists?: SpotifyPaging<SpotifySimplifiedPlaylist | null>;
142
+ }
143
+ export interface SpotifySavedTrack {
144
+ added_at: string;
145
+ track: SpotifyTrack;
45
146
  }
147
+ export type SpotifyRecentlyPlayedResponse = SpotifyCursorPaging<SpotifyRecentlyPlayedItem>;
46
148
  export interface SpotifyErrorBody {
47
149
  error?: {
48
150
  status?: number;
@@ -1,16 +1,19 @@
1
1
  import { z } from 'zod';
2
2
  declare const configSchema: z.ZodObject<{
3
+ spotifyClientId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
3
4
  watchAfterPlay: z.ZodDefault<z.ZodBoolean>;
4
5
  refreshIntervalMs: z.ZodDefault<z.ZodNumber>;
5
6
  }, z.core.$strict>;
6
7
  export type AppConfig = z.infer<typeof configSchema>;
7
- export declare const CONFIG_KEYS: readonly ["watchAfterPlay", "refreshIntervalMs"];
8
+ export declare const CONFIG_KEYS: readonly ["spotifyClientId", "watchAfterPlay", "refreshIntervalMs"];
8
9
  export type ConfigKey = (typeof CONFIG_KEYS)[number];
9
10
  export declare const DEFAULT_CONFIG: Readonly<AppConfig>;
10
11
  export interface ConfigStore {
12
+ readonly path?: string;
11
13
  read(): Promise<AppConfig>;
12
14
  write(config: AppConfig): Promise<void>;
13
15
  set<Key extends ConfigKey>(key: Key, value: AppConfig[Key]): Promise<void>;
16
+ resetKey<Key extends ConfigKey>(key: Key): Promise<void>;
14
17
  reset(): Promise<void>;
15
18
  }
16
19
  export interface FileConfigStoreOptions {
@@ -23,6 +26,7 @@ export declare class FileConfigStore implements ConfigStore {
23
26
  read(): Promise<AppConfig>;
24
27
  write(config: AppConfig): Promise<void>;
25
28
  set<Key extends ConfigKey>(key: Key, value: AppConfig[Key]): Promise<void>;
29
+ resetKey<Key extends ConfigKey>(key: Key): Promise<void>;
26
30
  reset(): Promise<void>;
27
31
  }
28
32
  export declare function parseConfigValue<Key extends ConfigKey>(key: Key, value: string): AppConfig[Key];
@@ -4,11 +4,22 @@ import { join } from 'node:path';
4
4
  import { z } from 'zod';
5
5
  import { ConfigurationError, toError } from '../utils/errors.js';
6
6
  import { getConfigDirectory } from './credentials.js';
7
+ const spotifyClientIdSchema = z
8
+ .string()
9
+ .trim()
10
+ .min(1)
11
+ .max(256)
12
+ .regex(/^[A-Za-z0-9]+$/);
7
13
  const configSchema = z.strictObject({
14
+ spotifyClientId: spotifyClientIdSchema.nullable().default(null),
8
15
  watchAfterPlay: z.boolean().default(false),
9
16
  refreshIntervalMs: z.number().int().min(1_000).max(30_000).default(1_000),
10
17
  });
11
- export const CONFIG_KEYS = ['watchAfterPlay', 'refreshIntervalMs'];
18
+ export const CONFIG_KEYS = [
19
+ 'spotifyClientId',
20
+ 'watchAfterPlay',
21
+ 'refreshIntervalMs',
22
+ ];
12
23
  export const DEFAULT_CONFIG = Object.freeze(configSchema.parse({}));
13
24
  export class FileConfigStore {
14
25
  path;
@@ -72,6 +83,9 @@ export class FileConfigStore {
72
83
  const current = await this.read();
73
84
  await this.write({ ...current, [key]: value });
74
85
  }
86
+ async resetKey(key) {
87
+ await this.set(key, DEFAULT_CONFIG[key]);
88
+ }
75
89
  async reset() {
76
90
  try {
77
91
  await unlink(this.path);
@@ -84,6 +98,12 @@ export class FileConfigStore {
84
98
  }
85
99
  }
86
100
  export function parseConfigValue(key, value) {
101
+ if (key === 'spotifyClientId') {
102
+ const clientId = spotifyClientIdSchema.safeParse(value);
103
+ if (clientId.success)
104
+ return clientId.data;
105
+ throw new ConfigurationError('Invalid Spotify client ID: expected a non-empty alphanumeric value.');
106
+ }
87
107
  if (key === 'watchAfterPlay') {
88
108
  if (value === 'true')
89
109
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/storage/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/storage/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface SuccessfulUpdateCheckCache {
2
+ checkedAt: number;
3
+ currentVersion: string;
4
+ latestVersion: string;
5
+ }
6
+ export interface UpdateCache {
7
+ version: 1;
8
+ lastCheckedAt: number;
9
+ lastSuccessfulCheck?: SuccessfulUpdateCheckCache;
10
+ lastFailedCheckAt?: number;
11
+ }
12
+ export interface UpdateCacheStore {
13
+ read(): Promise<UpdateCache | null>;
14
+ write(cache: UpdateCache): Promise<void>;
15
+ }
16
+ export interface FileUpdateCacheStoreOptions {
17
+ directory?: string;
18
+ }
19
+ export declare class UpdateCacheError extends Error {
20
+ constructor(message: string, options?: ErrorOptions);
21
+ }
22
+ export declare class FileUpdateCacheStore implements UpdateCacheStore {
23
+ readonly path: string;
24
+ private readonly directory;
25
+ constructor(options?: FileUpdateCacheStoreOptions);
26
+ read(): Promise<UpdateCache | null>;
27
+ write(cache: UpdateCache): Promise<void>;
28
+ }
29
+ export declare function parseUpdateCache(value: unknown): UpdateCache;
@@ -0,0 +1,135 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { chmod, mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { getConfigDirectory } from './credentials.js';
5
+ export class UpdateCacheError extends Error {
6
+ constructor(message, options) {
7
+ super(message, options);
8
+ this.name = 'UpdateCacheError';
9
+ }
10
+ }
11
+ export class FileUpdateCacheStore {
12
+ path;
13
+ directory;
14
+ constructor(options = {}) {
15
+ this.directory = options.directory ?? getConfigDirectory();
16
+ this.path = join(this.directory, 'update-cache.json');
17
+ }
18
+ async read() {
19
+ let contents;
20
+ try {
21
+ contents = await readFile(this.path, 'utf8');
22
+ }
23
+ catch (error) {
24
+ if (isFileNotFound(error))
25
+ return null;
26
+ throw new UpdateCacheError(`Unable to read the update cache: ${errorMessage(error)}`, {
27
+ cause: error,
28
+ });
29
+ }
30
+ try {
31
+ return parseUpdateCache(JSON.parse(contents));
32
+ }
33
+ catch {
34
+ // Cache data is disposable. Treat malformed or partially written data as a cache miss.
35
+ return null;
36
+ }
37
+ }
38
+ async write(cache) {
39
+ const validated = parseUpdateCache(cache);
40
+ try {
41
+ await mkdir(this.directory, { recursive: true, mode: 0o700 });
42
+ await chmod(this.directory, 0o700);
43
+ }
44
+ catch (error) {
45
+ throw new UpdateCacheError(`Unable to prepare the update cache directory: ${errorMessage(error)}`, {
46
+ cause: error,
47
+ });
48
+ }
49
+ const temporaryPath = join(this.directory, `.update-cache-${randomUUID()}.tmp`);
50
+ try {
51
+ await writeFile(temporaryPath, `${JSON.stringify(validated, null, 2)}\n`, {
52
+ encoding: 'utf8',
53
+ flag: 'wx',
54
+ mode: 0o600,
55
+ });
56
+ await chmod(temporaryPath, 0o600);
57
+ await rename(temporaryPath, this.path);
58
+ await chmod(this.path, 0o600);
59
+ }
60
+ catch (error) {
61
+ await unlink(temporaryPath).catch(() => undefined);
62
+ throw new UpdateCacheError(`Unable to store the update cache: ${errorMessage(error)}`, {
63
+ cause: error,
64
+ });
65
+ }
66
+ }
67
+ }
68
+ export function parseUpdateCache(value) {
69
+ if (!isRecord(value) || !hasOnlyKeys(value, CACHE_KEYS)) {
70
+ throw new UpdateCacheError('The update cache has an invalid format.');
71
+ }
72
+ if (value.version !== 1 || !isTimestamp(value.lastCheckedAt)) {
73
+ throw new UpdateCacheError('The update cache has an invalid format.');
74
+ }
75
+ const successful = parseSuccessfulCheck(value.lastSuccessfulCheck);
76
+ const failedAt = value.lastFailedCheckAt;
77
+ if (failedAt !== undefined && !isTimestamp(failedAt)) {
78
+ throw new UpdateCacheError('The update cache has an invalid format.');
79
+ }
80
+ if (!successful && failedAt === undefined) {
81
+ throw new UpdateCacheError('The update cache has an invalid format.');
82
+ }
83
+ const newestOutcomeAt = Math.max(successful?.checkedAt ?? -1, failedAt ?? -1);
84
+ if (value.lastCheckedAt !== newestOutcomeAt) {
85
+ throw new UpdateCacheError('The update cache has inconsistent timestamps.');
86
+ }
87
+ return {
88
+ version: 1,
89
+ lastCheckedAt: value.lastCheckedAt,
90
+ ...(successful ? { lastSuccessfulCheck: successful } : {}),
91
+ ...(failedAt === undefined ? {} : { lastFailedCheckAt: failedAt }),
92
+ };
93
+ }
94
+ const CACHE_KEYS = new Set([
95
+ 'version',
96
+ 'lastCheckedAt',
97
+ 'lastSuccessfulCheck',
98
+ 'lastFailedCheckAt',
99
+ ]);
100
+ const SUCCESS_KEYS = new Set(['checkedAt', 'currentVersion', 'latestVersion']);
101
+ function parseSuccessfulCheck(value) {
102
+ if (value === undefined)
103
+ return undefined;
104
+ if (!isRecord(value) ||
105
+ !hasOnlyKeys(value, SUCCESS_KEYS) ||
106
+ !isTimestamp(value.checkedAt) ||
107
+ !isNonemptyString(value.currentVersion) ||
108
+ !isNonemptyString(value.latestVersion)) {
109
+ throw new UpdateCacheError('The update cache has an invalid successful check.');
110
+ }
111
+ return {
112
+ checkedAt: value.checkedAt,
113
+ currentVersion: value.currentVersion,
114
+ latestVersion: value.latestVersion,
115
+ };
116
+ }
117
+ function isRecord(value) {
118
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
119
+ }
120
+ function hasOnlyKeys(value, allowed) {
121
+ return Object.keys(value).every((key) => allowed.has(key));
122
+ }
123
+ function isTimestamp(value) {
124
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
125
+ }
126
+ function isNonemptyString(value) {
127
+ return typeof value === 'string' && value.length > 0;
128
+ }
129
+ function isFileNotFound(error) {
130
+ return isRecord(error) && error.code === 'ENOENT';
131
+ }
132
+ function errorMessage(error) {
133
+ return error instanceof Error ? error.message : String(error);
134
+ }
135
+ //# sourceMappingURL=update-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-cache.js","sourceRoot":"","sources":["../../src/storage/update-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type CompletionShell = 'bash' | 'zsh' | 'fish';
2
+ /** Return a self-contained completion definition without running the spoti CLI. */
3
+ export declare function generateCompletionScript(shell: CompletionShell): string;