diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index cc7483a..acef728 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -49,6 +49,8 @@ jobs: run: | if [ "$RUNNER_OS" == "Windows" ]; then SEP=";"; else SEP=":"; fi pyinstaller --onefile \ + --hidden-import pkg_resources \ + --hidden-import setuptools \ --collect-all onionshare_cli \ --collect-all flask_socketio \ --collect-all engineio \ diff --git a/UPCOMING_RELEASE.md b/UPCOMING_RELEASE.md index fad3bb0..8f1952d 100644 --- a/UPCOMING_RELEASE.md +++ b/UPCOMING_RELEASE.md @@ -1,8 +1,11 @@ -# VoxVera v0.2.4 +# VoxVera v0.2.11 -## New Features -- **Optional File Attachment:** Users can now attach a file (e.g., a .torrent, image, or document) to their flyers. This file is packaged into the Tor-hosted site and made available via a "Download Attachment" button on the landing page. -- **Interactive Attachment Selection:** Added a prompt during `voxvera init` to easily specify the path to an attachment. +## Changes and Improvements -## Localization -- Added new tokens for attachment handling across all 14+ supported languages. +### Logic and UI Fixes +- **Attachment overriding URL:** Modified the core HTML template and config generation so that a provided file attachment fully replaces the external URL in the main content area and QR codes, eliminating redundancy. The "Download Attachment" button at the bottom was removed, keeping the main interface clean and focusing on the attachment directly via the primary URL slot. +- **Interactive Prompt:** The interactive CLI now treats the URL and attachment path as an "either/or" choice conditionally, improving clarity. + +### Stability and Bug Fixes +- **Nano Terminal Crash:** Fixed an issue where the `nano` editor would crash with "Code: 11" when launched from the interactive interface within a PyInstaller binary. The application now properly inherits standard input/output streams for standard terminal editors. +- **ModuleNotFoundError Fix:** Added explicit `pkg_resources` and `setuptools` hidden imports to the PyInstaller build configuration, permanently fixing an error where `onionshare-cli` would fail to initialize in the standalone binary with a `ModuleNotFoundError: No module named 'pkg_resources'`. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index bc77be8..59ae224 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ voxvera = ["templates/**", "src/**", "resources/**", "locales/**", "resources/bi [project] name = "voxvera" -version = "0.2.10" +version = "0.2.11" description = "VoxVera CLI utilities" readme = "README.md" authors = [{name = "VoxVera"}] diff --git a/voxvera/__init__.py b/voxvera/__init__.py index f80336e..115e1e8 100644 --- a/voxvera/__init__.py +++ b/voxvera/__init__.py @@ -1,7 +1,7 @@ import sys from pathlib import Path -__version__ = "0.2.10" +__version__ = "0.2.11" # Add the vendor directory to sys.path. We prepend it to ensure our bundled # dependencies take priority over potentially incompatible system packages diff --git a/voxvera/cli.py b/voxvera/cli.py index a99953d..cfaffe3 100644 --- a/voxvera/cli.py +++ b/voxvera/cli.py @@ -180,7 +180,7 @@ def _open_editor_terminal(initial: str) -> str: try: with os.fdopen(fd, "w", encoding="utf-8") as fh: fh.write(initial or "") - subprocess.call([editor, path]) + subprocess.run([editor, path], stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr) with open(path, "r", encoding="utf-8") as fh: return fh.read() except Exception as e: @@ -375,11 +375,18 @@ def interactive_update(config_path: str): console.rule(t("cli.init_links")) link_qs = [ + { + "type": "input", + "message": t("cli.attachment_path_label"), + "name": "attachment_path", + "default": data.get("attachment_path", ""), + }, { "type": "input", "message": t("cli.url_label"), "name": "url", - "default": data.get("url", "https://voxvera.org/"), + "default": data.get("url", "https://voxvera.org/") if not data.get("url", "").startswith("download/") else "", + "when": lambda result: not result.get("attachment_path", "").strip(), "transformer": _len_transform(200), "validate": _len_validator(200), }, @@ -391,21 +398,6 @@ def interactive_update(config_path: str): "transformer": _len_transform(120), "validate": _len_validator(120), }, - - { - "type": "input", - "message": t("cli.binary_message_label"), - "name": "binary_message", - "default": data.get("binary_message", ""), - "transformer": _len_transform(120), - "validate": _len_validator(120), - }, - { - "type": "input", - "message": t("cli.attachment_path_label"), - "name": "attachment_path", - "default": data.get("attachment_path", ""), - }, ] data.update(prompt(link_qs)) @@ -542,18 +534,19 @@ def build_assets( val_str = re.sub(r"~~(.*?)~~", r'\1', val_str) html = html.replace(f"{{{{{key}}}}}", val_str) - # Handle optional file attachment + # Handle optional file attachment logic attachment_path = data.get("attachment_path") - attachment_url = "" - attachment_display = "none" if attachment_path and os.path.isfile(attachment_path): att_filename = os.path.basename(attachment_path) - attachment_url = f"download/{att_filename}" - attachment_display = "inline-block" - - html = html.replace("{{attachment_url}}", attachment_url) - html = html.replace("{{attachment_display}}", attachment_display) - + # We don't replace the URL here if it's already an onion link (e.g. during serve rebuild) + if not data.get("url", "").startswith("http://") or ".onion" not in data.get("url", ""): + data["url"] = f"download/{att_filename}" + # Must write back to config so generate_qr uses the new URL + save_config(data, config_path) + + # Also update the HTML we just replaced if we changed it + html = html.replace("{{url}}", data["url"]) + folder_name = data["folder_name"] dest = DATA_DIR / "host" / folder_name os.makedirs(dest, exist_ok=True) diff --git a/voxvera/src/index-master.html b/voxvera/src/index-master.html index 447a473..a86ac6b 100644 --- a/voxvera/src/index-master.html +++ b/voxvera/src/index-master.html @@ -579,9 +579,6 @@ - - -