morille 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 (82) hide show
  1. package/README.md +15 -3
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +2 -1
  4. package/dist/app.js.map +1 -1
  5. package/dist/components/device-indicator.d.ts +18 -0
  6. package/dist/components/device-indicator.d.ts.map +1 -0
  7. package/dist/components/device-indicator.js +53 -0
  8. package/dist/components/device-indicator.js.map +1 -0
  9. package/dist/components/device-picker-view.d.ts +10 -0
  10. package/dist/components/device-picker-view.d.ts.map +1 -0
  11. package/dist/components/device-picker-view.js +65 -0
  12. package/dist/components/device-picker-view.js.map +1 -0
  13. package/dist/components/panel-content.d.ts.map +1 -1
  14. package/dist/components/panel-content.js +4 -0
  15. package/dist/components/panel-content.js.map +1 -0
  16. package/dist/components/player.d.ts.map +1 -1
  17. package/dist/components/player.js +35 -3
  18. package/dist/components/player.js.map +1 -1
  19. package/dist/contexts/devices-context.d.ts +28 -0
  20. package/dist/contexts/devices-context.d.ts.map +1 -0
  21. package/dist/contexts/devices-context.js +33 -0
  22. package/dist/contexts/devices-context.js.map +1 -0
  23. package/dist/contexts/panel-mode-context.d.ts +2 -1
  24. package/dist/contexts/panel-mode-context.d.ts.map +1 -0
  25. package/dist/contexts/panel-mode-context.js +3 -0
  26. package/dist/contexts/panel-mode-context.js.map +1 -0
  27. package/dist/hooks/use-album-art.d.ts.map +1 -1
  28. package/dist/hooks/use-album-art.js +2 -1
  29. package/dist/hooks/use-album-art.js.map +1 -1
  30. package/dist/hooks/use-browse.d.ts.map +1 -1
  31. package/dist/hooks/use-browse.js +4 -3
  32. package/dist/hooks/use-browse.js.map +1 -1
  33. package/dist/hooks/use-devices.d.ts +24 -0
  34. package/dist/hooks/use-devices.d.ts.map +1 -0
  35. package/dist/hooks/use-devices.js +106 -0
  36. package/dist/hooks/use-devices.js.map +1 -0
  37. package/dist/hooks/use-playback.d.ts +7 -0
  38. package/dist/hooks/use-playback.d.ts.map +1 -1
  39. package/dist/hooks/use-playback.js +31 -9
  40. package/dist/hooks/use-playback.js.map +1 -1
  41. package/dist/hooks/use-player-input.d.ts.map +1 -1
  42. package/dist/hooks/use-player-input.js +31 -2
  43. package/dist/hooks/use-player-input.js.map +1 -0
  44. package/dist/hooks/use-queue.d.ts.map +1 -1
  45. package/dist/hooks/use-queue.js +3 -2
  46. package/dist/hooks/use-queue.js.map +1 -1
  47. package/dist/hooks/use-search.d.ts.map +1 -1
  48. package/dist/hooks/use-search.js +2 -1
  49. package/dist/hooks/use-search.js.map +1 -0
  50. package/dist/icons.d.ts +7 -0
  51. package/dist/icons.d.ts.map +1 -1
  52. package/dist/icons.js +8 -0
  53. package/dist/icons.js.map +1 -1
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +4 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/logger.d.ts +9 -0
  59. package/dist/logger.d.ts.map +1 -0
  60. package/dist/logger.js +15 -0
  61. package/dist/logger.js.map +1 -0
  62. package/dist/spotify/auth.d.ts.map +1 -1
  63. package/dist/spotify/auth.js +2 -1
  64. package/dist/spotify/auth.js.map +1 -1
  65. package/dist/spotify/client.d.ts.map +1 -1
  66. package/dist/spotify/client.js +2 -1
  67. package/dist/spotify/client.js.map +1 -1
  68. package/dist/spotify/devices.d.ts +36 -0
  69. package/dist/spotify/devices.d.ts.map +1 -0
  70. package/dist/spotify/devices.js +72 -0
  71. package/dist/spotify/devices.js.map +1 -0
  72. package/dist/spotify/fetch-with-retry.d.ts.map +1 -1
  73. package/dist/spotify/fetch-with-retry.js +5 -4
  74. package/dist/spotify/fetch-with-retry.js.map +1 -0
  75. package/dist/spotify/lyrics.d.ts.map +1 -1
  76. package/dist/spotify/lyrics.js +3 -2
  77. package/dist/spotify/lyrics.js.map +1 -1
  78. package/dist/spotify/playback.d.ts +3 -0
  79. package/dist/spotify/playback.d.ts.map +1 -1
  80. package/dist/spotify/playback.js +39 -21
  81. package/dist/spotify/playback.js.map +1 -1
  82. package/package.json +1 -1
