@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 +1 -1
- package/dist/src/commands/play.js +49 -1
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -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}`
|