Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ body:
id: version
attributes:
label: Versión de FlowMobile
placeholder: 7.6.0
placeholder: "Ejecuta: flow --version"
validations:
required: true
- type: dropdown
Expand All @@ -17,6 +17,9 @@ body:
options:
- iOS / a-Shell
- Android / Termux
- Windows 10/11
- Linux / Bash
- Linux / Zsh
validations:
required: true
- type: textarea
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
matrix:
python-version: ["3.10", "3.12", "3.13"]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ matrix.python-version }}
Expand All @@ -33,7 +33,7 @@ jobs:
name: Instaladores y publicación
runs-on: windows-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.13"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: site
- id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.13"
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/smoke-installers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Prueba real de instaladores

on:
schedule:
- cron: "17 6 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
linux:
name: Instalación real · Linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Instalar desde el release estable
shell: bash
env:
FLOWMOBILE_HOME: ${{ runner.temp }}/flowmobile-linux
FLOWMOBILE_DOWNLOADS: ${{ runner.temp }}/downloads
FLOWMOBILE_INSTALL_LOG: ${{ runner.temp }}/flowmobile-linux.log
FLOWMOBILE_BIN: ${{ runner.temp }}/bin
run: |
bash install-linux.sh tacosandtypescript-debug/FlowMobile
"${FLOWMOBILE_BIN}/flow" --health-check
"${FLOWMOBILE_BIN}/flow" --version

windows:
name: Instalación real · Windows
runs-on: windows-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Instalar desde el release estable
shell: powershell
run: |
$env:FLOWMOBILE_HOME = Join-Path $env:RUNNER_TEMP "flowmobile-windows"
$env:FLOWMOBILE_DOWNLOADS = Join-Path $env:RUNNER_TEMP "downloads"
$env:FLOWMOBILE_INSTALL_LOG = Join-Path $env:RUNNER_TEMP "flowmobile-windows.log"
.\install-windows.ps1 -Repository tacosandtypescript-debug/FlowMobile -Auto
$launcher = Join-Path $env:LOCALAPPDATA "FlowMobileBin\flow.cmd"
& $launcher --health-check
& $launcher --version
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Historial de versiones

## 8.0.4 — 2026-07-21

- Avisos de nueva versión persistentes y separados de la caché de comprobación.
- yt-dlp solo se ofrece cuando la versión está verificada en `requirements.lock`.
- ACL privadas en Windows para cookies, ajustes, historial, colas e informes.
- Pruebas semanales de instalación real en Windows y Linux.
- Formulario de errores actualizado para iOS, Android, Windows y Linux.

## 8.0.3 — 2026-07-17