package/README.md CHANGED
@@ -43,6 +43,21 @@ and rebuild.
43
43
 
44
44
  [quota]: https://developer.spotify.com/documentation/web-api/concepts/quota-modes
45
45
 
46
+ ### Debug output
47
+
48
+ morille is silent on stderr by default so the terminal UI stays clean. To see
49
+ internal diagnostics (fetch traces, retry notices, auth and API errors), run
50
+ with the `--debug` flag or set the `DEBUG=1` environment variable:
51
+
52
+ ```sh
53
+ npx morille --debug
54
+ # or
55
+ DEBUG=1 npx morille
56
+ ```
57
+
58
+ Debug output is written to stderr and will visibly interfere with the ink UI —
59
+ this mode is intended for development, not regular use.
60
+
46
61
  ## Usage
47
62
 
48
63
  - **Space** - toggle play/pause
@@ -74,9 +89,6 @@ pnpm test:biome # lint/format check
74
89
 
75
90
  - Add track to queue
76
91
  - Device selection / transfer playback
77
- - ~~Search tracks, albums, artists, and playlists~~
78
- - ~~Browse and play playlists~~
79
- - ~~Browse and play albums~~
80
92
  - Show recently played tracks
81
93
  - Like / unlike tracks (save to library)
82
94
  - Keyboard shortcuts customization
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAgB,GAAG,4CAmFlB"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wBAAgB,GAAG,4CAmFlB"}
package/dist/app.js CHANGED
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text, useApp, useInput } from 'ink';
3
3
  import { useEffect, useRef, useState } from 'react';
4
4
  import { Player } from './components/player.js';
5
+ import { logger } from './logger.js';
5
6
  import { createSpotifyClient, getClientId } from './spotify/client.js';
