spudzy-vid 0.1.0__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.
- spudzy_vid-0.1.0/LICENSE +7 -0
- spudzy_vid-0.1.0/PKG-INFO +60 -0
- spudzy_vid-0.1.0/README.md +46 -0
- spudzy_vid-0.1.0/pyproject.toml +26 -0
- spudzy_vid-0.1.0/setup.cfg +4 -0
- spudzy_vid-0.1.0/src/spudzy_vid/__init__.py +3 -0
- spudzy_vid-0.1.0/src/spudzy_vid/__main__.py +3 -0
- spudzy_vid-0.1.0/src/spudzy_vid/cli.py +42 -0
- spudzy_vid-0.1.0/src/spudzy_vid/runner.py +127 -0
- spudzy_vid-0.1.0/src/spudzy_vid.egg-info/PKG-INFO +60 -0
- spudzy_vid-0.1.0/src/spudzy_vid.egg-info/SOURCES.txt +13 -0
- spudzy_vid-0.1.0/src/spudzy_vid.egg-info/dependency_links.txt +1 -0
- spudzy_vid-0.1.0/src/spudzy_vid.egg-info/entry_points.txt +2 -0
- spudzy_vid-0.1.0/src/spudzy_vid.egg-info/requires.txt +1 -0
- spudzy_vid-0.1.0/src/spudzy_vid.egg-info/top_level.txt +1 -0
spudzy_vid-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spudzy-vid
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python wrapper for the browser-only Spudzy Vid procedural prompt-to-video generator.
|
|
5
|
+
Author: Spudzy Vid Package Author
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js
|
|
8
|
+
Keywords: video,canvas,mediarecorder,prompt-to-video,playwright
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: playwright>=1.45
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# spudzy-vid
|
|
16
|
+
|
|
17
|
+
Python wrapper for **Spudzy Vid / RealLifeVideo**.
|
|
18
|
+
|
|
19
|
+
It loads this browser-only JavaScript file:
|
|
20
|
+
|
|
21
|
+
`https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js`
|
|
22
|
+
|
|
23
|
+
Because the JavaScript uses browser APIs like `Canvas`, `canvas.captureStream`, and `MediaRecorder`, the wrapper runs it inside Chromium with Playwright, then returns the video data to Python and can save a `.webm` file.
|
|
24
|
+
|
|
25
|
+
## Install locally
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m pip install -e .
|
|
29
|
+
python -m playwright install chromium
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Python usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from spudzy_vid import generate
|
|
36
|
+
|
|
37
|
+
result = generate(
|
|
38
|
+
"make a dragon fly in the rain in an rpg game with the effect fire",
|
|
39
|
+
output="dragon.webm",
|
|
40
|
+
seconds=6,
|
|
41
|
+
width=960,
|
|
42
|
+
height=540,
|
|
43
|
+
fps=30,
|
|
44
|
+
)
|
|
45
|
+
print(result["ok"], result["correctedPrompt"], result["output"])
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## CLI usage
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
spudzy-vid "recreate this futuristic UI being used in a video" -o ui.webm --seconds 6
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Build and publish
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python -m pip install -U build twine
|
|
58
|
+
python -m build
|
|
59
|
+
python -m twine upload dist/*
|
|
60
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# spudzy-vid
|
|
2
|
+
|
|
3
|
+
Python wrapper for **Spudzy Vid / RealLifeVideo**.
|
|
4
|
+
|
|
5
|
+
It loads this browser-only JavaScript file:
|
|
6
|
+
|
|
7
|
+
`https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js`
|
|
8
|
+
|
|
9
|
+
Because the JavaScript uses browser APIs like `Canvas`, `canvas.captureStream`, and `MediaRecorder`, the wrapper runs it inside Chromium with Playwright, then returns the video data to Python and can save a `.webm` file.
|
|
10
|
+
|
|
11
|
+
## Install locally
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python -m pip install -e .
|
|
15
|
+
python -m playwright install chromium
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Python usage
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from spudzy_vid import generate
|
|
22
|
+
|
|
23
|
+
result = generate(
|
|
24
|
+
"make a dragon fly in the rain in an rpg game with the effect fire",
|
|
25
|
+
output="dragon.webm",
|
|
26
|
+
seconds=6,
|
|
27
|
+
width=960,
|
|
28
|
+
height=540,
|
|
29
|
+
fps=30,
|
|
30
|
+
)
|
|
31
|
+
print(result["ok"], result["correctedPrompt"], result["output"])
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## CLI usage
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
spudzy-vid "recreate this futuristic UI being used in a video" -o ui.webm --seconds 6
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Build and publish
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
python -m pip install -U build twine
|
|
44
|
+
python -m build
|
|
45
|
+
python -m twine upload dist/*
|
|
46
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spudzy-vid"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python wrapper for the browser-only Spudzy Vid procedural prompt-to-video generator."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Spudzy Vid Package Author" }]
|
|
13
|
+
dependencies = ["playwright>=1.45"]
|
|
14
|
+
keywords = ["video", "canvas", "mediarecorder", "prompt-to-video", "playwright"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js"
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
spudzy-vid = "spudzy_vid.cli:main"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools]
|
|
23
|
+
package-dir = {"" = "src"}
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
from .runner import JS_URL, SpudzyVidError, generate, generate_async, parse_prompt, parse_prompt_async, correct_prompt, correct_prompt_async
|
|
2
|
+
|
|
3
|
+
__all__ = ["JS_URL", "SpudzyVidError", "generate", "generate_async", "parse_prompt", "parse_prompt_async", "correct_prompt", "correct_prompt_async"]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from .runner import SpudzyVidError, generate
|
|
7
|
+
|
|
8
|
+
def main(argv: list[str] | None = None) -> int:
|
|
9
|
+
parser = argparse.ArgumentParser(description="Generate Spudzy Vid videos from Python.")
|
|
10
|
+
parser.add_argument("prompt")
|
|
11
|
+
parser.add_argument("-o", "--output", default="spudzy_vid_output.webm")
|
|
12
|
+
parser.add_argument("--width", type=int, default=960)
|
|
13
|
+
parser.add_argument("--height", type=int, default=540)
|
|
14
|
+
parser.add_argument("--fps", type=int, default=30)
|
|
15
|
+
parser.add_argument("--seconds", type=float, default=6)
|
|
16
|
+
parser.add_argument("--bitrate", type=int, default=6000000)
|
|
17
|
+
parser.add_argument("--seed", type=int, default=None)
|
|
18
|
+
parser.add_argument("--return-frames", action="store_true")
|
|
19
|
+
parser.add_argument("--show-browser", action="store_true")
|
|
20
|
+
parser.add_argument("--json", action="store_true")
|
|
21
|
+
args = parser.parse_args(argv)
|
|
22
|
+
try:
|
|
23
|
+
result = generate(args.prompt, output=args.output, width=args.width, height=args.height, fps=args.fps, seconds=args.seconds, bitrate=args.bitrate, seed=args.seed, returnFrames=args.return_frames, headless=not args.show_browser)
|
|
24
|
+
except SpudzyVidError as exc:
|
|
25
|
+
print(f"spudzy-vid error: {exc}", file=sys.stderr)
|
|
26
|
+
return 1
|
|
27
|
+
if args.json:
|
|
28
|
+
printable = dict(result)
|
|
29
|
+
if printable.get("videoBase64"):
|
|
30
|
+
printable["videoBase64"] = f"<base64 omitted: {len(result['videoBase64'])} chars>"
|
|
31
|
+
print(json.dumps(printable, indent=2))
|
|
32
|
+
else:
|
|
33
|
+
print(f"ok: {result.get('ok')}")
|
|
34
|
+
print(f"corrected prompt: {result.get('correctedPrompt')}")
|
|
35
|
+
print(f"mime type: {result.get('mimeType')}")
|
|
36
|
+
print(f"saved: {result.get('output')}")
|
|
37
|
+
if result.get("reason"):
|
|
38
|
+
print(f"reason: {result.get('reason')}")
|
|
39
|
+
return 0
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import base64
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Dict, Optional
|
|
8
|
+
|
|
9
|
+
JS_URL = "https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js"
|
|
10
|
+
|
|
11
|
+
class SpudzyVidError(RuntimeError):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
def _clean_options(options: Dict[str, Any]) -> Dict[str, Any]:
|
|
15
|
+
blocked = {"output", "headless", "timeout", "js_url"}
|
|
16
|
+
clean: Dict[str, Any] = {}
|
|
17
|
+
for key, value in options.items():
|
|
18
|
+
if key in blocked or value is None:
|
|
19
|
+
continue
|
|
20
|
+
try:
|
|
21
|
+
json.dumps(value)
|
|
22
|
+
except TypeError:
|
|
23
|
+
continue
|
|
24
|
+
clean[key] = value
|
|
25
|
+
return clean
|
|
26
|
+
|
|
27
|
+
async def _run_js_function(function_name: str, prompt: str, options: Dict[str, Any]) -> Any:
|
|
28
|
+
try:
|
|
29
|
+
from playwright.async_api import async_playwright
|
|
30
|
+
except Exception as exc:
|
|
31
|
+
raise SpudzyVidError("Playwright is required. Run: python -m pip install playwright; then: python -m playwright install chromium") from exc
|
|
32
|
+
|
|
33
|
+
headless = bool(options.pop("headless", True))
|
|
34
|
+
timeout = int(options.pop("timeout", 120_000))
|
|
35
|
+
js_url = str(options.pop("js_url", JS_URL))
|
|
36
|
+
browser_options = _clean_options(options)
|
|
37
|
+
html = "<!doctype html><html><head><meta charset='utf-8'></head><body></body></html>"
|
|
38
|
+
|
|
39
|
+
async with async_playwright() as pw:
|
|
40
|
+
browser = await pw.chromium.launch(headless=headless)
|
|
41
|
+
page = await browser.new_page()
|
|
42
|
+
page.set_default_timeout(timeout)
|
|
43
|
+
try:
|
|
44
|
+
await page.set_content(html, wait_until="domcontentloaded")
|
|
45
|
+
await page.add_script_tag(url=js_url)
|
|
46
|
+
await page.wait_for_function("() => !!window.RealLifeVideo", timeout=timeout)
|
|
47
|
+
|
|
48
|
+
if function_name == "generate":
|
|
49
|
+
return await page.evaluate("""
|
|
50
|
+
async ({ prompt, options }) => {
|
|
51
|
+
const data = await window.RealLifeVideo.generate(prompt, options);
|
|
52
|
+
let videoBase64 = null;
|
|
53
|
+
let videoSize = 0;
|
|
54
|
+
if (data.blob) {
|
|
55
|
+
const arrayBuffer = await data.blob.arrayBuffer();
|
|
56
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
57
|
+
let binary = "";
|
|
58
|
+
const chunk = 0x8000;
|
|
59
|
+
for (let i = 0; i < bytes.length; i += chunk) {
|
|
60
|
+
binary += String.fromCharCode.apply(null, bytes.subarray(i, i + chunk));
|
|
61
|
+
}
|
|
62
|
+
videoBase64 = btoa(binary);
|
|
63
|
+
videoSize = data.blob.size || bytes.length;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
ok: data.ok,
|
|
67
|
+
reason: data.reason || null,
|
|
68
|
+
originalPrompt: data.originalPrompt,
|
|
69
|
+
correctedPrompt: data.correctedPrompt,
|
|
70
|
+
parsed: data.parsed,
|
|
71
|
+
width: data.width,
|
|
72
|
+
height: data.height,
|
|
73
|
+
fps: data.fps,
|
|
74
|
+
seconds: data.seconds,
|
|
75
|
+
frameCount: data.frameCount,
|
|
76
|
+
mimeType: data.mimeType,
|
|
77
|
+
videoBase64,
|
|
78
|
+
videoSize,
|
|
79
|
+
framePreviewCount: data.frames ? data.frames.length : 0,
|
|
80
|
+
frames: data.frames || []
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
""", {"prompt": prompt, "options": browser_options})
|
|
84
|
+
|
|
85
|
+
if function_name == "parsePrompt":
|
|
86
|
+
return await page.evaluate("({ prompt, options }) => window.RealLifeVideo.parsePrompt(prompt, options)", {"prompt": prompt, "options": browser_options})
|
|
87
|
+
if function_name == "correctPrompt":
|
|
88
|
+
return await page.evaluate("({ prompt, options }) => window.RealLifeVideo.correctPrompt(prompt, options)", {"prompt": prompt, "options": browser_options})
|
|
89
|
+
raise SpudzyVidError(f"Unknown JS function: {function_name}")
|
|
90
|
+
finally:
|
|
91
|
+
await browser.close()
|
|
92
|
+
|
|
93
|
+
async def generate_async(prompt: str, output: Optional[str | Path] = None, **options: Any) -> Dict[str, Any]:
|
|
94
|
+
result = await _run_js_function("generate", prompt, dict(options))
|
|
95
|
+
if output and result.get("videoBase64"):
|
|
96
|
+
out = Path(output)
|
|
97
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
out.write_bytes(base64.b64decode(result["videoBase64"]))
|
|
99
|
+
result["output"] = str(out)
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
def generate(prompt: str, output: Optional[str | Path] = None, **options: Any) -> Dict[str, Any]:
|
|
103
|
+
try:
|
|
104
|
+
asyncio.get_running_loop()
|
|
105
|
+
except RuntimeError:
|
|
106
|
+
return asyncio.run(generate_async(prompt, output=output, **options))
|
|
107
|
+
raise SpudzyVidError("generate() cannot run inside an active event loop. Use await generate_async(...).")
|
|
108
|
+
|
|
109
|
+
async def parse_prompt_async(prompt: str, **options: Any) -> Dict[str, Any]:
|
|
110
|
+
return await _run_js_function("parsePrompt", prompt, dict(options))
|
|
111
|
+
|
|
112
|
+
def parse_prompt(prompt: str, **options: Any) -> Dict[str, Any]:
|
|
113
|
+
try:
|
|
114
|
+
asyncio.get_running_loop()
|
|
115
|
+
except RuntimeError:
|
|
116
|
+
return asyncio.run(parse_prompt_async(prompt, **options))
|
|
117
|
+
raise SpudzyVidError("parse_prompt() cannot run inside an active event loop. Use await parse_prompt_async(...).")
|
|
118
|
+
|
|
119
|
+
async def correct_prompt_async(prompt: str, **options: Any) -> str:
|
|
120
|
+
return await _run_js_function("correctPrompt", prompt, dict(options))
|
|
121
|
+
|
|
122
|
+
def correct_prompt(prompt: str, **options: Any) -> str:
|
|
123
|
+
try:
|
|
124
|
+
asyncio.get_running_loop()
|
|
125
|
+
except RuntimeError:
|
|
126
|
+
return asyncio.run(correct_prompt_async(prompt, **options))
|
|
127
|
+
raise SpudzyVidError("correct_prompt() cannot run inside an active event loop. Use await correct_prompt_async(...).")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spudzy-vid
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python wrapper for the browser-only Spudzy Vid procedural prompt-to-video generator.
|
|
5
|
+
Author: Spudzy Vid Package Author
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js
|
|
8
|
+
Keywords: video,canvas,mediarecorder,prompt-to-video,playwright
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: playwright>=1.45
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# spudzy-vid
|
|
16
|
+
|
|
17
|
+
Python wrapper for **Spudzy Vid / RealLifeVideo**.
|
|
18
|
+
|
|
19
|
+
It loads this browser-only JavaScript file:
|
|
20
|
+
|
|
21
|
+
`https://alaricholt677.github.io/PKGS/spudzy-vid/spudzy-vid-js.js`
|
|
22
|
+
|
|
23
|
+
Because the JavaScript uses browser APIs like `Canvas`, `canvas.captureStream`, and `MediaRecorder`, the wrapper runs it inside Chromium with Playwright, then returns the video data to Python and can save a `.webm` file.
|
|
24
|
+
|
|
25
|
+
## Install locally
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m pip install -e .
|
|
29
|
+
python -m playwright install chromium
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Python usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from spudzy_vid import generate
|
|
36
|
+
|
|
37
|
+
result = generate(
|
|
38
|
+
"make a dragon fly in the rain in an rpg game with the effect fire",
|
|
39
|
+
output="dragon.webm",
|
|
40
|
+
seconds=6,
|
|
41
|
+
width=960,
|
|
42
|
+
height=540,
|
|
43
|
+
fps=30,
|
|
44
|
+
)
|
|
45
|
+
print(result["ok"], result["correctedPrompt"], result["output"])
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## CLI usage
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
spudzy-vid "recreate this futuristic UI being used in a video" -o ui.webm --seconds 6
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Build and publish
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python -m pip install -U build twine
|
|
58
|
+
python -m build
|
|
59
|
+
python -m twine upload dist/*
|
|
60
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/spudzy_vid/__init__.py
|
|
5
|
+
src/spudzy_vid/__main__.py
|
|
6
|
+
src/spudzy_vid/cli.py
|
|
7
|
+
src/spudzy_vid/runner.py
|
|
8
|
+
src/spudzy_vid.egg-info/PKG-INFO
|
|
9
|
+
src/spudzy_vid.egg-info/SOURCES.txt
|
|
10
|
+
src/spudzy_vid.egg-info/dependency_links.txt
|
|
11
|
+
src/spudzy_vid.egg-info/entry_points.txt
|
|
12
|
+
src/spudzy_vid.egg-info/requires.txt
|
|
13
|
+
src/spudzy_vid.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
playwright>=1.45
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
spudzy_vid
|