@feralfile/cli 2.2.2 → 2.2.3

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.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feralfile/cli",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "description": "CLI for building, signing, and playing DP-1 playlists of digital art on Feral File devices",
5
5
  "repository": {
6
6
  "type": "git",
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.playCommand = void 0;
7
7
  exports.describeDiscoveryInput = describeDiscoveryInput;
8
+ exports.probeDiscoveryUrlAsPlaylist = probeDiscoveryUrlAsPlaylist;
8
9
  const commander_1 = require("commander");
9
10
  const chalk_1 = __importDefault(require("chalk"));
10
11
  const source_resolver_1 = require("@feralfile/source-resolver");
@@ -62,6 +63,46 @@ function describeDiscoveryInput(source) {
62
63
  return 'an artwork reference';
63
64
  }
64
65
  }
66
+ /**
67
+ * probeDiscoveryUrlAsPlaylist loads a discovery-classified http(s) URL as a
68
+ * DP-1 playlist document, or returns null when it is not one.
69
+ *
70
+ * The discovery parser claims whole hosts — any *.feralfile.com URL parses
71
+ * as a Feral File URL, and non-exhibition paths come back `unsupported` —
72
+ * which wrongly redirected DP-1 feed playlist URLs
73
+ * (https://feed.feralfile.com/api/v1/playlists/{slug}, exactly the URLs the
74
+ * feed hands out) to `find`, which has no feed route either; the documented
75
+ * "hosted playlist URL plays directly" contract was unreachable for them
76
+ * (found 2026-08-02 casting a published playlist to an FF1).
77
+ *
78
+ * Probing the document keeps both behaviors without a host allowlist: a URL
79
+ * that serves DP-1 JSON (`dpVersion` marker) plays directly; a marketplace
80
+ * *page* fails the probe (non-JSON, or JSON with no marker) and still
81
+ * redirects to `find` instead of being wrapped as a web item. The probe
82
+ * costs one fetch before a redirect, only for discovery inputs that are
83
+ * http(s) URLs; coordinates and wallet addresses never hit the network.
84
+ */
85
+ async function probeDiscoveryUrlAsPlaylist(source) {
86
+ if (!(0, playlist_source_1.isPlaylistSourceUrl)(source)) {
87
+ return null;
88
+ }
89
+ try {
90
+ const loaded = await (0, playlist_source_1.loadPlaylistSource)(source);
91
+ const document = loaded.playlist;
92
+ if (typeof document?.dpVersion !== 'string') {
93
+ return null;
94
+ }
95
+ return {
96
+ kind: 'playlist',
97
+ playlist: loaded.playlist,
98
+ sourceType: loaded.sourceType,
99
+ source: loaded.source,
100
+ };
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
65
106
  exports.playCommand = new commander_1.Command('play')
66
107
  .description('Play a playlist or media URL on an FF1 device')
67
108
  .argument('<source>', 'Playlist file, playlist URL, or media URL')
@@ -72,8 +113,15 @@ exports.playCommand = new commander_1.Command('play')
72
113
  // `play` casts an exact playable source. A marketplace URL / on-chain
73
114
  // coords / wallet must be resolved through the indexer first — redirect
74
115
  // to `find` rather than silently wrapping the *page* as a web item.
116
+ // Exception: a discovery-classified URL that actually serves a DP-1
117
+ // playlist document (the discovery parser claims whole hosts, catching
118
+ // feed playlist URLs) plays directly — see probeDiscoveryUrlAsPlaylist.
75
119
  const discovery = describeDiscoveryInput(source);
120
+ let probed = null;
76
121
  if (discovery) {
122
+ probed = await probeDiscoveryUrlAsPlaylist(source);
123
+ }
124
+ if (discovery && !probed) {
77
125
  console.error(chalk_1.default.red('\n`play` casts an exact playlist or media URL — it does not search marketplaces.'));
78
126
  console.error(chalk_1.default.dim(` "${source}" looks like ${discovery}, which needs to be resolved first.`));
79
127
  const deviceFlag = options.device ? ` -d "${options.device}"` : '';
@@ -83,7 +131,7 @@ exports.playCommand = new commander_1.Command('play')
83
131
  const config = (0, config_1.getConfig)();
84
132
  // No explicit duration: a direct video/audio URL plays its natural
85
133
  // length (DP-1 §4.1); static media uses config.defaultDuration.
86
- const resolved = await (0, playlist_source_1.resolvePlaySource)(source);
134
+ const resolved = probed ?? (await (0, playlist_source_1.resolvePlaySource)(source));
87
135
  const isPlaylistSource = resolved.kind === 'playlist';
88
136
  const sourceLabel = isPlaylistSource
89
137
  ? `${resolved.sourceType}: ${resolved.source}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feralfile/cli",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "description": "CLI for building, signing, and playing DP-1 playlists of digital art on Feral File devices",
5
5
  "repository": {
6
6
  "type": "git",