6
7
  /**
7
8
  * Root application component. Handles Spotify authentication on mount,
@@ -31,7 +32,7 @@ export function App() {
31
32
  }
32
33
  }
33
34
  catch (err) {
34
- console.error('Spotify authentication failed:', err);
35
+ logger.error('Spotify authentication failed:', err);
35
36
  if (!cancelled) {
36
37
  setAuthError(err instanceof Error ? err.message : 'Authentication failed');
37
38
  }
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { DeviceType } from '../spotify/devices.js';
2
+ type DeviceIndicatorProps = {
3
+ name: string | null;
4
+ type: DeviceType | null;
5
+ };
6
+ /**
7
+ * Picks a glyph for a device type. Kept as an exported helper so the
8
+ * device-picker-view can reuse it next to each row without duplicating the
9
+ * icon-to-type mapping.
10
+ */
11
+ export declare function deviceIcon(type: DeviceType | null): string;
12
+ /**
13
+ * Compact always-visible header badge showing which Spotify Connect device
14
+ * is currently playing. On narrow terminals (<60 columns) only the glyph is
15
+ * rendered so the animated title still has room.
16
+ */
17
+ export declare function DeviceIndicator({ name, type }: DeviceIndicatorProps): import("react/jsx-runtime").JSX.Element;
18
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-indicator.d.ts","sourceRoot":"","sources":["../../src/components/device-indicator.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIxD,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,MAAM,CA2B1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,oBAAoB,2CAanE"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Text, useWindowSize } from 'ink';
3
+ import { ICON_DEVICE_CAR, ICON_DEVICE_COMPUTER, ICON_DEVICE_GAME, ICON_DEVICE_PHONE, ICON_DEVICE_SPEAKER, ICON_DEVICE_TV, ICON_DEVICE_UNKNOWN, } from '../icons.js';
4
+ const MIN_WIDE_COLUMNS = 60;
5
+ /**
6
+ * Picks a glyph for a device type. Kept as an exported helper so the
7
+ * device-picker-view can reuse it next to each row without duplicating the
8
+ * icon-to-type mapping.
9
+ */
10
+ export function deviceIcon(type) {
11
+ switch (type) {
12
+ case 'Computer':
13
+ return ICON_DEVICE_COMPUTER;
14
+ case 'Smartphone':
15
+ return ICON_DEVICE_PHONE;
16
+ case 'Speaker':
17
+ case 'AVR':
18
+ case 'STB':
19
+ case 'AudioDongle':
20
+ case 'CastAudio':
21
+ return ICON_DEVICE_SPEAKER;
22
+ case 'TV':
23
+ case 'CastVideo':
24
+ return ICON_DEVICE_TV;
25
+ case 'Automobile':
26
+ return ICON_DEVICE_CAR;
27
+ case 'GameConsole':
28
+ return ICON_DEVICE_GAME;
29
+ case 'Unknown':
30
+ case null:
31
+ return ICON_DEVICE_UNKNOWN;
32
+ default: {
33
+ const _exhaustive = type;
34
+ return _exhaustive;
35
+ }
36
+ }
37
+ }
38
+ /**
39
+ * Compact always-visible header badge showing which Spotify Connect device
40
+ * is currently playing. On narrow terminals (<60 columns) only the glyph is
41
+ * rendered so the animated title still has room.
42
+ */
43
+ export function DeviceIndicator({ name, type }) {
44
+ const { columns } = useWindowSize();
45
+ const glyph = deviceIcon(type);
46
+ if (!name) {
47
+ return _jsx(Text, { dimColor: true, children: `${glyph} no device` });
48
+ }
49
+ if (columns < MIN_WIDE_COLUMNS) {
50
+ return _jsx(Text, { dimColor: true, children: glyph });
51
+ }
52
+ return _jsx(Text, { dimColor: true, children: `${glyph} ${name}` });
53
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-indicator.js","sourceRoot":"","sources":["../../src/components/device-indicator.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAGrB,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAO5B;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,UAAU;YACb,OAAO,oBAAoB,CAAC;QAC9B,KAAK,YAAY;YACf,OAAO,iBAAiB,CAAC;QAC3B,KAAK,SAAS,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,aAAa,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,mBAAmB,CAAC;QAC7B,KAAK,IAAI,CAAC;QACV,KAAK,WAAW;YACd,OAAO,cAAc,CAAC;QACxB,KAAK,YAAY;YACf,OAAO,eAAe,CAAC;QACzB,KAAK,aAAa;YAChB,OAAO,gBAAgB,CAAC;QAC1B,KAAK,SAAS,CAAC;QACf,KAAK,IAAI;YACP,OAAO,mBAAmB,CAAC;QAC7B,SAAS,CAAC;YACR,MAAM,WAAW,GAAU,IAAI,CAAC;YAChC,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAwB;IAClE,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,KAAK,YAAY,GAAQ,CAAC;IACtD,CAAC;IAED,IAAI,OAAO,GAAG,gBAAgB,EAAE,CAAC;QAC/B,OAAO,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,GAAQ,CAAC;IACvC,CAAC;IAED,OAAO,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,KAAK,IAAI,IAAI,EAAE,GAAQ,CAAC;AACpD,CAAC"}
@@ -0,0 +1,10 @@
1
+ type DevicePickerViewProps = {
2
+ height: number;
3
+ };
4
+ /**
5
+ * Device picker panel — lists Spotify Connect devices and lets the user
6
+ * transfer playback to one. The currently active device is highlighted in
7
+ * green; arrow keys move the cursor and enter triggers the transfer.
8
+ */
9
+ export declare function DevicePickerView({ height }: DevicePickerViewProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-picker-view.d.ts","sourceRoot":"","sources":["../../src/components/device-picker-view.tsx"],"names":[],"mappings":"AAKA,KAAK,qBAAqB,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAuCF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,EAAE,qBAAqB,2CAsDjE"}
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import { useDevicesContext } from '../contexts/devices-context.js';
4
+ import { deviceIcon } from './device-indicator.js';
5
+ function formatType(type) {
6
+ if (type === 'Unknown')
7
+ return '';
8
+ if (type === 'AVR' || type === 'STB' || type === 'TV')
9
+ return type;
10
+ // Break "GameConsole" / "CastVideo" / "CastAudio" / "AudioDongle" into two words
11
+ return type.replace(/([a-z])([A-Z])/g, '$1 $2');
12
+ }
13
+ function formatVolume(vol) {
14
+ if (vol === null)
15
+ return '';
16
+ return `${vol}%`;
17
+ }
18
+ function DeviceRow({ device, isSelected }) {
19
+ const icon = deviceIcon(device.type);
20
+ const type = formatType(device.type);
21
+ const volume = formatVolume(device.volumePercent);
22
+ const details = [
23
+ type,
24
+ volume,
25
+ ]
26
+ .filter((s) => s.length > 0)
27
+ .join(' · ');
28
+ const label = details ? `${icon} ${device.name} ${details}` : `${icon} ${device.name}`;
29
+ if (device.isActive) {
30
+ return (_jsx(Text, { bold: true, color: "green", inverse: isSelected, children: label }));
31
+ }
32
+ if (isSelected) {
33
+ return _jsx(Text, { inverse: true, children: label });
34
+ }
35
+ return _jsx(Text, { children: label });
36
+ }
37
+ /**
38
+ * Device picker panel — lists Spotify Connect devices and lets the user
39
+ * transfer playback to one. The currently active device is highlighted in
40
+ * green; arrow keys move the cursor and enter triggers the transfer.
41
+ */
42
+ export function DevicePickerView({ height }) {
43
+ const { devices, isLoading, selectedIndex, error } = useDevicesContext();
44
+ if (isLoading && devices.length === 0) {
45
+ return _jsx(Text, { dimColor: true, children: "Loading devices..." });
46
+ }
47
+ if (devices.length === 0) {
48
+ return _jsx(Text, { dimColor: true, children: "No devices available. Open Spotify on a device to connect." });
49
+ }
50
+ const activeName = devices.find((d) => d.isActive)?.name ?? null;
51
+ const headerLines = 1;
52
+ const availableHeight = Math.max(height - headerLines, 2);
53
+ const visibleCount = Math.min(availableHeight, devices.length);
54
+ const halfHeight = Math.floor(availableHeight / 2);
55
+ const startIndex = Math.max(0, Math.min(selectedIndex - halfHeight, devices.length - visibleCount));
56
+ return (_jsxs(Box, { flexDirection: "column", height: height, overflow: "hidden", children: [_jsxs(Box, { gap: 1, borderColor: "gray", borderStyle: "single", borderBottom: true, borderLeft: false, borderRight: false, borderTop: false, children: [_jsx(Text, { bold: true, children: "Devices" }), _jsx(Text, { dimColor: true, children: "-" }), _jsxs(Text, { dimColor: true, children: [devices.length, " available"] }), activeName && _jsxs(Text, { dimColor: true, children: ["\u00B7 on ", activeName] })] }), Array.from({
57
+ length: visibleCount,
58
+ }, (_, i) => {
59
+ const idx = startIndex + i;
60
+ const device = devices[idx];
61
+ if (!device)
62
+ return _jsx(Text, { children: " " }, idx);
63
+ return _jsx(DeviceRow, { device: device, isSelected: idx === selectedIndex }, device.id);
64
+ }), error && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "red", children: error }) }))] }));
65
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-picker-view.js","sourceRoot":"","sources":["../../src/components/device-picker-view.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"panel-content.d.ts","sourceRoot":"","sources":["../../src/components/panel-content.tsx"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,iBAAiB,kDAgBrE"}
1
+ {"version":3,"file":"panel-content.d.ts","sourceRoot":"","sources":["../../src/components/panel-content.tsx"],"names":[],"mappings":"AAMA,KAAK,iBAAiB,GAAG;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,iBAAiB,kDAoBrE"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { usePanelMode } from '../contexts/panel-mode-context.js';
3
+ import { DevicePickerView } from './device-picker-view.js';
3
4
  import { LyricsPanel } from './lyrics-panel.js';
4
5
  import { QueueView } from './queue-view.js';
5
6
  import { SearchPanel } from './search-panel.js';
@@ -18,5 +19,8 @@ export function PanelContent({ progressMs, height }) {
18
19
  if (panelMode === 'search') {
19
20
  return _jsx(SearchPanel, { height: height });
20
21
  }
22
+ if (panelMode === 'devices') {
23
+ return _jsx(DevicePickerView, { height: height });
24
+ }
21
25
  return null;
22
26
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-content.js","sourceRoot":"","sources":["../../src/components/panel-content.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAOhD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,UAAU,EAAE,MAAM,EAAqB;IACpE,MAAM,EAAE,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;IAErC,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,KAAC,WAAW,IAAC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAI,CAAC;IACjE,CAAC;IAED,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,KAAC,SAAS,IAAC,MAAM,EAAE,MAAM,GAAI,CAAC;IACvC,CAAC;IAED,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,KAAC,WAAW,IAAC,MAAM,EAAE,MAAM,GAAI,CAAC;IACzC,CAAC;IAED,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,KAAC,gBAAgB,IAAC,MAAM,EAAE,MAAM,GAAI,CAAC;IAC9C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../src/components/player.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAqB1D,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAmLF;;GAEG;AACH,wBAAgB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,WAAW,2CAM7C"}
1
+ {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../src/components/player.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAuB1D,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAgNF;;GAEG;AACH,wBAAgB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,WAAW,2CAM7C"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Spacer, useWindowSize } from 'ink';
3
3
  import { useMemo } from 'react';
4
4
  import { LYRICS_WIDE_COLUMNS } from '../config.js';
5
+ import { DevicesProvider } from '../contexts/devices-context.js';
5
6
  import { LyricsProvider, useLyricsContext } from '../contexts/lyrics-context.js';
6
7
  import { PanelModeProvider, usePanelMode } from '../contexts/panel-mode-context.js';
7
8
  import { QueueProvider } from '../contexts/queue-context.js';
@@ -12,6 +13,7 @@ import { usePlayerInput } from '../hooks/use-player-input.js';
12
13
  import { ICON_ARROW_HORIZONTAL, ICON_ARROW_VERTICAL } from '../icons.js';
13
14
  import { AnimatedSubtitle } from './animated-subtitle.js';
14
15
  import { AnimatedTitle } from './animated-title.js';
16
+ import { DeviceIndicator } from './device-indicator.js';
15
17
  import { KeyboardHints } from './keyboard-hints.js';
16
18
  import { PanelContent } from './panel-content.js';
17
19
  import { PlaybackStatus } from './playback-status.js';
@@ -107,6 +109,30 @@ function buildHints(panelMode, lyricsOffset, isPlainText, isInputMode) {
107
109
  },
108
110
  ];
109
111
  }
112
+ if (panelMode === 'devices') {
113
+ return [
114
+ {
115
+ key: ICON_ARROW_VERTICAL,
116
+ label: 'navigate',
117
+ },
118
+ {
119
+ key: 'enter',
120
+ label: 'switch',
121
+ },
122
+ {
123
+ key: 'c',
124
+ label: 'close',
125
+ },
126
+ {
127
+ key: 'esc',
128
+ label: 'close',
129
+ },
130
+ {
131
+ key: 'q',
132
+ label: 'quit',
133
+ },
134
+ ];
135
+ }
110
136
  if (panelMode === 'lyrics') {
111
137
  const hints = [];
112
138
  if (isPlainText) {
@@ -175,6 +201,10 @@ function buildHints(panelMode, lyricsOffset, isPlainText, isInputMode) {
175
201
  key: 'b',
176
202
  label: 'playlists',
177
203
  },
204
+ {
205
+ key: 'c',
206
+ label: 'devices',
207
+ },
178
208
  {
179
209
  key: 'q',
180
210
  label: 'quit',
@@ -195,12 +225,12 @@ function PlayerWithProviders({ client }) {
195
225
  const { track, isLoading, error } = playback;
196
226
  const { columns, rows } = useWindowSize();
197
227
  const { panelMode, hasPanel } = usePanelMode();
198
- return (_jsx(LyricsProvider, { track: track, children: _jsx(QueueProvider, { client: client, track: track, playTrackUri: playback.playTrackUri, refresh: playback.refresh, children: _jsx(SearchProvider, { client: client, track: track, playTrackUri: playback.playTrackUri, refresh: playback.refresh, children: _jsx(PlayerUI, { playback: playback, track: track, isLoading: isLoading, error: error, columns: columns, rows: rows, panelMode: panelMode, hasPanel: hasPanel }) }) }) }));
228
+ return (_jsx(LyricsProvider, { track: track, children: _jsx(QueueProvider, { client: client, track: track, playTrackUri: playback.playTrackUri, refresh: playback.refresh, children: _jsx(SearchProvider, { client: client, track: track, playTrackUri: playback.playTrackUri, refresh: playback.refresh, children: _jsx(DevicesProvider, { client: client, track: track, children: _jsx(PlayerUI, { playback: playback, track: track, activeDevice: playback.activeDevice, isLoading: isLoading, error: error, columns: columns, rows: rows, panelMode: panelMode, hasPanel: hasPanel }) }) }) }) }));
199
229
  }
200
230
  /**
201
231
  * Pure UI component - consumes contexts for panel data, receives playback as props.
202
232
  */
203
- function PlayerUI({ playback, track, isLoading, error, columns, rows, panelMode, hasPanel }) {
233
+ function PlayerUI({ playback, track, activeDevice, isLoading, error, columns, rows, panelMode, hasPanel, }) {
204
234
  const { offset: lyricsOffset, isPlainText: isPlainLyrics } = useLyricsContext();
205
235
  const { isInputMode } = usePanelMode();
206
236
  const layout = computeLayout(columns, rows, hasPanel, false);
@@ -215,5 +245,7 @@ function PlayerUI({ playback, track, isLoading, error, columns, rows, panelMode,
215
245
  ]);
216
246
  const showPanelWide = finalLayout.isPanelWide && hasPanel && !!track;
217
247
  const showPanelNarrow = !finalLayout.isPanelWide && hasPanel && !!track;
218
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, height: "100%", borderColor: "black", borderStyle: "single", children: [_jsx(AnimatedTitle, { text: "morille", isPlaying: track?.isPlaying ?? false }), _jsx(AnimatedSubtitle, { hasError: !!error, hasTrack: !!track, isPlaying: track?.isPlaying ?? false, panelMode: panelMode }), _jsxs(Box, { marginTop: 1, flexDirection: showPanelWide ? 'row' : 'column', flexGrow: 1, children: [_jsx(Box, { flexDirection: "column", width: showPanelWide ? finalLayout.leftWidth : undefined, flexGrow: showPanelWide ? 0 : 1, children: _jsx(PlaybackStatus, { track: track, isLoading: isLoading, error: error, art: art, progressBarWidth: finalLayout.progressBarWidth }) }), showPanelWide && track && (_jsx(SidePanel, { width: finalLayout.panelColumnWidth || undefined, isWideLayout: true, children: _jsx(PanelContent, { progressMs: track.progressMs, height: finalLayout.panelHeight }) }))] }), showPanelNarrow && track && (_jsx(SidePanel, { width: undefined, isWideLayout: false, children: _jsx(PanelContent, { progressMs: track.progressMs, height: finalLayout.panelHeight }) })), _jsx(Spacer, {}), _jsx(KeyboardHints, { hints: hints }), _jsx(TrackFacts, { track: track })] }));
248
+ const indicatorName = track?.deviceName ?? activeDevice?.name ?? null;
249
+ const indicatorType = track?.deviceType ?? activeDevice?.type ?? null;
250
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, height: "100%", borderColor: "black", borderStyle: "single", children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(AnimatedTitle, { text: "morille", isPlaying: track?.isPlaying ?? false }), _jsx(Spacer, {}), _jsx(DeviceIndicator, { name: indicatorName, type: indicatorType })] }), _jsx(AnimatedSubtitle, { hasError: !!error, hasTrack: !!track, isPlaying: track?.isPlaying ?? false, panelMode: panelMode }), _jsxs(Box, { marginTop: 1, flexDirection: showPanelWide ? 'row' : 'column', flexGrow: 1, children: [_jsx(Box, { flexDirection: "column", width: showPanelWide ? finalLayout.leftWidth : undefined, flexGrow: showPanelWide ? 0 : 1, children: _jsx(PlaybackStatus, { track: track, isLoading: isLoading, error: error, art: art, progressBarWidth: finalLayout.progressBarWidth }) }), showPanelWide && track && (_jsx(SidePanel, { width: finalLayout.panelColumnWidth || undefined, isWideLayout: true, children: _jsx(PanelContent, { progressMs: track.progressMs, height: finalLayout.panelHeight }) }))] }), showPanelNarrow && track && (_jsx(SidePanel, { width: undefined, isWideLayout: false, children: _jsx(PanelContent, { progressMs: track.progressMs, height: finalLayout.panelHeight }) })), _jsx(Spacer, {}), _jsx(KeyboardHints, { hints: hints }), _jsx(TrackFacts, { track: track })] }));
219
251
  }
