spotifyplus 0.1.2 → 0.1.4

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 (2) hide show
  1. package/dev.cjs +62 -81
  2. package/package.json +1 -1
package/dev.cjs CHANGED
@@ -32,9 +32,7 @@ var import_node_util = require("node:util");
32
32
  var import_esbuild = require("esbuild");
33
33
  var execFile = (0, import_node_util.promisify)(import_node_child_process.execFile);
34
34
  var DEFAULT_PORT = 37846;
35
- var DEFAULT_MODULE_PACKAGE = "com.lenerd.spotifyplus";
36
- var START_BRIDGE_ACTION = "com.lenerd.spotifyplus.action.START_BRIDGE";
37
- var HOT_RELOAD_ACTION = "com.lenerd.spotifyplus.action.HOT_RELOAD";
35
+ var RUNTIME_PORT = 37846;
38
36
  var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".json"]);
39
37
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".gradle"]);
40
38
  function parseArgs(argv) {
@@ -43,8 +41,6 @@ function parseArgs(argv) {
43
41
  adb: process.env.ADB || "adb",
44
42
  device: "",
45
43
  port: DEFAULT_PORT,
46
- modulePackage: DEFAULT_MODULE_PACKAGE,
47
- spotifyPackage: "com.spotify.music",
48
44
  debounceMs: 150,
49
45
  help: false
50
46
  };
@@ -72,12 +68,6 @@ function parseArgs(argv) {
72
68
  case "port":
73
69
  options.port = parseInteger(value, "--port");
74
70
  break;
75
- case "module-package":
76
- options.modulePackage = value;
77
- break;
78
- case "spotify-package":
79
- options.spotifyPackage = value;
80
- break;
81
71
  case "debounce-ms":
82
72
  options.debounceMs = parseInteger(value, "--debounce-ms");
83
73
  break;
@@ -101,9 +91,7 @@ function printHelp() {
101
91
  Options:
102
92
  --adb <path> adb executable to use (default: adb)
103
93
  --device <serial> adb device serial
104
- --port <port> local HTTP/reverse port (default: ${DEFAULT_PORT})
105
- --module-package <name> SpotifyPlus manager app package (default: ${DEFAULT_MODULE_PACKAGE})
106
- --spotify-package <name> Spotify app package, reserved for future checks (default: com.spotify.music)
94
+ --port <port> local forwarded hot reload port (default: ${DEFAULT_PORT})
107
95
  --debounce-ms <ms> file change debounce (default: 150)
108
96
  --help, -h show this help
109
97
  `);
@@ -119,7 +107,7 @@ async function readManifest(scriptDir) {
119
107
  }
120
108
  async function bundleScript(scriptDir) {
121
109
  const manifest = await readManifest(scriptDir);
122
- const entryPath = import_node_path.default.resolve(scriptDir, manifest.main);
110
+ const entryPath = await resolveEntryPath(scriptDir, manifest);
123
111
  const result = await (0, import_esbuild.build)({
124
112
  entryPoints: [entryPath],
125
113
  bundle: true,
@@ -139,35 +127,26 @@ async function bundleScript(scriptDir) {
139
127
  source
140
128
  };
141
129
  }
142
- function createReloadServer(state, port) {
143
- const server = import_node_http.default.createServer((request, response) => {
144
- const url = new URL(request.url ?? "/", `http://127.0.0.1:${port}`);
145
- const match = /^\/reload\/([^/]+)\/([^/]+)\.json$/.exec(url.pathname);
146
- if (!match) {
147
- response.writeHead(404, { "content-type": "application/json" });
148
- response.end(JSON.stringify({ error: "not found" }));
149
- return;
130
+ async function resolveEntryPath(scriptDir, manifest) {
131
+ const manifestEntry = import_node_path.default.resolve(scriptDir, manifest.main);
132
+ if (import_node_fs.default.existsSync(manifestEntry)) return manifestEntry;
133
+ const candidates = [
134
+ "src/index.tsx",
135
+ "src/index.ts",
136
+ "src/index.jsx",
137
+ "src/index.js",
138
+ "index.tsx",
139
+ "index.ts",
140
+ "index.jsx"
141
+ ];
142
+ for (const candidate of candidates) {
143
+ const candidatePath = import_node_path.default.resolve(scriptDir, candidate);
144
+ if (import_node_fs.default.existsSync(candidatePath)) {
145
+ console.warn(`[spotifyplus] manifest.main points to missing ${manifest.main}; using ${candidate} as the dev entry`);
146
+ return candidatePath;
150
147
  }
151
- const [, buildId, scriptId] = match;
152
- const current = state.currentBuild;
153
- if (!current || current.buildId !== buildId || current.manifest.id !== decodeURIComponent(scriptId)) {
154
- response.writeHead(404, { "content-type": "application/json" });
155
- response.end(JSON.stringify({ error: "build not found" }));
156
- return;
157
- }
158
- response.writeHead(200, {
159
- "content-type": "application/json; charset=utf-8",
160
- "cache-control": "no-store"
161
- });
162
- response.end(JSON.stringify(current));
163
- });
164
- return new Promise((resolve, reject) => {
165
- server.once("error", reject);
166
- server.listen(port, "127.0.0.1", () => {
167
- server.off("error", reject);
168
- resolve(server);
169
- });
170
- });
148
+ }
149
+ throw new Error(`Could not resolve ${manifestEntry}. Set manifest.main to a real source file, or add src/index.tsx.`);
171
150
  }
172
151
  async function adb(options, args) {
173
152
  const fullArgs = [];
@@ -183,37 +162,43 @@ async function adb(options, args) {
183
162
  }
184
163
  }
185
164
  async function notifyDevice(options, buildInfo) {
186
- const encodedScriptId = encodeURIComponent(buildInfo.manifest.id);
187
- const url = `http://127.0.0.1:${options.port}/reload/${buildInfo.buildId}/${encodedScriptId}.json`;
188
- await adb(options, ["reverse", `tcp:${options.port}`, `tcp:${options.port}`]);
189
- await adb(options, [
190
- "shell",
191
- "am",
192
- "broadcast",
193
- "-a",
194
- START_BRIDGE_ACTION,
195
- "-n",
196
- `${options.modulePackage}/.manager.bridge.BridgeStartReceiver`
197
- ]);
198
- await adb(options, [
199
- "shell",
200
- "am",
201
- "broadcast",
202
- "-a",
203
- HOT_RELOAD_ACTION,
204
- "-n",
205
- `${options.modulePackage}/.manager.bridge.HotReloadReceiver`,
206
- "--es",
207
- "scriptId",
208
- buildInfo.manifest.id,
209
- "--es",
210
- "buildId",
211
- buildInfo.buildId,
212
- "--es",
213
- "url",
214
- url
215
- ]);
216
- return url;
165
+ await adb(options, ["forward", `tcp:${options.port}`, `tcp:${RUNTIME_PORT}`]);
166
+ await postHotReloadBundle(options.port, buildInfo);
167
+ }
168
+ function postHotReloadBundle(port, buildInfo) {
169
+ const body = JSON.stringify(buildInfo);
170
+ return new Promise((resolve, reject) => {
171
+ const request = import_node_http.default.request({
172
+ host: "127.0.0.1",
173
+ port,
174
+ path: "/hot-reload",
175
+ method: "POST",
176
+ headers: {
177
+ "content-type": "application/json; charset=utf-8",
178
+ "content-length": Buffer.byteLength(body)
179
+ }
180
+ }, (response) => {
181
+ response.setEncoding("utf8");
182
+ let responseBody = "";
183
+ response.on("data", (chunk) => {
184
+ responseBody += chunk;
185
+ });
186
+ response.on("end", () => {
187
+ if ((response.statusCode ?? 0) >= 200 && (response.statusCode ?? 0) < 300) {
188
+ resolve(responseBody);
189
+ return;
190
+ }
191
+ reject(new Error(`SpotifyPlus runtime returned HTTP ${response.statusCode}: ${responseBody}`));
192
+ });
193
+ });
194
+ request.on("error", (error) => {
195
+ reject(new Error(`Could not reach SpotifyPlus runtime on forwarded port ${port}. Open Spotify and wait for the script runtime to start, then try again. ${error.message}`));
196
+ });
197
+ request.setTimeout(5e3, () => {
198
+ request.destroy(new Error(`Timed out connecting to SpotifyPlus runtime on forwarded port ${port}`));
199
+ });
200
+ request.end(body);
201
+ });
217
202
  }
218
203
  function shouldWatchFile(filePath) {
219
204
  return WATCH_EXTENSIONS.has(import_node_path.default.extname(filePath).toLowerCase());
@@ -262,9 +247,8 @@ async function run() {
262
247
  printHelp();
263
248
  return;
264
249
  }
265
- const state = { currentBuild: null };
266
- const server = await createReloadServer(state, options.port);
267
- console.log(`[spotifyplus] dev server listening on http://127.0.0.1:${options.port}`);
250
+ await adb(options, ["forward", `tcp:${options.port}`, `tcp:${RUNTIME_PORT}`]);
251
+ console.log(`[spotifyplus] forwarding http://127.0.0.1:${options.port} to the SpotifyPlus runtime`);
268
252
  console.log(`[spotifyplus] watching ${options.scriptDir}`);
269
253
  let buildInFlight = false;
270
254
  let pendingBuild = false;
@@ -276,10 +260,8 @@ async function run() {
276
260
  buildInFlight = true;
277
261
  try {
278
262
  const buildInfo = await bundleScript(options.scriptDir);
279
- state.currentBuild = buildInfo;
280
- const url = await notifyDevice(options, buildInfo);
263
+ await notifyDevice(options, buildInfo);
281
264
  console.log(`[spotifyplus] reloaded ${buildInfo.manifest.id} (${buildInfo.buildId})`);
282
- console.log(`[spotifyplus] served ${url}`);
283
265
  } catch (error) {
284
266
  console.error(`[spotifyplus] ${reason} failed`);
285
267
  console.error(error?.message ?? error);
@@ -303,7 +285,6 @@ async function run() {
303
285
  await rebuild("initial build");
304
286
  const close = () => {
305
287
  closeWatchers();
306
- server.close();
307
288
  process.exit(0);
308
289
  };
309
290
  process.on("SIGINT", close);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spotifyplus",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "commonjs",
5
5
  "main": "./index.cjs",
6
6
  "types": "./index.d.ts",