weed-cli 2.5.3__tar.gz → 2.5.5__tar.gz

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 (29) hide show
  1. {weed_cli-2.5.3/weed_cli.egg-info → weed_cli-2.5.5}/PKG-INFO +12 -4
  2. {weed_cli-2.5.3 → weed_cli-2.5.5}/README.md +11 -3
  3. {weed_cli-2.5.3 → weed_cli-2.5.5}/node.py +18 -3
  4. {weed_cli-2.5.3 → weed_cli-2.5.5}/pyproject.toml +1 -1
  5. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_host_live_reload.py +29 -0
  6. {weed_cli-2.5.3 → weed_cli-2.5.5/weed_cli.egg-info}/PKG-INFO +12 -4
  7. {weed_cli-2.5.3 → weed_cli-2.5.5}/LICENSE +0 -0
  8. {weed_cli-2.5.3 → weed_cli-2.5.5}/dht.py +0 -0
  9. {weed_cli-2.5.3 → weed_cli-2.5.5}/discovery_relay.py +0 -0
  10. {weed_cli-2.5.3 → weed_cli-2.5.5}/lightning_settle.py +0 -0
  11. {weed_cli-2.5.3 → weed_cli-2.5.5}/poc_reputation.py +0 -0
  12. {weed_cli-2.5.3 → weed_cli-2.5.5}/setup.cfg +0 -0
  13. {weed_cli-2.5.3 → weed_cli-2.5.5}/shell.py +0 -0
  14. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_dht.py +0 -0
  15. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_discovery_relay.py +0 -0
  16. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_node_manifest.py +0 -0
  17. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_orbit_ws.py +0 -0
  18. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_timing_challenge.py +0 -0
  19. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_tunnel_failover.py +0 -0
  20. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/test_web_ui_api.py +0 -0
  21. {weed_cli-2.5.3 → weed_cli-2.5.5}/tests/testutil.py +0 -0
  22. {weed_cli-2.5.3 → weed_cli-2.5.5}/tunnel_relay.py +0 -0
  23. {weed_cli-2.5.3 → weed_cli-2.5.5}/web_ui.py +0 -0
  24. {weed_cli-2.5.3 → weed_cli-2.5.5}/weed.py +0 -0
  25. {weed_cli-2.5.3 → weed_cli-2.5.5}/weed_cli.egg-info/SOURCES.txt +0 -0
  26. {weed_cli-2.5.3 → weed_cli-2.5.5}/weed_cli.egg-info/dependency_links.txt +0 -0
  27. {weed_cli-2.5.3 → weed_cli-2.5.5}/weed_cli.egg-info/entry_points.txt +0 -0
  28. {weed_cli-2.5.3 → weed_cli-2.5.5}/weed_cli.egg-info/requires.txt +0 -0
  29. {weed_cli-2.5.3 → weed_cli-2.5.5}/weed_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weed-cli
3
- Version: 2.5.3
3
+ Version: 2.5.5
4
4
  Summary: Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel
5
5
  License: MIT
6
6
  Keywords: p2p,video,censorship-resistant,discovery,dht,kademlia,nat-traversal
@@ -246,11 +246,19 @@ Zoom retune every mode; every setting persists in the browser.
246
246
  endless encoders are detected on their own. Every row, plugin modes
247
247
  and transitions included, has a Learn button; **export** saves the
248
248
  keymap as a `.json` file and **import** loads one.