@@ -1 +1 @@
1
- {"version":3,"file":"player.js","sourceRoot":"","sources":["../../src/components/player.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"player.js","sourceRoot":"","sources":["../../src/components/player.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { SpotifyApi } from '@spotify/web-api-ts-sdk';
2
+ import type { ReactNode } from 'react';
3
+ import type { SpotifyDevice } from '../spotify/devices.js';
4
+ import type { TrackInfo } from '../spotify/playback.js';
5
+ type DevicesContextValue = {
6
+ devices: SpotifyDevice[];
7
+ isLoading: boolean;
8
+ selectedIndex: number;
9
+ error: string | null;
10
+ devicesUp: (() => void) | undefined;
11
+ devicesDown: (() => void) | undefined;
12
+ devicesSelect: (() => Promise<void>) | undefined;
13
+ };
14
+ type DevicesProviderProps = {
15
+ client: SpotifyApi;
16
+ track: TrackInfo | null;
17
+ children: ReactNode;
18
+ };
19
+ /**
20
+ * Provides Spotify Connect device list and transfer-playback controls.
21
+ * Only fetches the device list while the devices panel is active.
22
+ */
23
+ export declare function DevicesProvider({ client, track, children }: DevicesProviderProps): import("react/jsx-runtime").JSX.Element;
24
+ /**
25
+ * Access the device list and transfer controls.
26
+ */
27
+ export declare function useDevicesContext(): DevicesContextValue;
28
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devices-context.d.ts","sourceRoot":"","sources":["../../src/contexts/devices-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGxD,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACtC,aAAa,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAClD,CAAC;AAIF,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,oBAAoB,2CAqBhF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CAIvD"}
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from 'react';
3
+ import { useDevices } from '../hooks/use-devices.js';
4
+ import { usePanelMode } from './panel-mode-context.js';
5
+ const DevicesContext = createContext(null);
6
+ /**
7
+ * Provides Spotify Connect device list and transfer-playback controls.
8
+ * Only fetches the device list while the devices panel is active.
9
+ */
10
+ export function DevicesProvider({ client, track, children }) {
11
+ const { panelMode } = usePanelMode();
12
+ const isActive = panelMode === 'devices';
13
+ const { devices, isLoading, selectedIndex, error, up, down, select } = useDevices(client, isActive, track?.isPlaying ?? false);
14
+ const value = {
15
+ devices,
16
+ isLoading,
17
+ selectedIndex,
18
+ error,
19
+ devicesUp: isActive ? up : undefined,
20
+ devicesDown: isActive ? down : undefined,
21
+ devicesSelect: isActive ? select : undefined,
22
+ };
23
+ return _jsx(DevicesContext, { value: value, children: children });
24
+ }
25
+ /**
26
+ * Access the device list and transfer controls.
27
+ */
28
+ export function useDevicesContext() {
29
+ const ctx = useContext(DevicesContext);
30
+ if (!ctx)
31
+ throw new Error('useDevicesContext must be used within DevicesProvider');
32
+ return ctx;
33
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devices-context.js","sourceRoot":"","sources":["../../src/contexts/devices-context.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAYvD,MAAM,cAAc,GAAG,aAAa,CAA6B,IAAI,CAAC,CAAC;AAQvE;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAwB;IAC/E,MAAM,EAAE,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,SAAS,KAAK,SAAS,CAAC;IAEzC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAC/E,MAAM,EACN,QAAQ,EACR,KAAK,EAAE,SAAS,IAAI,KAAK,CAC1B,CAAC;IAEF,MAAM,KAAK,GAAwB;QACjC,OAAO;QACP,SAAS;QACT,aAAa;QACb,KAAK;QACL,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QACpC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACxC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KAC7C,CAAC;IAEF,OAAO,KAAC,cAAc,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAkB,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IACvC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACnF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- export type PanelMode = 'none' | 'lyrics' | 'queue' | 'search';
2
+ export type PanelMode = 'none' | 'lyrics' | 'queue' | 'search' | 'devices';
3
3
  type PanelModeContextValue = {
4
4
  panelMode: PanelMode;
5
5
  hasPanel: boolean;
@@ -8,6 +8,7 @@ type PanelModeContextValue = {
8
8
  toggleLyrics: () => void;
9
9
  toggleQueue: () => void;
10
10
  toggleSearch: () => void;
11
+ toggleDevices: () => void;
11
12
  };
12
13
  /**
13
14
  * Provides shared panel mode state. Only one panel can be active at a time.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-mode-context.d.ts","sourceRoot":"","sources":["../../src/contexts/panel-mode-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3E,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CA4CtE;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,qBAAqB,CAIpD"}
@@ -31,6 +31,9 @@ export function PanelModeProvider({ children }) {
31
31
  toggleSearch: useCallback(() => toggle('search'), [
32
32
  toggle,
33
33
  ]),
34
+ toggleDevices: useCallback(() => toggle('devices'), [
35
+ toggle,
36
+ ]),
34
37
  };
35
38
  return _jsx(PanelModeContext, { value: value, children: children });
36
39
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-mode-context.js","sourceRoot":"","sources":["../../src/contexts/panel-mode-context.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAezE,MAAM,gBAAgB,GAAG,aAAa,CAA+B,IAAI,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAE,QAAQ,EAA2B;IACrE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAY,MAAM,CAAC,CAAC;IAC9D,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,IAAe,EAAE,EAAE;QAC7C,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE;YACjB,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YACxC,IAAI,IAAI,KAAK,QAAQ;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAA0B;QACnC,SAAS;QACT,QAAQ,EAAE,SAAS,KAAK,MAAM;QAC9B,WAAW;QACX,YAAY;QACZ,YAAY,EAAE,WAAW,CACvB,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EACtB;YACE,MAAM;SACP,CACF;QACD,WAAW,EAAE,WAAW,CACtB,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EACrB;YACE,MAAM;SACP,CACF;QACD,YAAY,EAAE,WAAW,CACvB,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EACtB;YACE,MAAM;SACP,CACF;QACD,aAAa,EAAE,WAAW,CACxB,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EACvB;YACE,MAAM;SACP,CACF;KACF,CAAC;IAEF,OAAO,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAoB,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-album-art.d.ts","sourceRoot":"","sources":["../../src/hooks/use-album-art.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,iBAyDlE"}
1
+ {"version":3,"file":"use-album-art.d.ts","sourceRoot":"","sources":["../../src/hooks/use-album-art.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,iBAyDlE"}
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
2
  import terminalImage from 'terminal-image';
3
+ import { logger } from '../logger.js';
3
4
  /**
4
5
  * Fetches an album art image and converts it to a terminal-renderable ANSI string.
5
6
  * Caches by URL to avoid re-fetching on every render cycle.
@@ -39,7 +40,7 @@ export function useAlbumArt(imageUrl, height) {
39
40
  }
40
41
  }
41
42
  catch (err) {
42
- console.error(`Failed to render album art for ${imageUrl}:`, err);
43
+ logger.error(`Failed to render album art for ${imageUrl}:`, err);
43
44
  if (!cancelled) {
44
45
  setArt(null);
45
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-album-art.js","sourceRoot":"","sources":["../../src/hooks/use-album-art.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,QAAuB,EAAE,MAAc;IACjE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,MAAM,CAIb,IAAI,CAAC,CAAC;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC7E,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,KAAK,UAAU,IAAI;YACjB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAS,CAAC,CAAC;gBACxC,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACjD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE;oBACvE,MAAM;oBACN,mBAAmB,EAAE,IAAI;oBACzB,kBAAkB,EAAE,KAAK;iBAC1B,CAAC,CAAC;gBAEH,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,QAAQ,CAAC,OAAO,GAAG;wBACjB,GAAG,EAAE,QAAS;wBACd,MAAM;wBACN,GAAG,EAAE,QAAQ;qBACd,CAAC;oBACF,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,kCAAkC,QAAQ,GAAG,EAAE,GAAG,CAAC,CAAC;gBAClE,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC;QACP,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,QAAQ;QACR,MAAM;KACP,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"use-album-art.js","sourceRoot":"","sources":["../../src/hooks/use-album-art.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,QAAuB,EAAE,MAAc;IACjE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,MAAM,CAIb,IAAI,CAAC,CAAC;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC7E,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,KAAK,UAAU,IAAI;YACjB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAS,CAAC,CAAC;gBACxC,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACjD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE;oBACvE,MAAM;oBACN,mBAAmB,EAAE,IAAI;oBACzB,kBAAkB,EAAE,KAAK;iBAC1B,CAAC,CAAC;gBAEH,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,QAAQ,CAAC,OAAO,GAAG;wBACjB,GAAG,EAAE,QAAS;wBACd,MAAM;wBACN,GAAG,EAAE,QAAQ;qBACd,CAAC;oBACF,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,kCAAkC,QAAQ,GAAG,EAAE,GAAG,CAAC,CAAC;gBACjE,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC;QACP,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,QAAQ;QACR,MAAM;KACP,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-browse.d.ts","sourceRoot":"","sources":["../../src/hooks/use-browse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAA+B,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9F,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU;;;;;yBAQxB,MAAM;+BA2BH,MAAM;;;EAyD5B"}
1
+ {"version":3,"file":"use-browse.d.ts","sourceRoot":"","sources":["../../src/hooks/use-browse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,KAAK,EAA+B,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9F,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU;;;;;yBAQxB,MAAM;+BA2BH,MAAM;;;EAyD5B"}
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useRef, useState } from 'react';
2
+ import { logger } from '../logger.js';
2
3
  import { fetchAlbumTracks, fetchPlaylistTracks, fetchUserPlaylists } from '../spotify/search.js';
3
4
  /**
4
5
  * Manages drill-down browse state for albums, playlists, and user playlist library.
@@ -27,7 +28,7 @@ export function useBrowse(client) {
27
28
  });
28
29
  }
29
30
  catch (err) {
30
- console.error(`Failed to load album ${albumId}:`, err);
31
+ logger.error(`Failed to load album ${albumId}:`, err);
31
32
  if (cancelRef.current !== token)
32
33
  return;
33
34
  setData(null);
@@ -55,7 +56,7 @@ export function useBrowse(client) {
55
56
  });
56
57
  }
57
58
  catch (err) {
58
- console.error(`Failed to load playlist ${playlistId}:`, err);
59
+ logger.error(`Failed to load playlist ${playlistId}:`, err);
59
60
  if (cancelRef.current !== token)
60
61
  return;
61
62
  setData(null);
@@ -74,7 +75,7 @@ export function useBrowse(client) {
74
75
  setUserPlaylists(result.items);
75
76
  }
76
77
  catch (err) {
77
- console.error('Failed to load user playlists:', err);
78
+ logger.error('Failed to load user playlists:', err);
78
79
  setUserPlaylists(null);
79
80
  }
80
81
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"use-browse.js","sourceRoot":"","sources":["../../src/hooks/use-browse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-browse.js","sourceRoot":"","sources":["../../src/hooks/use-browse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { SpotifyApi } from '@spotify/web-api-ts-sdk';
2
+ import type { SpotifyDevice } from '../spotify/devices.js';
3
+ /**
4
+ * Fetches and manages the list of Spotify Connect devices while the device
5
+ * picker panel is open. Only fetches when `enabled` is true. Exposes a
6
+ * `select` action that transfers playback to the currently highlighted
7
+ * device using the "mirror current playing state" policy supplied by the
8
+ * caller.
9
+ * @param client - Authenticated Spotify API client
10
+ * @param enabled - Whether the picker is active (gates the initial fetch)
11
+ * @param shouldResume - Current playing state used to decide whether the
12
+ * transferred session should resume on the new device
13
+ * @returns Device list, loading state, and navigation / selection controls
14
+ */
15
+ export declare function useDevices(client: SpotifyApi, enabled: boolean, shouldResume: boolean): {
16
+ devices: SpotifyDevice[];
17
+ isLoading: boolean;
18
+ selectedIndex: number;
19
+ error: string | null;
20
+ up: () => void;
21
+ down: () => void;
22
+ select: () => Promise<void>;
23
+ refresh: () => Promise<void>;
24
+ };