- El enlace Linux activa `~/.local/bin` directamente en la terminal actual.
Expand Down
9 changes: 6 additions & 3 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ git config user.name "tacosandtypescript-debug"
git config user.email "tacosandtypescript-debug@users.noreply.github.com"
git add .
git status
git commit -m "Publicar FlowMobile 8.0.3"
git commit -m "Publicar FlowMobile 8.0.4"
git remote add origin https://github.com/tacosandtypescript-debug/FlowMobile.git
git push -u origin main
```
Expand Down Expand Up @@ -78,11 +78,14 @@ primero la prueba completa en Termux y después repítela en a-Shell.

## Crear una versión estable

Antes de crear la etiqueta, completa `docs/DEVICE_TESTING.md` y confirma que
la acción **Prueba real de instaladores** terminó correctamente en Windows y Linux.

Cuando `main` esté verde y la matriz de `docs/DEVICE_TESTING.md` esté completa:

```powershell
git tag -a v8.0.3 -m "FlowMobile 8.0.3"
git push origin v8.0.3
git tag -a v8.0.4 -m "FlowMobile 8.0.4"
git push origin v8.0.4
```

La acción `Release` comprueba que la etiqueta coincida con `VERSION`, ejecuta
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Descarga vídeos o extrae audio desde **iOS, Android, Windows y Linux**.
El comando para abrir la aplicación es `flow`.

Versión actual: **8.0.3**.
Versión actual: **8.0.4**.

[![CI](https://github.com/tacosandtypescript-debug/FlowMobile/actions/workflows/ci.yml/badge.svg)](https://github.com/tacosandtypescript-debug/FlowMobile/actions/workflows/ci.yml)
[![Última versión](https://img.shields.io/github/v/release/tacosandtypescript-debug/FlowMobile?label=versión&color=7c3aed)](https://github.com/tacosandtypescript-debug/FlowMobile/releases/latest)
Expand Down
3 changes: 3 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ Solo la versión estable más reciente recibe correcciones de seguridad.
- Las dependencias Python se instalan desde `requirements.lock` con hashes.
- Las cookies se guardan localmente con permisos privados y nunca se incluyen
en el diagnóstico.
- Windows aplica ACL del usuario actual a cookies, ajustes, historial, colas e
informes; los sistemas POSIX usan permisos `600` y directorios `700`.
- El registro de instalación se reemplaza en cada intento, usa permisos
privados y no contiene cookies ni historial de descargas.
- Los paquetes publicados incluyen una atestación de procedencia de GitHub.
- Dependabot revisa semanalmente Python y GitHub Actions; CodeQL analiza el
código y la rama principal exige verificaciones antes de integrar cambios.
- Una prueba semanal instala el release estable desde cero en Windows y Linux.

El Centro de seguridad está en **Herramientas → Centro de seguridad**. Si la
integridad falla, no introduzcas cookies ni ejecutes actualizaciones: reinstala
Expand Down
29 changes: 15 additions & 14 deletions SECURITY_MANIFEST.sha256
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
bc65ac1f04d1daf95e2becdff1187d00e62afd1cc56e83c23256b8e93c03bb97 bootstrap_ios.py
bef7b364e5d12f33b5a62421241c0b74e37f621dce414bb6f2702e63615959d4 flow/__init__.py
5dae8ab0908dd4ef0529c339fc60fab93cbd3626cde545dbb6a45c13097d416e flow/__init__.py
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 flow/application/__init__.py
7b4d5de99e6b1a966cccd68f70a10ce0ccf6dab05583314727c04d37ca495a22 flow/application/media_service.py
772037ea16035984dc84756eef3a0a973508c7c136948db4a565a2835a890348 flow/application/real_tests.py
16c46681e9d59b84a59a19442d12892d146cb21ecb5acc7faa25bce7f5348379 flow/application/real_tests.py
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 flow/domain/__init__.py
e3776c5ee20ed20936187b527b6188851dc34129a73f003ade0260b49373cb84 flow/domain/cancellation.py
90be10bcae6036a21bc4c028c54a53cf921b32ff48e640a93b6300b81e87d120 flow/domain/errors.py
Expand All @@ -12,29 +12,30 @@ ad81f8b337eb6f777a4dd142c97e95b7ad365c6f0c0106067a018b0cf897725b flow/domain/mo
3dca4284d4456795cd894c239064d1fbad03be510f1991da9839dc4d19e81d13 flow/domain/sites.py
5dd3e1d6739e6b037c9affe81843ed03ebde5cad9a218ed40dab367eb24a4a7a flow/domain/urls.py
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 flow/infrastructure/__init__.py
6f1165ab8793b0f2452df78a4e4593393b9ea4a90fe19d857e775257e04485e1 flow/infrastructure/batches.py
8666a2a85c55b22c1d5238af4152025f9f415230b722c30b256e3ff0e01a1674 flow/infrastructure/batches.py
b859f19f74df5605e664825fafdcf0df38ff5fc0f39debef9714deaf06eb4530 flow/infrastructure/clipboard.py
9c283ca9b9dcedfe241fdd45e4880d7713d0766141aa2b9aab9cc21a168b914f flow/infrastructure/device.py
1b0a00f288bdb2fc4a6dfbfb6396a2f349d0b08b672092ce16459681ad106901 flow/infrastructure/diagnostics.py
0de44e7db16bc34633159f133a8764ec59104652cb216088917eb9cd2f069265 flow/infrastructure/diagnostics.py
e3683f7d87e118f717999d899950a30152f84dda68b1ffd9da00c5e54bd86537 flow/infrastructure/feedback.py
a709587a39ba77b1eb2b7c2b60a654ac7ae4613b1202168614e98be461ca5d6f flow/infrastructure/ffmpeg.py
3e5e4ed63691a1763372510ee98ed70c3e23839b6d7947967fe5c8ecf1cd7e93 flow/infrastructure/history.py
da574b72e65b095037edb993913f1cec2f515c0056028a57c5421a41520b87f0 flow/infrastructure/history.py
79ef911c2a159c5d1448149b4c9d3117ba46ff3ea70d0eb2f57ba9ffc85e96f7 flow/infrastructure/ios.py
cb0a952ef09f571c470580fe153cee770e29a56f566fcc9967a464ba2f8c6d33 flow/infrastructure/paths.py
b066e3fe18507502a82c01be3e710926387bed3da10ed934db504fc970e8b308 flow/infrastructure/paths.py
26f61a969ed032dc2495b618d94ea21dda983bf192148a686359dcc1a80d5846 flow/infrastructure/platform.py
d7f753c875f5ab077debd708708787dacbaf968eed54027de6d2f91bbe6fb0c2 flow/infrastructure/privacy.py
1b1d9280ef8a29c7d583e6d60e941f7ea991e0c603af1662c0469e9bde2871d6 flow/infrastructure/repair.py
7de1f33dc26d4ba4d7e400f41e172048848aba45ae4c6188e21a4538db6d3c3a flow/infrastructure/resume.py
4ca958d586f19a4cb3084a1e316b5ce0b91357976fdeeb7c9f784ca2ece1df65 flow/infrastructure/security.py
d327f560cd2a5f553033976fccc87f2a20b277332f252d012950a07c0d56f85a flow/infrastructure/sessions.py
12c69228233f54ef283dc02b2a0b8f2860aea5e21e85cea19380f2f82a8aa6d0 flow/infrastructure/settings.py
0ec4f8595ddccaa8375bc13363712cc46b2f9278a59f46b87fbbbeace4d65ccd flow/infrastructure/resume.py
be276fef4070467a9d347eba322c104585a516d0c8e8c80b3cb0f6b39f5cdb86 flow/infrastructure/security.py
f1e7e3132df532659ce39eaecfdc13e783f9ad529ec97144f564e1c8b4f317c3 flow/infrastructure/sessions.py
b2d5a084f1276bac16c87769a32c6a7165816ed006e16b9f2e3f4621b6a5276b flow/infrastructure/settings.py
12052b1c424e8ef935d6cc89b54baa55f21603cb29ba7123f7082afbd5ffb1e6 flow/infrastructure/uninstall.py
94b0b59761c0092dcf22995ddff32137754b27bf07d2f01462e04538aec4fa57 flow/infrastructure/updates.py
046f27d2016ac365f452f8df8ec92f72763b7067fc4c6e02faa5c3e10b9aec03 flow/infrastructure/updates.py
7571602c4277ff09cc7e3cbed587bcd81efc67288af2621815f4d05d79e9fe5d flow/infrastructure/ytdlp_gateway.py
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 flow/presentation/__init__.py
26ef88d8759233c053ad13be8842801d12b270f961f2d2bd2cde60ba2556e234 flow/presentation/cli.py
35b0565d22b41aa194ffb430e0d7c0614a4d1839725e82cec5cfb38649977f42 flow/presentation/cli.py
37969356b90b0cacae43cb7a171ecb00468eb9b213535d073aea73e52834aa77 flow/presentation/theme.py
180a06189d1a4a43afadca937699fe71547c688452078a6504df660ce4597cd9 flow/presentation/tools_menu.py
7d8fcf9013e958504982f3e05513444a158598051002815b9a1efd31f14075d1 flow/presentation/update_menu.py
19eaec49c93f8d1b91b90ec50da3149a69820d83e50a45a207afd267a434ab60 flow/presentation/update_menu.py
7fa2c927279ee0debbcfb396fb0b36c1768ac06523b9a5946e59c919dbe276f1 install-ios.sh
195bcb63be402b812748de2c16483a67652bf5e0c8297ddeca7c413b5f66bf36 install-linux.sh
3ce1d78c35c61ec8776256f5241a8a3ac90f6d3a987f458d3a99609dccb69429 install-termux.sh
Expand All @@ -45,7 +46,7 @@ d1f637cbe753fdbc3f6e519ecac22200eb056ff7e57ce44731b3c4615ad76fb9 main.py
9bb72d1814d87534c45ecdea987054b55dc7270885120e64286e80a9494e89ba requirements.lock
2b614b7c952c5de70d2a4ee93926d1f8d439871cc68182f250cb33e63415633f requirements.txt
dea06592b4edf0288e64c3b47eec7f827b223986bca39a046f6935b1a29c4bd9 scripts/check-device.sh
3d7339564a69cc4a000101cdf43fa8cf850fc38262f17d309735c61bc89c33d8 scripts/check-release.ps1
b17f3b91ee6b83b5fc6d724af5dcfcaa7b1e3353fcbaf5c0dd874dfab85321c4 scripts/check-release.ps1
d14bc31dfc5f0a7f145e3de64bed0af5c1c077267887c3c896b9e88733a231f8 scripts/check_device.py
8736555af43c1baa89e12dbafc459bc25dde30a5f940786ab0300ba6d7a1c7d6 scripts/flow
7b897d26e7b8d8ffa339a731bfbe0af5dcfe293958a8272692a61428983a6e42 scripts/flow_ios.py
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.0.3
8.0.4
5 changes: 5 additions & 0 deletions docs/DEVICE_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Esta matriz debe completarse antes de crear una etiqueta estable.

La acción semanal **Prueba real de instaladores** comprueba instalaciones
limpias en Windows y Linux. No sustituye las pruebas de descarga y compartir
en dispositivos físicos, porque los servicios pueden bloquear centros de datos.

## Preparación

- Probar en una instalación limpia de a-Shell en iOS.
Expand All @@ -11,6 +15,7 @@ Esta matriz debe completarse antes de crear una etiqueta estable.
- Ejecutar `python3 scripts/check_device.py` en a-Shell.
- Ejecutar `sh scripts/check-device.sh` en Termux.
- Confirmar que todas las pruebas automatizadas terminan correctamente.
- Confirmar que la última ejecución semanal de instaladores está en verde.

## Matriz obligatoria

Expand Down
2 changes: 1 addition & 1 deletion flow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
APP_NAME = "FlowMobile"
APP_VERSION = "8.0.3"
APP_VERSION = "8.0.4"
5 changes: 4 additions & 1 deletion flow/application/real_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from flow.domain.models import DownloadChoice
from flow.infrastructure.ffmpeg import MediaProbe, probe_media
from flow.infrastructure.paths import STATE_DIR
from flow.infrastructure.privacy import protect_private_path


@dataclass(frozen=True, slots=True)
Expand Down Expand Up @@ -116,9 +117,11 @@ def save_report(rows: list[dict[str, object]]) -> Path:
json.dumps({"created": datetime.now().isoformat(), "results": rows}, ensure_ascii=False, indent=2),
encoding="utf-8",
)
if not protect_private_path(target):
target.unlink(missing_ok=True)
raise OSError("No se pudo proteger el informe de pruebas reales.")
return target


def verification_dict(verification: Verification) -> dict[str, object]:
return asdict(verification)

8 changes: 4 additions & 4 deletions flow/infrastructure/batches.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from flow.domain.models import DownloadChoice
from flow.infrastructure.paths import AUDIO_BATCH_DIR, BATCH_DIR, QUEUE_DIR, VIDEO_BATCH_DIR
from flow.infrastructure.privacy import protect_private_path


@dataclass(slots=True)
Expand Down Expand Up @@ -80,10 +81,9 @@ def save_queue(queue: DownloadQueue) -> None:
"items": [asdict(item) for item in queue.items],
}
temporary.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
try:
temporary.chmod(0o600)
except OSError:
pass
if not protect_private_path(temporary):
temporary.unlink(missing_ok=True)
raise OSError("No se pudo proteger la cola privada.")
os.replace(temporary, target)


Expand Down
4 changes: 4 additions & 0 deletions flow/infrastructure/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from flow.infrastructure.ffmpeg import tools_status
from flow.infrastructure.paths import STATE_DIR, VIDEO_DIR
from flow.infrastructure.platform import PLATFORM
from flow.infrastructure.privacy import protect_private_path
from flow.infrastructure.security import security_status


Expand Down Expand Up @@ -63,4 +64,7 @@ def save_diagnostic_report(directory: Path | None = None) -> Path:
json.dumps(diagnostic_data(), ensure_ascii=False, indent=2),
encoding="utf-8",
)
if not protect_private_path(target):
target.unlink(missing_ok=True)
raise OSError("No se pudo proteger el informe de diagnóstico.")
return target
3 changes: 3 additions & 0 deletions flow/infrastructure/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pathlib import Path
from typing import Any
from .paths import HISTORY_FILE, LEGACY_HISTORY_FILE
from .privacy import protect_private_path


class HistoryError(RuntimeError):
Expand Down Expand Up @@ -51,6 +52,8 @@ def save_history(entry: dict[str, Any]) -> None:
json.dumps(history[:50], ensure_ascii=False, indent=2),
encoding="utf-8",
)
if not protect_private_path(temp):
raise OSError("no se pudieron aplicar permisos privados")
os.replace(temp, HISTORY_FILE)
except OSError as exc:
temp.unlink(missing_ok=True)
Expand Down
6 changes: 2 additions & 4 deletions flow/infrastructure/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
termux_shared_directory,
termux_shared_downloads,
)
from flow.infrastructure.privacy import protect_private_path

BASE_DIR = Path(__file__).resolve().parents[2]
STATE_DIR = BASE_DIR / ".flowmobile"
Expand Down Expand Up @@ -65,7 +66,4 @@ def _prepare_download_dir() -> Path:
for media_directory in (VIDEO_DIR, AUDIO_DIR, BATCH_DIR, VIDEO_BATCH_DIR, AUDIO_BATCH_DIR):
media_directory.mkdir(parents=True, exist_ok=True)
for private_directory in (STATE_DIR, SESSION_DIR, QUEUE_DIR):
try:
private_directory.chmod(0o700)
except OSError:
pass
protect_private_path(private_directory, directory=True)
Loading