249
+ - **Autopilot** (🤖 in the visualizer's header, or a MIDI pad): the
250
+ visualizer drives itself. It listens for onsets and the running energy,
251
+ holds a mode for a while, drops back to the plain video, then picks a
252
+ fresh mode -- energetic ones when the music is up, calmer ones when it
253
+ isn't -- with a punchy or gentle transition to match the hit, and when
254
+ a track ends with nothing queued it draws the next download by
255
+ lottery, weighted toward the least-played and longest-rested.
249
256
  - **Video swap** (⇄ on the player): another download's picture stands
250
257
  in for the current track's — for an mp3 or a static-image video, so
251
258
  the visuals have real footage. Audio stays with the track; the
252
- borrowed video loops on its own, follows play/pause, and the pairing
253
- is remembered per track.
259
+ borrowed video loops on its own, follows play/pause, has its own seek
260
+ slider in the picker, and the pairing is remembered per track. The
261
+ picker has a search box for big libraries.
254
262
 
255
263
  ### Orbit Visualizer plugins
256
264
 
@@ -264,7 +272,7 @@ mode selector; a registered transition gets a Fade option and a turn in
264
272
  "Random". A plugin that throws is logged once and disabled without
265
273
  taking the draw loop down. `web/orbit_extras.js` (loaded by default) is
266
274
  built entirely on that API and adds Halftone, Lava, Terrain, Rain,
267
- Lissajous, Ripples, Cube, VHS, Win95, Joy Division, Spectrogram, Stained
275
+ Lissajous, Vinyl 33, Cube, VHS, Win95, Joy Division, Spectrogram, Stained
268
276
  glass, Fireworks, Screensaver, Slit-scan, Skyline and Globe, plus the
269
277
  Melt, Dissolve, Iris, Shatter, Wave, Spin, Zoom blur, RGB split, VHS,
270
278
  Win95, Blinds, Flip tiles, CRT off, Droplet, Blur, Slide and Flash
@@ -214,11 +214,19 @@ Zoom retune every mode; every setting persists in the browser.
214
214
  endless encoders are detected on their own. Every row, plugin modes
215
215
  and transitions included, has a Learn button; **export** saves the
216
216
  keymap as a `.json` file and **import** loads one.
217
+ - **Autopilot** (🤖 in the visualizer's header, or a MIDI pad): the
218
+ visualizer drives itself. It listens for onsets and the running energy,
219
+ holds a mode for a while, drops back to the plain video, then picks a
220
+ fresh mode -- energetic ones when the music is up, calmer ones when it
221
+ isn't -- with a punchy or gentle transition to match the hit, and when
222
+ a track ends with nothing queued it draws the next download by
223
+ lottery, weighted toward the least-played and longest-rested.
217
224
  - **Video swap** (⇄ on the player): another download's picture stands
218
225
  in for the current track's — for an mp3 or a static-image video, so
219
226
  the visuals have real footage. Audio stays with the track; the
220
- borrowed video loops on its own, follows play/pause, and the pairing
221
- is remembered per track.
227
+ borrowed video loops on its own, follows play/pause, has its own seek
228
+ slider in the picker, and the pairing is remembered per track. The
229
+ picker has a search box for big libraries.
222
230
 
223
231
  ### Orbit Visualizer plugins
224
232
 
@@ -232,7 +240,7 @@ mode selector; a registered transition gets a Fade option and a turn in
232
240
  "Random". A plugin that throws is logged once and disabled without
233
241
  taking the draw loop down. `web/orbit_extras.js` (loaded by default) is
234
242
  built entirely on that API and adds Halftone, Lava, Terrain, Rain,
235
- Lissajous, Ripples, Cube, VHS, Win95, Joy Division, Spectrogram, Stained
243
+ Lissajous, Vinyl 33, Cube, VHS, Win95, Joy Division, Spectrogram, Stained
236
244
  glass, Fireworks, Screensaver, Slit-scan, Skyline and Globe, plus the
237
245
  Melt, Dissolve, Iris, Shatter, Wave, Spin, Zoom blur, RGB split, VHS,
238
246
  Win95, Blinds, Flip tiles, CRT off, Droplet, Blur, Slide and Flash
@@ -429,15 +429,30 @@ def _manifest_mtime(archive_dir):
429
429
 
430
430
 
431
431
  def _load_hostable_entries(archive_dir, file_name):
432
+ """Every entry that can actually be served: manifest entry, its chunk
433
+ leaves, and the file on disk. Hosting a whole directory skips an
434
+ entry whose file has since been deleted or moved (with a warning on
435
+ stderr) rather than refusing to host anything -- one missing video
436
+ used to poison-pill the other forty-four beside it, and the web UI
437
+ then forgot the host config as unrecoverable. Asking for one file by
438
+ name that isn't there is still an error: that's the one thing the
439
+ caller explicitly wanted."""
432
440
  entries = load_manifest_entries(archive_dir, file_name)
433
441
  entries_by_hash = {}
442
+ kept = []
434
443
  for entry in entries:
435
- leaves = load_leaves(archive_dir, entry['sha256'])
436
444
  file_path = resolve_file_path(entry, archive_dir)
437
445
  if not os.path.exists(file_path):
438
- sys.exit(f"archived file not found on disk at {file_path}")
446
+ if file_name is not None or len(entries) == 1:
447
+ sys.exit(f"archived file not found on disk at {file_path}")
448
+ print(f"[host] skipping {entry.get('name')!r}: archived file not found on disk at {file_path}", file=sys.stderr)
449
+ continue
450
+ leaves = load_leaves(archive_dir, entry['sha256'])
439
451
  entries_by_hash[entry['sha256']] = (entry, leaves, file_path)
440
- return entries, entries_by_hash
452
+ kept.append(entry)
453
+ if not entries_by_hash:
454
+ sys.exit(f"no archived file found in {archive_dir} is still on disk -- nothing to host")
455
+ return kept, entries_by_hash
441
456
 
442
457
 
443
458
  def run_host_server(archive_dir, file_name, port, bind_host='0.0.0.0', quiet=False, price=0,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "weed-cli"
7
- version = "2.5.3"
7
+ version = "2.5.5"
8
8
  description = "Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -79,3 +79,32 @@ def test_a_broken_manifest_mid_session_does_not_take_down_an_already_running_hos
79
79
  out2 = str(tmp_path / 'out2.mp4')
80
80
  node.download(f'127.0.0.1:{port}', out2, content_hash=second['sha256'])
81
81
  assert os.path.getsize(out2) == 6_000
82
+
83
+
84
+ def test_a_missing_file_no_longer_stops_the_rest_of_the_directory_being_hosted(tmp_path):
85
+ """Real report: "archived file not found on disk" for one video that
86
+ had since been deleted refused to host the whole archive_dir. Now the
87
+ missing one is skipped with a warning and everything else is served;
88
+ asking for the missing file by name is still an error, and so is a
89
+ directory where nothing is left."""
90
+ import os, pytest
91
+ archive_dir = str(tmp_path / 'archive')
92
+ keep = make_fake_archive(archive_dir, name='keep.mp4', size=30_000, chunk_size=8_192)
93
+ gone = make_fake_archive(archive_dir, name='gone.mp4', size=20_000, chunk_size=8_192)
94
+ os.remove(os.path.join(archive_dir, 'gone.mp4'))
95
+
96
+ entries, by_hash = node._load_hostable_entries(archive_dir, None)
97
+ assert [e['name'] for e in entries] == ['keep.mp4']
98
+ assert set(by_hash) == {keep['sha256']}
99
+ with pytest.raises(SystemExit, match='not found on disk'):
100
+ node._load_hostable_entries(archive_dir, 'gone.mp4')
101
+
102
+ port = free_port()
103
+ _host_thread(archive_dir, port)
104
+ out = str(tmp_path / 'out.mp4')
105
+ node.download(f'127.0.0.1:{port}', out, content_hash=keep['sha256'])
106
+ assert os.path.getsize(out) == 30_000
107
+
108
+ os.remove(os.path.join(archive_dir, 'keep.mp4'))
109
+ with pytest.raises(SystemExit, match='nothing to host'):
110
+ node._load_hostable_entries(archive_dir, None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weed-cli
3
- Version: 2.5.3
3
+ Version: 2.5.5
4
4
  Summary: Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel
5
5
  License: MIT
6
6
  Keywords: p2p,video,censorship-resistant,discovery,dht,kademlia,nat-traversal
@@ -246,11 +246,19 @@ Zoom retune every mode; every setting persists in the browser.
246
246
  endless encoders are detected on their own. Every row, plugin modes
247
247
  and transitions included, has a Learn button; **export** saves the
248
248
  keymap as a `.json` file and **import** loads one.
249
+ - **Autopilot** (🤖 in the visualizer's header, or a MIDI pad): the
250
+ visualizer drives itself. It listens for onsets and the running energy,
251
+ holds a mode for a while, drops back to the plain video, then picks a
252
+ fresh mode -- energetic ones when the music is up, calmer ones when it
253
+ isn't -- with a punchy or gentle transition to match the hit, and when
254
+ a track ends with nothing queued it draws the next download by
255
+ lottery, weighted toward the least-played and longest-rested.
249
256
  - **Video swap** (⇄ on the player): another download's picture stands
250
257
  in for the current track's — for an mp3 or a static-image video, so
251
258
  the visuals have real footage. Audio stays with the track; the
252
- borrowed video loops on its own, follows play/pause, and the pairing
253
- is remembered per track.
259
+ borrowed video loops on its own, follows play/pause, has its own seek
260
+ slider in the picker, and the pairing is remembered per track. The
261
+ picker has a search box for big libraries.
254
262
 
255
263
  ### Orbit Visualizer plugins
256
264
 
@@ -264,7 +272,7 @@ mode selector; a registered transition gets a Fade option and a turn in
264
272
  "Random". A plugin that throws is logged once and disabled without
265
273
  taking the draw loop down. `web/orbit_extras.js` (loaded by default) is
266
274
  built entirely on that API and adds Halftone, Lava, Terrain, Rain,
267
- Lissajous, Ripples, Cube, VHS, Win95, Joy Division, Spectrogram, Stained
275
+ Lissajous, Vinyl 33, Cube, VHS, Win95, Joy Division, Spectrogram, Stained
268
276
  glass, Fireworks, Screensaver, Slit-scan, Skyline and Globe, plus the
269
277
  Melt, Dissolve, Iris, Shatter, Wave, Spin, Zoom blur, RGB split, VHS,
270
278
  Win95, Blinds, Flip tiles, CRT off, Droplet, Blur, Slide and Flash
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes