Compare commits

...
13 Commits
Author SHA1 Message Date
JesterDev 1f4b37acfd PS5 Directo 1.20.3 2026-10-27 18:51:59 +01:00
JesterDev 80bba19d57 PS5 Directo 1.20.0
Biblioteca, formatos con PS5 Dump Forge, acceso desde el móvil y más novedades
2026-10-26 20:36:45 +01:00
JesterDev 088c46f548 Version 1.19.1 2026-10-24 18:25:06 +02:00
JesterDev b65a3b34dd Delete index.html 2026-10-24 18:21:55 +02:00
JesterDev 3e642e0986 v1.19.0 2026-10-24 14:17:39 +02:00
JesterDev d8113534ea v1.18.3 2026-10-19 19:32:31 +02:00
JesterDev 5128f49f8b Version 1.18.2 2026-10-16 19:36:37 +02:00
JesterDev c8a0466854 Version 1.18.1 2026-10-16 19:11:15 +02:00
JesterDev 3314a0f1b0 Version 1.18.0 2026-10-16 19:06:32 +02:00
JesterDev baa4616faf Version 1.18.0 2026-10-16 18:47:56 +02:00
JesterDev d9c33091ca Version 1.17.0 2026-10-16 16:38:42 +02:00
JesterDev 4fc970e7d8 Version 1.16.0 2026-10-16 15:41:04 +02:00
JesterDev 65911f790d Add files via upload 2026-10-16 14:07:39 +02:00
20 changed files with 9859 additions and 190 deletions

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Publica una version: al subir una etiqueta vX.Y.Z crea la release de GitHub con dos .zip:
# - PS5Directo-X.Y.Z.zip la app (la que usa "Actualizar" dentro del programa)
# - PS5Directo-X.Y.Z-portable-windows.zip la app + Python incluido: descomprimir y abrir, sin instalar nada
name: Publicar version
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Version de app.py
id: v
run: echo "ver=$(grep -oP 'VERSION = "\K[^"]+' app.py)" >> "$GITHUB_OUTPUT"
- name: La etiqueta tiene que coincidir con la version
if: startsWith(github.ref, 'refs/tags/')
run: test "${GITHUB_REF_NAME#v}" = "${{ steps.v.outputs.ver }}"
- name: Paquete normal
run: |
mkdir -p dist/PS5Directo
git archive HEAD | tar -x -C dist/PS5Directo
rm -rf dist/PS5Directo/.github
(cd dist && zip -qr "PS5Directo-${{ steps.v.outputs.ver }}.zip" PS5Directo)
- name: Paquete portable (con Python para Windows)
run: |
PY=3.12.10
curl -fsSL -o py.zip "https://www.python.org/ftp/python/$PY/python-$PY-embed-amd64.zip"
mkdir -p dist/PS5Directo/python
unzip -q py.zip -d dist/PS5Directo/python
# que el Python incluido vea la carpeta del programa
for f in dist/PS5Directo/python/python*._pth; do printf '..\n' >> "$f"; done
(cd dist && zip -qr "PS5Directo-${{ steps.v.outputs.ver }}-portable-windows.zip" PS5Directo)
- uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: dist/*.zip
+4
View File
@@ -0,0 +1,4 @@
__pycache__/
*.pyc
.backup/
*.nuevo
+8 -4
View File
@@ -2,11 +2,15 @@
chcp 65001 >nul
title PS5 Directo
cd /d "%~dp0"
where py >nul 2>nul
if %errorlevel%==0 (
py -3 app.py %*
if exist "%~dp0python\python.exe" (
"%~dp0python\python.exe" app.py %*
) else (
python app.py %*
where py >nul 2>nul
if not errorlevel 1 (
py -3 app.py %*
) else (
python app.py %*
)
)
if %errorlevel%==3 exit /b 0
echo.
+365 -6
View File
@@ -1,5 +1,54 @@
PS5 DIRECTO 1.14
================
PS5 DIRECTO 1.20.0
==================
(English: see README_EN.txt)
EMPIEZA AQUÍ (5 MINUTOS)
========================
Lo que necesitas antes:
- Una PS5 con el jailbreak ya hecho. PS5 Directo no hace el jailbreak.
- Un PC con Windows 10 u 11 conectado a la misma red que la PS5.
Paso 1. Descarga
En la página de GitHub del programa, entra en "Releases" y descarga
PS5Directo-X.Y.Z-portable-windows.zip (trae todo, no hay que instalar
nada más). Descomprímelo en una carpeta, por ejemplo en Documentos.
Paso 2. Ábrelo
Doble clic en "PS5 Directo.vbs". Se abre en su propia ventana y crea un
icono en el escritorio para la próxima vez. Si Windows pregunta si quieres
abrir un archivo descargado de internet, pulsa "Abrir".
Paso 3. En la PS5
Carga el jailbreak como siempre y ShadowMountPlus (es lo que hace que lo
que envíes aparezca en el menú). Si tu menú de payloads también carga el
FTP (ftpsrv) y BFpilot, mejor; si no, PS5 Directo te ayuda en el paso 5.
Paso 4. La IP de la PS5
El asistente que sale al abrir te la pide. En la PS5: Ajustes > Red >
Ver estado de la conexión > "Dirección IPv4" (algo como 192.168.1.50).
Paso 5. Comprobar la conexión
El asistente mira si responden el FTP y BFpilot. Si alguno sale en rojo,
pulsa "Cargar" a su lado y se envía solo. (Con Y2JB Autoloader eso no
funciona: cárgalos desde Payload Manager en la PS5 y pulsa "Volver a
comprobar".)
Paso 6. Envía algo
Pega un enlace de descarga directa (o arrastra un archivo de tu PC a la
ventana) y pulsa "Añadir a la cola". Cuando ponga "Listo", ya está en el
menú de la PS5.
¿Algo no va?
Ajustes > "Revisión completa" dice qué falla y cómo arreglarlo. Los dos
puntos de arriba (FTP y BFpilot) en rojo: púlsalos para cargarlos. Puedes
repetir el asistente en Ajustes > "Asistente de primeros pasos".
Aviso: PS5 Directo solo copia archivos. Úsalo con contenido que tengas
derecho a usar (tus copias de seguridad y homebrew). Lo que hagas con él
es responsabilidad tuya.
(Lo de abajo es la guía completa: no hace falta leerla para empezar.)
Pega los enlaces (o arrastra archivos de tu PC) y la herramienta hace todo sola:
@@ -15,6 +64,38 @@ Pega los enlaces (o arrastra archivos de tu PC) y la herramienta hace todo sola:
Mientras una transferencia se descomprime en la PS5, la siguiente de la cola ya se
va enviando.
PESTAÑAS
- Transferencias: la cola de siempre.
- Archivos de la consola: navega por la PS5 como en un explorador. Ves el
tamaño y la fecha de cada archivo (el de las carpetas, con "calcular"),
y puedes crear carpetas, renombrar, copiar o mover (Copiar/Mover y
luego "Pegar aquí" en la carpeta de destino), borrar, bajar al PC
(a Descargas\PS5 Directo), poner permisos 777 y subir archivos o
carpetas tal cual a la carpeta en la que estás.
Clic derecho en un archivo o en el hueco para el menú; atajos: Supr,
F2, Ctrl+C / Ctrl+X / Ctrl+V, Ctrl+A y Retroceso. "Mover a…" y "Copiar
a…" abren un selector de carpetas con los destinos recientes. Si al pegar
ya existe algo con el mismo nombre, eliges reemplazar/combinar, conservar
ambos u omitir. "Extraer…" descomprime en la consola un .rar/.7z/.zip que
ya esté allí. A la izquierda tienes las unidades (con su espacio libre) y
accesos rápidos. Puedes arrastrar archivos del PC a la carpeta abierta.
Sin BFpilot casi todo funciona por FTP (copiar pasa por el PC, más
lento); descomprimir y ver el espacio libre sí necesitan BFpilot.
- Espacio: gráfico de quesitos con lo que ocupa sitio en la consola, con
el nombre de cada aplicación y su tamaño. Avisa de contenido repetido (por
ejemplo la carpeta y su versión convertida a imagen), envíos a medias y
restos, y permite borrarlos desde ahí (pide confirmación). Necesita
BFpilot. Lo instalado desde la propia PS5 se ve pero se borra
desde la consola.
- Actividad: historial de lo que se ha terminado o ha fallado.
CARPETAS DEL PC
Con "Elegir carpeta…" (o arrastrando la carpeta al icono) se manda una
carpeta entera tal cual. Si tiene sce_sys, va a /data/homebrew como
TITLEID-app. Si en la consola ya hay parte (por ejemplo, un envío de otro
programa que se cortó), salta los archivos que ya están iguales y
continúa los que se quedaron a medias.
ALTERNATIVA: DESCOMPRIMIR EN EL PC (7-Zip)
En "Dónde descomprimir" elige "En el PC (7-Zip)" (o ponlo por defecto en
Ajustes). Entonces:
@@ -142,13 +223,290 @@ de quien es la culpa cuando va lento. Tambien hay uno solo PC -> PS5 en
Ajustes.
BIBLIOTECA
----------
La pestaña Biblioteca enseña lo que hay en /data/homebrew (y en los USB) con su
portada, nombre, Title ID, versión, si es carpeta o imagen (.ffpkg, .ffpfsc,
.exfat) y qué firmware pide. Si pones el firmware de tu PS5 en Ajustes
(por ejemplo 13.60), marca en rojo los que no arrancarán. También avisa de
contenido repetido, de DLC/actualizaciones y de carpetas incompletas. Funciona
solo con FTP; con BFpilot además ve cuánto ocupa cada carpeta.
El firmware sale de param.json y, si trae backport (carpeta
fakelib), de lo que piden sus ejecutables. Al terminar cada transferencia
también se comprueba y te avisa si no va a arrancar.
IMÁGENES Y LZ4 (PS5 DUMP FORGE)
-------------------------------
En "Cómo dejarlo en la PS5" la opción por defecto es «Sin convertir»: se deja
tal como viene (un comprimido se descomprime; si ya es una imagen .ffpkg,
.exfat o .ffpfsc, o viene en LZ4, se envía sin tocar). Además puedes elegir:
- Carpeta normal: siempre acaba en carpeta; si es una imagen, un .fpkg o
viene en LZ4, se deshace en el PC.
- Imagen .ffpkg: la que recomienda ShadowMountPlus. Velocidad completa.
- Imagen .exfat o .ffpfs: también las monta ShadowMountPlus.
- Imagen comprimida .ffpfsc: ocupa un 30-60 % menos, pero la consola la lee
más despacio (150-250 MB/s) y algunos títulos pueden dar tirones.
- Paquete .fpkg: se instala como una app de la tienda. Solo firmware 11.60
o inferior (kstuff, fpkg-enable y ppr-patch). Se deja en /data/pkg.
Para .fpkg y .ffpfsc puedes elegir la compresión (rápida, equilibrada,
mínimo tamaño o sin comprimir).
- LZ4 (carpeta o dentro de una .ffpkg): solo títulos AMPR. Experimental: con
algunos títulos se cuelga al guardar partida. Si no es AMPR, se
manda como carpeta o como .ffpkg normal.
Se prepara en el PC con PS5 Dump Forge (github.com/quer3q/ps5-dump-forge, se
descarga solo la primera vez) y se envía un único archivo: va más rápido por
FTP que miles de archivos pequeños y no tiene el problema de permisos. Hace
falta sitio en el PC para la imagen. Las imágenes .ffpkg/.ffpfsc no son
paquetes FPKG: no se instalan, ShadowMountPlus las monta (hasta 13.60 con
ShadowMountPlus 1.7). Los DLC y actualizaciones se mandan como carpeta.
ANTES DE ENVIAR
---------------
- Si ya está en la consola (mismo Title ID), la transferencia se
para y te pregunta: enviar igualmente, reemplazar la copia que hay o
cancelar. Se puede desactivar en Ajustes.
- Si pegas el .sfv / .md5 / .sha1 junto con las partes (o están en la misma
carpeta del PC), cada parte se comprueba mientras se envía. Si una llega
dañada, se borra de la consola y se avisa antes de descomprimir.
- Si falta sitio, el error trae un botón "Hacer sitio": en la pestaña Espacio
te propone qué borrar (restos, copias repetidas, instaladores .pkg) hasta
llegar a lo que necesitas. Nada se borra sin confirmar.
PAYLOADS, DIAGNÓSTICO, MÓVIL Y PROGRAMAR
----------------------------------------
- Pulsa en los puntos FTP / BFpilot (o Ajustes > Cargar payloads) para
mandar ftpsrv o BFpilot a la PS5 por el cargador de ELF (puerto 9021,
etaHEN o elfldr). Se descargan de GitHub y se guardan. El cargador de
Y2JB Autoloader solo acepta la propia consola: con él usa Payload Manager.
- "¿Por qué va lento?" revisa si el PC va por Wi-Fi o cable, la banda y la
señal, cables a 100 Mb/s, VPN, redes distintas y el ping a la PS5, y te
dice qué cambiar.
- El botón del móvil (arriba) enseña un código QR para abrir PS5 Directo
desde el móvil en la misma red: pegar enlaces, ver la cola, pausar, ver
tu biblioteca. Desde el móvil no se pueden instalar actualizaciones ni
cambiar rutas de programas.
- "Programar" (en la cola): empezar a una hora y suspender o apagar el PC
al terminar (avisa y espera 1 minuto). Mientras hay envíos, el PC no se
suspende solo.
VERSIÓN PORTABLE
----------------
En cada versión hay dos descargas: PS5Directo-X.Y.Z.zip (necesita Python
instalado) y PS5Directo-X.Y.Z-portable-windows.zip, que trae Python dentro:
descomprimir y abrir, sin instalar nada.
NOVEDADES 1.20.3
- Biblioteca: «Comprobar» en cada aplicación, para cuando no abre o se
cierra al arrancar. Revisa la carpeta (ejecutable, param.json, permisos,
firmware, backports y el empaquetado LZ4), muestra los registros (.log) y
las capturas de los últimos minutos, explica el código de error que salió
en la tele y guarda un informe .zip. Solo lee: no cambia nada.
- Ventana de bienvenida la primera vez: resume qué es PS5 Directo y qué hace.
- Biblioteca: también lo instalado en la consola (PS4 y PS5), con portada,
versión y firmware, y filtro para verlo.
- Biblioteca, «En tu PC»: eliges carpetas del PC o del NAS, marca lo que ya
está en la consola y lo que no, y lo envías con un clic.
- Biblioteca: «Ver actualizaciones» abre en el navegador la lista pública de
actualizaciones oficiales de cada título (Prospero Patches). Avisa de que
las que piden firmware 14.00 o más no se pueden instalar. El programa no
descarga nada.
- Biblioteca: si tienes PS5 Game Updater en la consola, un botón lo abre; si
su carpeta está mal colocada, lo detecta y la coloca bien.
- Biblioteca: las imágenes y las carpetas sin param.json salen con nombre,
portada y firmware.
- Nueva pestaña «Copia de seguridad»: guarda en el PC las partidas, los
ajustes de ShadowMountPlus y de los payloads y la base de datos de
aplicaciones, a mano o una vez al día. Las partidas se pueden restaurar en
la misma consola (antes guarda las de ahora).
- Nueva pestaña «Capturas»: capturas y vídeos de la consola con miniaturas,
para verlos y bajarlos al PC.
- «Diagnóstico» en las transferencias con error: qué ha pasado, códigos y cómo
arreglarlo, y un informe .zip (sin contraseñas) para pasar a quien te ayude.
En Ajustes, «Crear informe de fallo».
- Torrents: pega un magnet o un .torrent. Se baja primero al PC con aria2 (se
descarga solo) y luego se envía, descomprime o convierte. No comparte al
terminar y lo borra del PC.
- PS5 Dump Forge se actualiza solo (una vez al día como mucho), comprobando
antes que la versión nueva funciona; si no, sigue con la anterior.
- Las versiones nuevas de PS5 Directo se avisan solas con una ventana y sus
novedades.
- Avisa si la velocidad hacia la PS5 cae de golpe (suele ser la consola
inactiva: pulsa un botón del mando).
- «Formato en la PS5» empieza plegado y dice cuánto tarda: sin convertir,
descarga y envío a la vez; convirtiendo, 3 pasos. Tarjetas ordenadas por lo
más usado y «¿Cuál elijo?» por necesidades.
- Firmware de tu PS5 junto al título (se guarda solo) y la tarjeta .fpkg dice
si te vale.
- En la cola, «Convertir a …» dice a qué formato, y avisa si algo no se pudo
convertir.
- Arreglado: un comprimido con versión normal y backport no se convertía;
ahora separa la que toca.
- Arreglado: lo convertido se mezclaba con una carpeta anterior del mismo
nombre.
- Arreglado: muchas carpetas de la Biblioteca salían sin nombre.
NOVEDADES 1.20.1
- Si no conecta y el PC y la PS5 están en redes distintas (por ejemplo
192.168.50.x y 192.168.1.x), lo dice y explica cómo arreglarlo.
- Botones «Usar en el móvil» y «Extensión del navegador» más visibles, y el
asistente de inicio los ofrece al final.
- «Descargar de nuevo» en la cola (terminados, con error o cancelados) y en
Actividad: vuelve a empezar desde cero sin tener que pegar el enlace.
- Si al colocar ya existe esa carpeta, pregunta (colocar igualmente con otro
nombre, reemplazar o cancelar) en vez de dar error.
- Arreglado: si el comprimido trae la versión normal y un «backport», ya no
da «Ya existe»: coloca la normal y aparta el backport (o lo descarta si tu
firmware no lo necesita). Y si en el destino hay un envío anterior a
medias, lo sustituye.
- «Guía de uso» renovada: explica el convertidor de formatos, cada pestaña,
el uso desde el móvil y la extensión del navegador.
- La ventana «¿Cuál elijo?» añade velocidades estimadas donde no había datos
y textos más claros sobre LZ4 y .ffpfsc.
NOVEDADES 1.20.0
- Asistente de primeros pasos (IP, comprobar la conexión y cargar lo que
falta, firmware) y una guía más corta y sencilla.
- Pestaña Biblioteca: lo que hay en la consola con portada, versión, formato y
el firmware que pide; marca los que no arrancan en tu firmware, repetidos,
DLC e incompletos.
- Imágenes .ffpkg / .ffpfsc y LZ4 con PS5 Dump Forge (opcional): se preparan
en el PC y se envía un solo archivo. Se eligen con tarjetas debajo del
destino, con la explicación de cada uno y el espacio que hace falta en el PC;
la primera vez avisa de que convertir ocupa sitio en el PC hasta terminar.
Si lo descargado ya es una imagen, se envía tal cual o se convierte al
formato elegido, y se coloca aunque BFpilot no esté cargado.
- Nuevos formatos: carpeta normal, .exfat, .ffpfs y .fpkg (con compresión
a elegir). Se aceptan carpetas, .zip/.7z/.rar, imágenes, .fpkg y LZ4, y
sin 7-Zip el contenido se saca con PS5 Dump Forge.
- Los formatos van agrupados (primero los que ocupan menos) y el botón
«¿Cuál elijo?» compara ventajas e inconvenientes de cada uno.
- Tiempo que queda (y hora aproximada) al enviar, descomprimir y convertir.
- En el móvil, al terminar o fallar algo sale un aviso grande, vibra y pita
(con la página abierta).
- Biblioteca: marca como LZ4 las carpetas empaquetadas en LZ4 (y filtro LZ4).
- Arreglado: al reanudar un envío preguntaba «Ya está en la consola» por lo
que ese mismo envío había dejado a medias.
- Arreglado: en algunos Chrome de Android la página del móvil salía en
blanco.
- Abrir en el móvil: la página va comprimida (carga antes por Wi-Fi) y la
ventana muestra «Qué le llega del móvil» para saber si llega y si se corta.
- Aviso de firmware: pon el de tu PS5 en Ajustes y te avisa de lo que no
arrancará (tiene en cuenta el backport).
- Si ya está en la consola, pregunta antes de enviarlo (enviar
igualmente, reemplazar o cancelar).
- Comprobación con .sfv / .md5 / .sha1 mientras se envía.
- "Hacer sitio": propone qué borrar cuando falta espacio.
- Cargar ftpsrv y BFpilot en la PS5 desde el programa (puerto 9021).
- "¿Por qué va lento?": diagnóstico de la red del PC.
- Abrir desde el móvil con un código QR.
- Programar la cola, suspender o apagar al terminar, y el PC no se
suspende mientras envía.
- Versión portable con Python incluido.
- Arreglado: solo con FTP (sin BFpilot), ftpsrv devolvía la raíz de la consola
al listar una carpeta; afectaba al explorador y al envío de carpetas.
- Abrir en el móvil: botón para dar permiso en el Firewall de Windows si la
página se queda en blanco.
NOVEDADES 1.19.2
- Arreglado "504 Option not supported" en Archivos de la consola cuando
BFpilot no está cargado: el explorador ya lista las carpetas solo con
ftpsrv (y con servidores FTP que no tienen MLSD).
NOVEDADES 1.19.1
- Arreglado: la cola dejaba de actualizarse sola (desde la 1.18.3), así que
"Quitar" parecía no hacer nada y luego decía "no existe".
- El explorador vuelve a listar la carpeta abierta cuando termina una subida
a esa carpeta.
- Arreglado "Descargar al PC" con aplicaciones: ftpsrv descifraba al vuelo los
eboot.bin/.prx/.sprx y la descarga salía incompleta. Ahora se transfieren
tal cual están (también mejora comparar tamaños al reanudar carpetas).
Gracias a RichyMX por encontrarlo y proponer el arreglo.
NOVEDADES 1.19
- Explorador de archivos renovado: menú de clic derecho, atajos de teclado,
ruta por tramos, unidades y accesos a la izquierda, "Mover a…" / "Copiar
a…" con destinos recientes, aviso al pegar si ya existe (reemplazar,
combinar, conservar ambos u omitir), "Extraer…" de comprimidos que ya
están en la consola, y arrastrar archivos del PC a la carpeta abierta.
- El explorador ya no necesita BFpilot para casi nada: renombrar, mover,
borrar, crear carpetas, permisos, tamaños y copiar funcionan solo con FTP.
- Campana de notificaciones arriba: transferencias terminadas o con error,
operaciones de archivos, desconexiones de la consola y versiones nuevas.
NOVEDADES 1.18.4
- Arreglado: si dejabas la ventana minimizada o en segundo plano un rato, el
programa se cerraba solo y al volver salía "Failed to fetch". Ahora solo se
cierra cuando cierras la ventana de verdad.
NOVEDADES 1.18.3
- Arreglado "Failed to fetch" y la cola que aparecía y desaparecía: en Windows
podían quedar dos PS5 Directo escuchando en el mismo puerto (por ejemplo al
abrirlo dos veces seguidas). Ahora solo puede haber uno abierto.
- Si la conexión con el programa falla un instante, se reintenta sola.
NOVEDADES 1.18.2
- Crea automáticamente un acceso directo "PS5 Directo" en el escritorio (y en "Enviar a")
con el icono del programa. Si lo borras no vuelve a aparecer; si apuntaba a
una copia vieja del programa, se corrige.
- La barra de tareas enseña el icono nuevo mientras el programa está abierto.
- Si se había quedado abierta una versión antigua (por ejemplo una copia vieja
en otra carpeta), al abrir esta se cierra la vieja sola en vez de enseñarla.
NOVEDADES 1.18.1
- Al borrar algo grande se ve cuánto se ha liberado y el tiempo que lleva, y el
espacio libre del explorador se actualiza mientras tanto.
NOVEDADES 1.18
- Pestaña "Espacio": gráfico de quesitos y lista de todo lo que ocupa sitio en
la consola, con el nombre de cada aplicación y su tamaño. Marca contenido repetido
(por ejemplo la carpeta y su versión convertida), envíos a medias y restos,
y se pueden borrar desde ahí. También con discos USB/externos.
- Descargas más rápidas: cada conexión se reutiliza para muchos trozos
seguidos, como hacen los gestores de descargas.
- La extensión pasa a PS5 Directo las cookies de ese alojamiento, el navegador
y la página de origen: misma velocidad y permiso que en el navegador (sesión
iniciada, cuenta premium) y menos errores 403. Las cookies no salen de tu PC
ni se guardan en disco. Tras actualizar, en chrome://extensions recarga la
extensión y acepta el permiso nuevo.
- Carpetas: antes de enviar comprueba que lo que falta cabe en la PS5, y la
velocidad ya no da saltos falsos al continuar un archivo a medias.
- La IP de la PS5 se limpia sola si se escribe con espacios, ftp://, puerto o
comas (antes daba "getaddrinfo failed").
- Tras actualizar, una ventana te enseña las novedades.
- Mejor diseño en ventanas estrechas y pequeños arreglos.
NOVEDADES 1.17
- Enlaces ftp:// (un NAS u otro servidor): ftp://usuario:clave@nas/ruta/archivo.rar
Funcionan como los enlaces normales, con reanudación.
- Comprimidos .tar, .tar.gz, .tar.bz2 y .tar.xz: se descomprimen en el PC
sobre la marcha (no hace falta 7-Zip ni BFpilot).
- Las carpetas se envían con varias conexiones a la vez (Ajustes > Partes a
la vez), más rápido con muchos archivos.
- Pasos propios para los envíos de carpetas: Comparar → Enviar → Listo.
NOVEDADES 1.16
- Pestaña "Archivos de la consola": explorador con tamaños, copiar, mover,
renombrar, borrar, bajar al PC, permisos y subir aquí.
- Enviar carpetas del PC, saltando lo que ya está y continuando lo cortado.
- Botones "Elegir archivos…" y "Elegir carpeta…" (ventana de Windows).
- Pestaña "Actividad" con el historial.
NOVEDADES 1.15
- Inglés: botón "English" / "Español" arriba. La primera vez elige solo
según el idioma de Windows. La extensión del navegador también.
NOVEDADES 1.14.1
- Busca las actualizaciones en github.com/jstrdev/ps5directo sin tener
que configurar nada.
NOVEDADES 1.14
- Guía de bienvenida la primera vez que se abre: enseña para qué es cada
parte. Se puede volver a ver con el botón "Guía" de arriba.
parte. Se puede volver a ver con el botón "Guía de uso" de arriba.
NOVEDADES 1.13.1
- El logo de la cabecera va dentro de la página (al actualizar desde una
@@ -210,8 +568,8 @@ NOVEDADES 1.8
-------------
- Mientras descomprime ves "leido del RAR X de Y" (lo que BFpilot ha
procesado del comprimido) y "descomprimido" (lo que ocupa de verdad en
la PS5). Una aplicación en formato carpeta puede ocupar varias veces el RAR:
Lost Records, 35 GB de RAR -> 145 GB de carpeta.
la PS5). Una aplicación en formato carpeta puede ocupar varias veces el RAR
(por ejemplo, 35 GB de RAR -> 145 GB de carpeta).
- Las previsiones de espacio cuentan con hasta ~5 veces el tamano del RAR.
- Si el RAR trae la aplicación dentro de una carpeta, se coloca igual como
TITLEID-app.
@@ -247,7 +605,8 @@ SI ALGO FALLA
ENLACES
-------
Funcionan los enlaces de descarga directa. Pixeldrain, Dropbox y algunos
Funcionan los enlaces de descarga directa, y también los ftp:// de un NAS
u otro servidor (ftp://usuario:clave@nas/ruta/archivo.rar). Pixeldrain, Dropbox y algunos
de Mediafire y Google Drive se convierten solos. Las páginas que piden
captcha o iniciar sesión no funcionan: copia el enlace final de descarga.
+4 -2
View File
@@ -9,13 +9,15 @@ For Each a In WScript.Arguments
args = args & " """ & a & """"
Next
py = ""
If sh.Run("cmd /c where pyw >nul 2>nul", 0, True) = 0 Then
If fso.FileExists(dir & "\python\pythonw.exe") Then
py = """" & dir & "\python\pythonw.exe"""
ElseIf sh.Run("cmd /c where pyw >nul 2>nul", 0, True) = 0 Then
py = "pyw -3"
ElseIf sh.Run("cmd /c where pythonw >nul 2>nul", 0, True) = 0 Then
py = "pythonw"
End If
If py = "" Then
MsgBox "No encuentro Python. Instala Python 3 (marca 'Add to PATH') o usa 'Iniciar PS5 Directo.bat'.", 48, "PS5 Directo"
MsgBox "No encuentro Python. Descarga la version portable (trae Python) o instala Python 3 (marca 'Add to PATH').", 48, "PS5 Directo"
Else
sh.Run py & " """ & dir & "\app.py""" & args, 0, False
End If
+79 -18
View File
@@ -1,29 +1,90 @@
# PS5 Directo
Herramienta de transferencia de archivos para Windows: envía archivos a una PS5 con jailbreak por FTP mientras se descargan, sin pasar por el disco del PC. Después los descomprime (en la consola con BFpilot, o en el PC con 7-Zip) y coloca las aplicaciones en `/data/homebrew` para que ShadowMountPlus las muestre en el menú.
**English** · [Español](#español)
- Descarga en paralelo, con pausa, reanudación y límite de velocidad.
- Vigila el espacio libre de la PS5 para no llenarla.
- Corrige los permisos de lo descomprimido con BFpilot. Sin esa corrección no arranca (CE-107750-0).
- Extensión opcional para Chrome/Edge que manda los enlaces directamente al programa.
- Se actualiza desde las releases de este repositorio.
An all-in-one Windows tool for jailbroken PS5 consoles: it **downloads, converts and sends** in a single step. Sent as is, files go to the console over FTP **while they download**, without storing them on your PC; or it **converts them on the fly** (LZ4, `.exfat`, folder, `.ffpfsc`…) as part of the same job, no second program needed. It extracts on the console (BFpilot) or on the PC (7-Zip), places apps in `/data/homebrew` so ShadowMountPlus shows them in the menu, and lets you browse your console's library with covers and control everything from your phone.
## Requisitos
![PS5 Directo: paste a link, send it as is or convert it, and it shows up in the library](docs/demo_en.gif)
- **PC:** Windows 10/11, [Python 3.9+](https://www.python.org/downloads/) y, para descomprimir en el PC, [7-Zip](https://www.7-zip.org/).
- **PS5 con jailbreak:**
- Servidor FTP, por ejemplo [ftpsrv](https://github.com/ps5-payload-dev/ftpsrv) en el puerto 2121.
- [BFpilot](https://github.com/ItsBlurf/BFpilot) en el puerto 5905.
<sub>Demo with a sample homebrew app served from a NAS on the local network.</sub>
- ✅ Streams downloads straight to the console: nothing is saved on the PC
- ✅ Works from download links, ftp:// links (e.g. a NAS), torrents (magnet or .torrent) or files on your PC
- ✅ Joins split parts (.part1, .part2… / .001, .002…) and extracts RAR, 7z, ZIP and tar (.gz/.bz2/.xz)
- ✅ Extracts on the console (BFpilot) or on the PC (7-Zip, every file CRC-checked)
- ✅ Fixes the file permissions that stop BFpilot-extracted content from launching (CE-107750-0)
- ✅ Pause, resume and retry where it left off, even after a dropped connection
- ✅ Built-in console file browser (works over plain FTP, BFpilot optional): right-click menu, shortcuts, move/copy to…, extract archives on the console, drag & drop uploads, download to PC
- ✅ Notification bell: finished or failed transfers, disconnections and new versions
- ✅ Storage view: a pie chart of what fills the console, by app name and size, flagging duplicates and leftovers you can delete
- ✅ Send whole PC folders over several connections, skipping what's already there and resuming what got cut off
- ✅ Watches free space so the console never fills up
- ✅ Speed limit and built-in speed test
- ✅ Download-manager style downloads: several reused connections per file, auto-backoff when a host complains
- ✅ Optional browser extension: links arrive by themselves with your browser session (same speed and access as the browser)
- ✅ Drag and drop, or "Send to" from Explorer
- ✅ Welcome guide, one-click updates, English and Spanish
- ✅ **Library tab**: covers, versions and the firmware each app needs, flagging what won't launch on your console (backport-aware), duplicates and incomplete folders. Also shows what's installed (PS4 and PS5), your PC/NAS collection with what's missing on the console, and links to each title's public update list
- ✅ **Backup tab**: saved data, ShadowMountPlus/payload settings and the app database copied to the PC, manually or daily; restore saved data to the same console
- ✅ **Captures tab**: view the console's screenshots and videos and download them
- ✅ **Diagnosis** on failed transfers (cause, codes and fixes) and a one-click problem report (.zip, no passwords)
- ✅ **Format converter** with [PS5 Dump Forge](https://github.com/quer3q/ps5-dump-forge) (optional): send it as is, or turn it on the PC into a plain folder, `.exfat`, LZ4, `.ffpfsc`, `.ffpkg`, `.ffpfs` or `.fpkg`, with a "Which one?" guide by need. Archives with a normal version plus a backport are split automatically
- ✅ Shows your PS5 firmware at the top and tells you which formats and apps will work on it
- ✅ "Download again" from the queue or the history, without pasting the link
- ✅ Asks before sending something that's already on the console (send anyway, replace or cancel)
- ✅ Checks every part against its `.sfv` / `.md5` / `.sha1` while sending
- ✅ "Make room": suggests what to delete when space runs out
- ✅ Loads ftpsrv and BFpilot on the PS5 from the app (ELF loader, port 9021)
- ✅ "Why is it slow?" network diagnostics (Wi-Fi band and signal, 100 Mb/s cables, VPNs, ping)
- ✅ Open it from your phone with a QR code; schedule the queue and sleep or shut down the PC when it's done
## Requirements
- **PC:** Windows 10/11. Get the `-portable-windows.zip` (Python included, nothing to install), or the plain `.zip` with [Python 3.9+](https://www.python.org/downloads/) installed (tick "Add python.exe to PATH"). For extracting on the PC, also install [7-Zip](https://www.7-zip.org/).
- **Jailbroken PS5:**
- An FTP server, for example [ftpsrv](https://github.com/ps5-payload-dev/ftpsrv) on port 2121.
- [BFpilot](https://github.com/ItsBlurf/BFpilot) on port 5905.
- [ShadowMountPlus](https://github.com/drakmor/ShadowMountPlus).
- Payloads can be loaded with [ps5-payload-manager](https://github.com/itsPLK/ps5-payload-manager).
## Uso
## Getting started
1. Descarga el `.zip` de la última [release](../../releases) y descomprímelo.
2. Ejecuta `Crear accesos directos.bat` y abre **PS5 Directo** desde el escritorio.
3. Pon la IP de tu PS5 en Ajustes y pega los enlaces o arrastra los archivos.
1. Download the `-portable-windows.zip` (or the plain `.zip` if you have Python) from the latest [release](../../releases) and extract it anywhere.
2. Run `Crear accesos directos.bat` ("create shortcuts"). It adds a desktop icon and a "Send to → PS5 Directo" entry.
3. Open **PS5 Directo** from the desktop. The language follows Windows; switch it with the **English / Español** button at the top.
4. Follow the welcome guide, enter your PS5's IP in Settings, then paste links or drop files.
La guía completa está en [LEEME.txt](LEEME.txt).
> **About BFpilot and permissions:** up to at least v0.4.4, BFpilot's archive extractor leaves files without the execute bit, so the PS5 refuses to launch them (CE-107750-0). This also happens when you extract from BFpilot's own web UI. PS5 Directo fixes it automatically after every extraction. For content you already have, use **Settings → Fix permissions**.
## Aviso
The full guide is in [README_EN.txt](README_EN.txt) (Spanish: [LEEME.txt](LEEME.txt)).
Proyecto independiente, sin relación con Sony ni con los autores de las herramientas citadas. No incluye contenido de terceros, claves ni archivos de Sony, ni enlaces a sitios de descargas. Úsalo solo con contenido que tengas derecho a usar (copias de seguridad propias y homebrew).
## Publishing a release
Bump `VERSION` in `app.py`, add the notes to `LEEME.txt` / `README_EN.txt`, then push a tag (`git tag v1.20.3 && git push --tags`). The GitHub Action builds both zips (plain and portable with Python) and creates the release.
## Disclaimer
Independent project, not affiliated with Sony or with the authors of the tools mentioned. It's a file-transfer tool: it includes no third-party content, no Sony keys or files, and no links to download sites. Use it only with content you have the right to use (your own backups and homebrew).
- It does not jailbreak the console or bypass any protection: it only copies files to a console you have already modified yourself.
- No piracy: don't use it to copy or run software you don't own or aren't licensed to use. Requests for help getting such content are not answered.
- You are responsible for how you use it. Modifying a console can void its warranty, break its terms of service or lose data: back up what matters.
- Provided "as is", without warranty of any kind. "PlayStation" and "PS5" are trademarks of Sony Interactive Entertainment, used only to describe compatibility.
---
## Español
![PS5 Directo: pegas un enlace, lo envías tal cual o lo conviertes, y aparece en la biblioteca](docs/demo_es.gif)
Herramienta todo en uno para Windows y PS5 con jailbreak: **descarga, convierte y envía** en un solo paso. Tal cual, los archivos van a la consola por FTP **mientras se descargan**, sin pasar por el disco del PC; o los **convierte sobre la marcha** (LZ4, `.exfat`, carpeta, `.ffpfsc`…) dentro del mismo trabajo, sin usar otro programa. Descomprime en la consola (BFpilot) o en el PC (7-Zip), coloca las aplicaciones en `/data/homebrew` para que ShadowMountPlus las muestre en el menú, y te deja ver la biblioteca de la consola con portadas y controlarlo todo desde el móvil.
**Novedades 1.20.3:** ventana de bienvenida, Biblioteca con lo instalado (PS4 y PS5) y con tu colección del PC/NAS, copias de seguridad de partidas y ajustes, capturas y vídeos, diagnóstico de errores con informe, torrents y avisos de actualización automáticos.
**Novedades 1.20:** pestaña Biblioteca con portadas y aviso de firmware, convertidor de formatos con [PS5 Dump Forge](https://github.com/quer3q/ps5-dump-forge) (carpeta, `.exfat`, LZ4, `.ffpfsc`, `.ffpkg`, `.ffpfs` y `.fpkg`), firmware de tu PS5 siempre a la vista, «Descargar de nuevo», pregunta si ya está en la consola, comprobación con `.sfv`/`.md5`, "Hacer sitio", cargar ftpsrv/BFpilot desde el programa, diagnóstico de red, acceso desde el móvil con QR y programar la cola.
**Requisitos:** Windows 10/11. Descarga el `-portable-windows.zip` (trae Python, no hay que instalar nada) o el `.zip` normal con [Python 3.9+](https://www.python.org/downloads/). Para descomprimir en el PC, [7-Zip](https://www.7-zip.org/). En la PS5: servidor FTP ([ftpsrv](https://github.com/ps5-payload-dev/ftpsrv)), [BFpilot](https://github.com/ItsBlurf/BFpilot) y [ShadowMountPlus](https://github.com/drakmor/ShadowMountPlus).
**Uso:** descarga el `.zip` de la última [release](../../releases), ejecuta `Crear accesos directos.bat` y abre **PS5 Directo** desde el escritorio. La guía completa está en [LEEME.txt](LEEME.txt).
**Aviso:** proyecto independiente, sin relación con Sony ni con los autores de las herramientas citadas. No incluye contenido de terceros, claves ni archivos de Sony, ni enlaces a sitios de descargas. Úsalo solo con contenido que tengas derecho a usar (copias de seguridad propias y homebrew). No hace el jailbreak ni salta ninguna protección: solo copia archivos a una consola que ya has modificado tú. No se da ayuda para conseguir contenido sin licencia. Se ofrece tal cual, sin garantías, y lo que hagas con él es responsabilidad tuya.
+493
View File
@@ -0,0 +1,493 @@
PS5 DIRECTO 1.20.0 — USER GUIDE (English)
=========================================
QUICK START (5 MINUTES)
=======================
You need: a PS5 that is already jailbroken (PS5 Directo doesn't do that)
and a Windows 10/11 PC on the same network.
1. Download PS5Directo-X.Y.Z-portable-windows.zip from the GitHub Releases
page (nothing else to install) and extract it, e.g. into Documents.
2. Double-click "PS5 Directo.vbs". If Windows asks whether to open a file
downloaded from the internet, click "Open".
3. On the PS5, load your jailbreak and ShadowMountPlus as usual.
4. The wizard asks for the PS5's IP: on the PS5, Settings > Network >
View Connection Status > "IPv4 Address".
5. It checks the FTP server and BFpilot. If one is red, click "Load" next to
it. (With Y2JB Autoloader that doesn't work: load them from Payload
Manager on the PS5 and click "Check again".)
6. Paste a direct download link (or drag a file onto the window) and click
"Add to queue". When it says "Done", it's in the PS5's menu.
Something wrong? Settings > "Full check" tells you what and how to fix it.
Note: PS5 Directo only copies files. Use it with content you have the
right to use (your own backups and homebrew).
(The full guide follows; you don't need it to get started.)
Paste links (or drag files from your PC) and the tool does the rest:
1. Downloads the files and sends them to the PS5 over FTP while they
download (nothing is stored on your PC's disk).
2. Joins split parts (.001, .002...) into a single file.
3. Asks BFpilot to extract the RAR/7z/ZIP ON the console, trying the
passwords it knows.
4. Finds the app folder (the one with sce_sys) and puts it in
/data/homebrew, where ShadowMountPlus picks it up automatically.
5. Deletes the archives from the PS5.
While one transfer is extracting on the PS5, the next one in the queue is
already being sent.
TABS
- Transfers: the queue.
- Console files: browse the PS5 like a file explorer. You see the size
and date of every file (folders with "calculate"), and you can create
folders, rename, copy or move (Copy/Move, then "Paste here" in the
destination folder), delete, download to the PC (to Downloads\PS5
Directo), set 777 permissions, and upload files or folders as-is into
the current folder.
Right-click a file or the empty space for the menu; shortcuts: Del,
F2, Ctrl+C / Ctrl+X / Ctrl+V, Ctrl+A and Backspace. "Move to…" and
"Copy to…" open a folder picker with recent destinations. If something
with the same name already exists when pasting, you choose replace/merge,
keep both or skip. "Extract…" unpacks a .rar/.7z/.zip that is already on
the console. Drives (with free space) and quick places are on the left.
You can drag files from the PC onto the open folder.
Without BFpilot almost everything works over FTP (copying goes through
the PC, slower); extracting and showing free space do need BFpilot.
- Space: a pie chart of what takes up space on the console, with each
app's name and size. It flags duplicate content (for example a folder and
its version converted to an image), half-sent transfers and leftovers,
and lets you delete them from there (it asks first). Needs BFpilot.
Anything installed from the PS5 itself is shown but deleted on the console.
- Activity: history of finished and failed transfers.
PC FOLDERS
With "Choose folder…" (or by dragging the folder onto the icon) a whole
folder is sent as-is. If it has sce_sys it goes to /data/homebrew as
TITLEID-app. If part of it is already on the console (for example, an
upload from another program that got cut off), it skips the files that
are already identical and resumes the ones left half-way.
ALTERNATIVE: EXTRACT ON THE PC (7-Zip)
In "Where to extract" choose "On the PC (7-Zip)" (or make it the default
in Settings). Then:
- Links are downloaded to the PC first (temporary folder in Settings;
you need room for the RAR, not for the extracted content). Your own
local files are used as they are and are never deleted.
- 7-Zip extracts on the fly and the app sends each loose file to the
PS5. Nothing extracted is written to the PC.
- Every file is checked against its CRC before it's accepted.
- On the PS5 it only takes the final size (no RAR alongside), and the
exact size is known before starting.
- Trade-off: everything travels uncompressed over Wi-Fi (can be 3-4
times more than the RAR), so sending takes longer.
- Pause/Retry continues from the file where it stopped.
Requires 7-Zip (free, 7-zip.org). BFpilot is not needed.
WHAT YOU NEED
-------------
This guide doesn't cover how to jailbreak: it assumes your PS5 is already
jailbroken and that you know how to load payloads (.elf).
ON THE PC
- Windows 10 or 11.
- Python 3.9 or newer: https://www.python.org/downloads/
When installing, tick "Add python.exe to PATH".
- 7-Zip (only for "Extract on the PC"): https://www.7-zip.org/
ON THE PS5 (loaded as payloads, for example with Payload Manager:
https://github.com/itsPLK/ps5-payload-manager )
- An FTP server. The reference one is ftpsrv (port 2121):
https://github.com/ps5-payload-dev/ftpsrv
Many payload menus already include it. If yours uses another port,
change it in Settings.
- BFpilot (port 5905): extracts on the console, moves and deletes files.
Get bfpilot.elf from: https://github.com/ItsBlurf/BFpilot/releases
If it isn't loaded, the program waits until you load it. Not needed in
"Extract on the PC" mode.
- ShadowMountPlus: makes the apps in /data/homebrew appear on the PS5
home screen: https://github.com/drakmor/ShadowMountPlus
To check that everything works: Settings > "Full check".
ABOUT BFPILOT AND PERMISSIONS (important even if you use it on its own)
-----------------------------------------------------------------------
Up to at least version 0.4.4, when BFpilot extracts a RAR, 7z or ZIP it
leaves the files without the execute permission, and the PS5 refuses to
open the app (error CE-107750-0). It also happens when you extract from
BFpilot's own web page, without PS5 Directo.
- PS5 Directo fixes it automatically after every extraction.
- For content already on your console: Settings > "Fix permissions".
- By hand: in FileZilla, right-click the app folder > File permissions >
777 > "Recurse into subdirectories".
FIRST TIME
----------
Double-click "Crear accesos directos.bat" ("create shortcuts"). It adds:
- A "PS5 Directo" icon on the desktop.
- "Send to > PS5 Directo" in the right-click menu of your files.
From then on, open PS5 Directo from the desktop icon: it runs in its own
window, with no tabs and no black console window.
(If something fails to start, use "Iniciar PS5 Directo.bat" ("start PS5
Directo"): same thing but with the black window, where errors are shown.
Log when running without the window: %USERPROFILE%\.ps5directo\ps5directo.log)
The language follows Windows. Switch it anytime with the "English" /
"Español" button at the top.
If you close the window with transfers running, they keep going in the
background. Open PS5 Directo again to see them. The "Quit" button closes
it completely (anything unfinished continues later with "Retry").
HOW TO USE IT
-------------
1. Extract this folder anywhere you like.
2. Open PS5 Directo from the desktop icon. A short welcome guide explains
each part (you can see it again with the "User guide" button).
3. The first time, Settings opens: enter your PS5's IP (on the PS5:
Settings > Network > View Connection Status), click "Save" and then
"Test connection". Both dots at the top should turn green.
4. Paste the direct links (all parts together, in any order) and click
"Add to queue".
- If you know the password, type it. Otherwise it tries the ones in
Settings and whatever is in brackets in the file name, like [WEB.COM].
- A path to a file already on your PC also works.
5. FILES ON YOUR PC WITHOUT COPYING PATHS:
- Drag one or more files onto the desktop icon.
- Or right-click the files > Send to > PS5 Directo.
If PS5 Directo is already open, they're added to its queue.
- Or drop them on the app window: PS5 Directo finds them on your PC by
name and size and puts their paths in the link box.
PAUSE, LIMIT AND SPACE
----------------------
- "Pause" stops sending; "Resume" continues where it left off.
- Settings > Speed limit (MB/s): to keep using the internet while it
sends. Applies instantly. 0 = no limit.
- Settings > Always keep free (GB, 25 by default): before starting it
checks that what's left to send fits, and while sending or extracting it
watches the free space. If it drops below that margin, it stops
everything before the PS5 fills up. Free up space and click Retry.
- Some file hosts limit connections: with them use just 2 per file, and
fewer if the server starts returning errors.
UPDATES AND EXTENSION
---------------------
- "Update" button (top): checks GitHub for a new version and installs it.
When there is one, the button turns blue and shows the version. You can
also install from a downloaded .zip. A copy of the previous version is
kept in the .backup folder.
- "Extension" button (top): opens the folder of the Chrome/Edge extension
and its instructions. With it, when you click Download on a website, the
link goes straight to PS5 Directo, no copy and paste:
1. Open chrome://extensions (or edge://extensions).
2. Turn on "Developer mode" (top right).
3. "Load unpacked" and choose PS5 Directo's "extension" folder.
Pass the captcha and click Download as usual: if it's a .rar/.7z/.zip/.pkg
and PS5 Directo is open, the final link (after redirects) appears in the
link box and the browser downloads nothing. When all parts are in, click
"Add to queue". If PS5 Directo is closed, the download goes ahead
normally. Turn it on and off from its icon.
SPEED TEST
----------
On a paused or finished transfer, "Speed test" measures (about 30 s):
download only, PC -> PS5 upload only, and both at once, and tells you
what's to blame when it's slow. There's also a PC -> PS5 only test in
Settings.
MAINTENANCE
-----------
- Settings > Full check: tests FTP, writing, BFpilot, formats, 7-Zip and
free space, and tells you what to do if something fails.
- Settings > PS5 cleanup: finds leftovers in /data/ps5directo, shows how
much they take and deletes them (it never touches anything outside that
folder).
- Warns if the same Title ID already exists in /data/homebrew or on a
USB/external drive.
- Destination: suggests /mnt/usbX/homebrew when drives are connected.
- Windows notification when a transfer finishes or fails (accept the
permission the first time).
IF SOMETHING GOES WRONG
-----------------------
- The network or FTP drops: it retries by itself and continues where it
left off.
- You close the program midway: when you open it again, click "Retry".
It continues from what was already on the console.
- Wrong password: click "Retry" and type it. Nothing is downloaded again.
- "Already exists": it never overwrites what you have. Delete or rename it
and click "Retry".
- Work files live in /data/ps5directo (outside the folders ShadowMountPlus
scans).
LINKS
-----
Direct download links work, and so do ftp:// links to a NAS or another
server (ftp://user:password@nas/path/file.rar). Pixeldrain, Dropbox and some Mediafire and
Google Drive links are converted automatically. Pages that require a
captcha or a login don't work directly: copy the final download link, or
use the browser extension.
.pkg files go to /data/pkg, to install them with ps5upload.
Images (.exfat, .ffpkg, .ffpfsc) go to /data/homebrew.
Settings and queue are stored in %USERPROFILE%\.ps5directo
LIBRARY
-------
The Library tab shows what's in /data/homebrew (and on USB drives) with its
cover, name, Title ID, version, folder or image (.ffpkg, .ffpfsc, .exfat)
and the firmware it needs. Set your PS5's firmware in Settings (e.g. 13.60)
and the ones that won't launch are flagged in red. It also flags duplicates,
DLC/updates and incomplete folders. Works with FTP alone; with BFpilot it
also shows how much each folder takes. Firmware comes from param.json and,
for backported titles (fakelib folder), from what the executables require.
Every finished transfer is checked too.
IMAGES AND LZ4 (PS5 DUMP FORGE)
-------------------------------
"How to leave it on the PS5" defaults to "No conversion": left as it comes
(archives are extracted; an .ffpkg, .exfat or .ffpfsc image or LZ4 content
is sent untouched). You can also pick:
- Plain folder: always ends up as a folder; images, .fpkg and LZ4 are
unpacked on the PC.
- .ffpkg image: recommended by ShadowMountPlus. Full speed.
- .exfat or .ffpfs image: ShadowMountPlus mounts them too.
- Compressed .ffpfsc image: 30-60% smaller, but read more slowly
(150-250 MB/s); some titles may stutter.
- .fpkg package: installs like a store app. Firmware 11.60 or lower only
(kstuff, fpkg-enable and ppr-patch). Left in /data/pkg. For .fpkg and
.ffpfsc you can pick the compression.
- LZ4 (folder or inside an .ffpkg): AMPR titles only. Experimental: some
titles crash when saving. Non-AMPR content is sent as a folder or plain
.ffpkg.
It's prepared on the PC with PS5 Dump Forge (github.com/quer3q/ps5-dump-forge,
downloaded automatically the first time) and sent as a single file. Needs
room on the PC for the image. .ffpkg/.ffpfsc images are not FPKG packages:
they aren't installed, ShadowMountPlus mounts them. DLC and updates are
sent as folders.
BEFORE SENDING
--------------
- If it's already on the console (same Title ID), the transfer
stops and asks: send anyway, replace the copy there, or cancel.
- Paste the .sfv / .md5 / .sha1 with the parts (or keep it next to them on
the PC) and every part is checked while it's sent.
- When there's no room, the error has a "Make room" button that suggests
what to delete in the Space tab. Nothing is deleted without confirmation.
PAYLOADS, DIAGNOSTICS, PHONE AND SCHEDULE
-----------------------------------------
- Click the FTP / BFpilot dots (or Settings > Load payloads) to send ftpsrv
or BFpilot to the PS5's ELF loader (port 9021, etaHEN or elfldr). The Y2JB
Autoloader loader only accepts the console itself: use Payload Manager.
- "Why is it slow?" checks Wi-Fi vs cable, band and signal, 100 Mb/s links,
VPNs, different networks and the ping to the PS5.
- The phone button shows a QR code to open PS5 Directo from your phone on
the same network.
- "Schedule" (queue): start at a set time and sleep or shut down the PC when
done. The PC doesn't go to sleep while transfers are running.
PORTABLE VERSION
----------------
Each release has PS5Directo-X.Y.Z.zip (needs Python installed) and
PS5Directo-X.Y.Z-portable-windows.zip, which includes Python: extract and run.
WHAT'S NEW
----------
1.20.3 - Library: "Check" on each app, for when it won't open or closes on
launch. It checks the folder (executable, param.json, permissions,
firmware, backports and LZ4 packing), shows logs (.log) and captures
from the last minutes, explains the error code shown on the TV and
saves a .zip report. Read-only: it changes nothing.
- Welcome window on first launch: sums up what PS5 Directo is and does.
- Library: also what's installed on the console (PS4 and PS5), with
cover, version and firmware, and a filter for it.
- Library, "On your PC": pick PC or NAS folders, see what's already on
the console and what isn't, and send it with one click.
- Library: "See updates" opens each title's public official update list
in your browser (Prospero Patches). Warns that updates needing
firmware 14.00 or higher can't be installed. The program downloads
nothing.
- Library: if PS5 Game Updater is on the console, a button opens it; if
its folder is misplaced, it detects and fixes it.
- Library: images and folders without param.json show name, cover and
firmware.
- New "Backup" tab: saves saved data, ShadowMountPlus and payload
settings and the app database to the PC, manually or daily. Saved data
can be restored to the same console (current data is backed up first).
- New "Captures" tab: the console's screenshots and videos with
thumbnails, to view and download to the PC.
- "Diagnosis" on failed transfers: what happened, codes and how to fix
it, plus a .zip report (no passwords) to send to whoever helps you. In
Settings, "Create problem report".
- Torrents: paste a magnet or a .torrent. It's downloaded to the PC
first with aria2 (fetched automatically) and then sent, extracted or
converted. No seeding afterwards; deleted from the PC.
- PS5 Dump Forge updates itself (at most daily), checking first the new
version works; otherwise it keeps the previous one.
- New PS5 Directo versions are announced by themselves in a window with
what's new.
- Warns if the speed to the PS5 suddenly drops (usually the console
idling: press a controller button).
- "Format on the PS5" starts folded and says how long it takes: no
conversion downloads and sends at once; converting takes 3 steps.
Cards sorted by most used and "Which one?" by need.
- Your PS5 firmware next to the title (saves automatically) and the
.fpkg card tells you if it works.
- In the queue, "Convert to …" names the format, and it warns if
something couldn't be converted.
- Fixed: an archive with a normal version plus a backport wasn't
converted; now it picks the right one.
- Fixed: converted files got mixed into an older folder with the same
name.
- Fixed: many Library folders showed no name.
1.20.1 - If it can't connect and the PC and PS5 are on different networks,
it says so and explains how to fix it.
- Clearer "Use on your phone" and "Browser extension" buttons, also
offered at the end of the first-steps wizard.
- "Download again" in the queue and in Activity: starts over without
pasting the link again. If the target already exists when placing,
it asks (keep both, replace or cancel) instead of failing.
- Fixed: archives with the normal app plus a "backport" folder no
longer fail with "Already exists"; half-sent leftovers are
replaced.
- Updated "User guide": explains the format converter, every tab,
phone access and the browser extension.
- The "Which one?" window adds estimated speeds where there was no
data, with clearer notes on LZ4 and .ffpfsc.
1.20.0 - First-steps wizard (IP, connection check and loading what's
missing, firmware) and a shorter, simpler guide.
- New Library tab: what's on the console with cover, version, format
and required firmware, flagging what won't launch on yours.
- .ffpkg / .ffpfsc images and LZ4 with PS5 Dump Forge (optional):
prepared on the PC and sent as a single file. Picked with cards
under the destination, each explained, with the room needed on the
PC; the first time it warns that converting takes PC space until
it's done. A download that's already an image is sent as is or
converted to the chosen format, and placed even without BFpilot.
- New formats: plain folder, .exfat, .ffpfs and .fpkg (with a
compression choice). Without 7-Zip, PS5 Dump Forge extracts it.
- Formats are grouped (space savers first) and "Which one?" compares
the pros and cons of each.
- Time left (and rough finish time) when sending, extracting and
converting. On the phone, a big alert with vibration and a beep
when something finishes or fails (with the page open).
- Library: LZ4-packed folders are tagged LZ4 (plus an LZ4 filter).
- Fixed: resuming a transfer asked "Already on the console" about
its own half-sent copy.
- Fixed: the phone page was blank in some Android Chrome versions.
- Open on phone: the page is sent compressed and the dialog shows
"What arrives from the phone" to tell whether it gets there.
- Firmware warning (set yours in Settings), backport-aware.
- Asks before sending something that's already on the console.
- .sfv / .md5 / .sha1 checks while sending.
- "Make room": suggests what to delete when space runs out.
- Load ftpsrv and BFpilot on the PS5 from the app (port 9021).
- "Why is it slow?" network diagnostics.
- Open from your phone with a QR code.
- Schedule the queue, sleep or shut down when done, no sleep while
sending.
- Portable version with Python included.
- Fixed: with FTP only (no BFpilot), ftpsrv returned the console's
root when listing a folder; it affected the file browser and
folder uploads.
- Phone access: a button to allow it in Windows Firewall if the page
stays blank.
1.19.2 - Fixed "504 Option not supported" in Console files when BFpilot is
not loaded: the file browser now lists folders with ftpsrv alone
(and with FTP servers that have no MLSD).
1.19.1 - Fixed: the queue stopped updating by itself (since 1.18.3), so
"Remove" seemed to do nothing and then said "no existe". The file
browser now relists the open folder when an upload to it finishes.
Fixed "Download to PC" for apps: ftpsrv decrypted eboot.bin/.prx/
.sprx on the fly, so downloads came out incomplete. Files are now
transferred exactly as stored (this also makes size comparisons
when resuming folders correct). Thanks to RichyMX for finding it.
1.19 - Renewed file browser: right-click menu, keyboard shortcuts,
clickable path, drives and places on the left, "Move to…" / "Copy
to…" with recent destinations, a choice when pasting over existing
items (replace, merge, keep both or skip), "Extract…" for archives
already on the console, and dragging files from the PC onto the
open folder.
- The file browser no longer needs BFpilot for most things: rename,
move, delete, new folder, permissions, sizes and copy work over FTP.
- Notification bell at the top: finished or failed transfers, file
operations, console disconnections and new versions.
1.18.4 - Fixed: leaving the window minimized or in the background for a while
made the program close itself, showing "Failed to fetch" on return.
Now it only closes when you actually close the window.
1.18.3 - Fixed "Failed to fetch" and the queue appearing and disappearing: on
Windows two PS5 Directo could end up listening on the same port (e.g.
when opened twice in a row). Now only one can be open. Brief
connection hiccups are retried automatically.
1.18.2 - Creates a "PS5 Directo" shortcut on the desktop (and in "Send to")
with the program's icon. If you delete it, it won't come back; if it
pointed to an old copy, it's fixed. The taskbar shows the new icon.
If an old version was still open (e.g. an old copy in another folder),
it's closed automatically instead of being shown.
1.18.1 - When deleting something big you see how much has been freed and how
long it has taken, and the browser's free space updates meanwhile.
1.18 - "Space" tab: a pie chart and list of everything that takes up space
on the console, by app name and size. It flags duplicate content (for
example a folder and its converted version), half-sent transfers and
leftovers, and deletes them from there. USB/external drives too.
- Faster downloads: each connection is reused for many chunks in a row,
like download managers do.
- The extension passes that host's cookies, browser and source page to
PS5 Directo: same speed and access as in the browser (logged-in or
premium) and fewer 403 errors. Cookies never leave your PC and are
never saved to disk. After updating, reload the extension in
chrome://extensions and accept the new permission.
- Folders: checks that what's left to send fits on the PS5, and the
speed no longer shows false jumps when resuming a half-sent file.
- The PS5 IP is cleaned up if typed with spaces, ftp://, a port or
commas (it used to fail with "getaddrinfo failed").
- After updating, a window shows what's new.
- Better layout on narrow windows and small fixes.
1.17 ftp:// links (a NAS or other server) with resume. .tar/.tar.gz/.tar.bz2/
.tar.xz extracted on the PC (no 7-Zip needed). Folders upload over several
connections at once. Own steps for folder uploads.
1.16 "Console files" tab (file browser: sizes, copy, move, rename, delete,
download to PC, permissions, upload here). Send PC folders with
resume. "Choose files…/Choose folder…" buttons. "Activity" tab.
1.15 English interface (auto-detected; English/Español button). The
browser extension also follows the browser's language.
1.14 Welcome guide on first launch ("Guide" button to see it again).
Updates are checked on GitHub automatically.
1.13 New icon and background.
1.12 "Update" and "Extension" buttons on the main screen. Asks for the
PS5's IP on first launch.
1.11 IMPORTANT FIX: content extracted by BFpilot didn't launch
(CE-107750-0) because of missing execute permissions. PS5 Directo now
sets 777 when placing it. New Settings > "Fix permissions".
1.10 New option: extract on the PC with 7-Zip and send the content already
extracted, verified file by file.
DISCLAIMER
----------
PS5 Directo is an independent program, not affiliated with Sony or with
the authors of BFpilot, ftpsrv or ShadowMountPlus. It's a file-transfer
tool: it includes no third-party content, no Sony keys or files, and no
links to download sites. Use it only with content you have the right to
use (your own backups and homebrew). Everyone is responsible for what they
transfer.
+4498 -70
View File
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 928 KiB

+657 -24
View File
@@ -10,9 +10,11 @@ Solo usa la biblioteca estandar de Python 3.9+.
"""
import ftplib
import http.client
import json
import math
import os
import posixpath
import re
import socket
import ssl
@@ -40,7 +42,12 @@ class PipeError(Exception):
# ---------------------------------------------------------------------------
ARCHIVE_RE = re.compile(
r"\.(part\d+\.rar|rar|r\d{2,3}|7z|7z\.\d{3}|zip|z\d{2})$", re.I)
r"\.(part\d+\.rar|rar|r\d{2,3}|7z|7z\.\d{3}|zip|z\d{2}|tar|tar\.gz|tgz|tar\.bz2|tbz2?|tar\.xz|txz)$", re.I)
TAR_RE = re.compile(r"\.(tar|tar\.gz|tgz|tar\.bz2|tbz2?|tar\.xz|txz)$", re.I)
def is_tar(name):
return bool(TAR_RE.search(name or ""))
SPLIT_RAW_RE = re.compile(r"^(?P<base>.+)\.(?P<num>\d{3})$")
IMAGE_EXTS = (".exfat", ".ffpkg", ".ffpfs", ".ffpfsc", ".ufs")
@@ -48,6 +55,7 @@ IMAGE_EXTS = (".exfat", ".ffpkg", ".ffpfs", ".ffpfsc", ".ufs")
def display_name(name):
"""Nombre sin la parte de volumen (conserva mayusculas)."""
for pat in (r"\.part\d+\.rar$", r"\.7z\.\d{3}$", r"\.r\d{2,3}$", r"\.z\d{2}$",
r"\.tar\.(gz|bz2|xz)$", r"\.(tgz|tbz2?|txz|tar)$",
r"\.rar$", r"\.7z$", r"\.zip$", r"\.\d{3}$"):
new = re.sub(pat, "", name, flags=re.I)
if new != name:
@@ -63,7 +71,8 @@ def set_key(name):
"""Nombre comun de un conjunto de volumenes (para agruparlos)."""
n = name
for pat in (r"\.part\d+\.rar$", r"\.7z\.\d{3}$", r"\.r\d{2,3}$",
r"\.z\d{2}$", r"\.rar$", r"\.7z$", r"\.zip$"):
r"\.z\d{2}$", r"\.tar\.(gz|bz2|xz)$", r"\.(tgz|tbz2?|txz|tar)$",
r"\.rar$", r"\.7z$", r"\.zip$"):
new = re.sub(pat, "", n, flags=re.I)
if new != n:
return new.lower()
@@ -150,20 +159,125 @@ HONEST_UA = "PS5Directo/1.0 (download manager)"
_HOST_MODE = {}
def _open(url, headers=None, timeout=30):
# Lo que la extension del navegador nos cuenta de cada alojamiento: sus cookies (sesion,
# cuenta premium), el navegador y la pagina de origen. Asi el servidor nos trata igual que
# al navegador, como hacen los gestores de descargas. Solo en memoria, nunca en disco.
_BROWSER = {}
_BROWSER_LOCK = threading.Lock()
def set_browser_headers(url, cookie="", ua="", referer=""):
host = urllib.parse.urlparse(url).netloc.lower()
if not host:
return
info = {}
if cookie:
info["Cookie"] = cookie[:8000]
if ua:
info["User-Agent"] = ua[:500]
if referer and re.match(r"^https?://", referer, re.I):
info["Referer"] = referer[:2000]
with _BROWSER_LOCK:
if info:
_BROWSER[host] = info
else:
_BROWSER.pop(host, None)
def _headers(url, extra=None):
pu = urllib.parse.urlparse(url)
if _HOST_MODE.get(pu.netloc) == "honest":
host = pu.netloc.lower()
with _BROWSER_LOCK:
browser = dict(_BROWSER.get(host) or {})
if _HOST_MODE.get(pu.netloc) == "honest" and not browser:
h = {"User-Agent": HONEST_UA, "Accept": "*/*"}
else:
h = {"User-Agent": UA, "Accept": "*/*", "Accept-Language": "es-ES,es;q=0.9,en;q=0.8"}
if pu.scheme in ("http", "https") and pu.netloc:
h["Referer"] = "%s://%s/" % (pu.scheme, pu.netloc)
if headers:
h.update(headers)
req = urllib.request.Request(url, headers=h)
h.update(browser)
if extra:
h.update(extra)
return h
def _open(url, headers=None, timeout=30):
req = urllib.request.Request(url, headers=_headers(url, headers))
return urllib.request.urlopen(req, timeout=timeout, context=_SSL)
class _KeepAlive:
"""Una conexion HTTP que se reutiliza para muchos trozos seguidos (como los gestores
de descargas): sin repetir el saludo TCP/TLS ni el arranque lento de TCP en cada trozo.
Si hay proxy o el servidor redirige, se usa la via normal."""
def __init__(self):
self.conn = None
self.key = None
self.used = False
self.off = False
@staticmethod
def usable(url):
scheme = urllib.parse.urlparse(url).scheme.lower()
if scheme not in ("http", "https"):
return False
try:
return not urllib.request.getproxies().get(scheme)
except Exception:
return False
def open(self, url, headers, timeout):
if self.off:
return None
pu = urllib.parse.urlparse(url)
key = (pu.scheme.lower(), pu.netloc)
if self.conn is None or self.key != key:
self.close()
if key[0] == "https":
self.conn = http.client.HTTPSConnection(pu.netloc, timeout=timeout, context=_SSL)
else:
self.conn = http.client.HTTPConnection(pu.netloc, timeout=timeout)
self.key = key
path = pu.path or "/"
if pu.query:
path += "?" + pu.query
h = _headers(url, headers)
h["Connection"] = "keep-alive"
try:
self.conn.request("GET", path, headers=h)
r = self.conn.getresponse()
except Exception:
stale = self.used # el servidor cerro la conexion mientras esperaba:
self.close() # es normal, se abre otra sin contarlo como fallo
if not stale:
raise
return self.open(url, headers, timeout)
self.used = True
if r.status >= 300:
hdrs = r.headers
try:
r.read(64 * 1024)
except Exception:
pass
self.close()
if r.status < 400:
self.off = True # redirige en cada trozo: que lo lleve urllib
return None
raise urllib.error.HTTPError(url, r.status, r.reason, hdrs, None)
return r
def close(self):
if self.conn is not None:
try:
self.conn.close()
except Exception:
pass
self.conn = None
self.key = None
self.used = False
def resolve_url(url):
"""Convierte paginas de algunos alojamientos en el enlace directo (lo que se pueda)."""
url = url.strip()
@@ -281,15 +395,20 @@ def _single(url, cancel, meter):
yield data
def _fetch_range(url, a, b, cancel, meter, tries=6, on_trouble=None):
def _fetch_range(url, a, b, cancel, meter, tries=6, on_trouble=None, ka=None):
want = b - a + 1
last = None
rng = {"Range": "bytes=%d-%d" % (a, b)}
for attempt in range(tries):
if cancel.is_set():
raise Cancelled()
got = bytearray()
try:
with _open(url, {"Range": "bytes=%d-%d" % (a, b)}, timeout=25) as r:
r = ka.open(url, rng, 25) if ka is not None else None
reused = r is not None
if r is None:
r = _open(url, rng, timeout=25)
try:
if r.status != 206:
raise PipeError("el servidor no respeto el rango pedido")
while len(got) < want:
@@ -300,8 +419,19 @@ def _fetch_range(url, a, b, cancel, meter, tries=6, on_trouble=None):
break
got += piece
meter(len(piece))
except BaseException:
if reused:
ka.close()
raise
finally:
if not reused:
r.close()
if len(got) == want:
if reused and r.will_close:
ka.close() # el servidor no deja reutilizarla
return bytes(got)
if reused:
ka.close()
last = "respuesta corta (%d de %d bytes)" % (len(got), want)
except (Cancelled, PipeError):
raise
@@ -384,7 +514,17 @@ def _ranged(url, start, end, cfg, cancel, meter):
state["trouble_t"] = now
log("El servidor va con problemas (%s): bajo a %d conexiones" % (kind, state["allowed"]))
use_ka = _KeepAlive.usable(url)
def worker():
ka = _KeepAlive() if use_ka else None
try:
_worker(ka)
finally:
if ka is not None:
ka.close()
def _worker(ka):
while True:
with cond:
# recuperar conexiones si lleva un rato sin problemas
@@ -407,18 +547,18 @@ def _ranged(url, start, end, cfg, cancel, meter):
started[i] = time.time()
state["active"] += 1
try:
fetch(i)
fetch(i, ka=ka)
finally:
with cond:
state["active"] -= 1
cond.notify_all()
def fetch(i, hedge=False):
def fetch(i, hedge=False, ka=None):
a = start + i * chunk
b = min(end, a + chunk) - 1
t0 = time.time()
try:
data = _fetch_range(url, a, b, cancel, meter, on_trouble=trouble)
data = _fetch_range(url, a, b, cancel, meter, on_trouble=trouble, ka=ka)
except Exception as e:
with cond:
# si es la copia de rescate, o el original ya llego, no es grave
@@ -495,13 +635,393 @@ class FileSource:
yield data
class FolderSource:
"""Una carpeta del PC: se manda entera, archivo a archivo, conservando la estructura."""
kind = "folder"
def __init__(self, path):
self.path = os.path.abspath(path.strip().strip('"'))
self.original = self.path
self.name = safe_name(os.path.basename(self.path.rstrip("\\/")) or "carpeta")
self.size = -1
self.ranges = True
self.files = [] # [(ruta relativa con /, tamano)]
self.dirs = []
def probe(self):
if not os.path.isdir(self.path):
raise PipeError("No existe la carpeta: %s" % self.path)
files, dirs = [], []
for root, ds, fs in os.walk(self.path):
ds.sort()
rel_root = os.path.relpath(root, self.path).replace("\\", "/")
rel_root = "" if rel_root == "." else rel_root
for d in ds:
dirs.append((rel_root + "/" + d).lstrip("/"))
for f in sorted(fs):
full = os.path.join(root, f)
try:
files.append(((rel_root + "/" + f).lstrip("/"), os.path.getsize(full)))
except OSError:
pass
self.files, self.dirs = files, dirs
self.size = sum(sz for _, sz in files)
return self
class FtpSource:
"""Un archivo en otro servidor FTP (un NAS, por ejemplo): ftp://usuario:clave@host:puerto/ruta"""
kind = "url"
def __init__(self, url):
self.original = url.strip()
u = urllib.parse.urlparse(self.original)
self.host = u.hostname or ""
self.port = u.port or 21
self.user = urllib.parse.unquote(u.username or "anonymous")
self.pw = urllib.parse.unquote(u.password or "")
self.path = urllib.parse.unquote(u.path or "/")
self.name = safe_name(posixpath.basename(self.path) or "archivo")
self.size = -1
self.ranges = True
def _connect(self):
f = ftplib.FTP()
f.encoding = "utf-8"
f.connect(self.host, self.port, timeout=30)
f.login(self.user, self.pw)
f.set_pasv(True)
f.voidcmd("TYPE I")
return f
def probe(self):
try:
f = self._connect()
except Exception as e:
raise PipeError("No puedo conectar con el FTP %s:%s (%s)" % (self.host, self.port, e))
try:
s = Ftp.size(f, self.path)
if s is None:
raise PipeError("No existe en el FTP: %s" % self.path)
self.size = s
finally:
try:
f.quit()
except Exception:
pass
return self
def stream(self, offset, cfg, cancel, meter):
tries = 0
while True:
f = None
try:
f = self._connect()
conn = f.transfercmd("RETR " + self.path, rest=offset or None)
with conn:
while True:
if cancel.is_set():
raise Cancelled()
data = conn.recv(MiB)
if not data:
break
offset += len(data)
tries = 0
meter(len(data))
yield data
try:
f.voidresp()
except Exception:
pass
if self.size >= 0 and offset < self.size:
raise PipeError("el FTP corto la descarga")
return
except (Cancelled, GeneratorExit):
raise
except Exception as e:
tries += 1
if tries > int(cfg.get("retries", 8)):
raise PipeError("Fallo al leer del FTP %s: %s" % (self.host, e))
time.sleep(min(30, 2 * tries))
finally:
if f is not None:
try:
f.close()
except Exception:
pass
def make_source(text):
text = text.strip().strip('"')
if re.match(r"^https?://", text, re.I):
return UrlSource(text)
if re.match(r"^ftp://", text, re.I):
return FtpSource(text)
if os.path.isdir(text):
return FolderSource(text)
return FileSource(text)
_MONTHS = {m: i for i, m in enumerate(("jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep",
"oct", "nov", "dec"), 1)}
def _list_mode(perm):
"""'drwxr-xr-x' -> 0o755 (None si no se entiende)."""
if len(perm) < 10:
return None
m = 0
for i, ch in enumerate(perm[1:10]):
if ch not in "-":
m |= 1 << (8 - i)
return m
def _list_mtime(mon, day, yt):
import time as _t
try:
mo = _MONTHS[mon[:3].lower()]
d = int(day)
if ":" in yt:
hh, mm = (int(x) for x in yt.split(":"))
now = _t.localtime()
y = now.tm_year if (mo, d) <= (now.tm_mon, now.tm_mday) else now.tm_year - 1
else:
y, hh, mm = int(yt), 0, 0
return int(_t.mktime((y, mo, d, hh, mm, 0, 0, 0, -1)))
except Exception:
return None
def ftp_listdir(f, path):
"""[(nombre, {"type": "file"|"dir", "size": int, "mtime": int|None, "mode": int|None})].
Usa MLSD tal cual (sin OPTS MLST: ftpsrv responde "504 Option not supported") y, si el
servidor no tiene MLSD, LIST. Lanza ftplib.error_perm 550 si la carpeta no existe."""
import time as _t
out = []
# Primero se entra en la carpeta y se lista "lo de aqui": ftpsrv no hace caso a la ruta de
# MLSD/LIST y devolvia la carpeta actual (la raiz de la PS5). Si no existe, CWD da 550.
f.cwd(path)
try:
lines = []
f.retrlines("MLSD", lines.append)
for ln in lines:
facts_s, _, name = ln.partition(" ")
if not name or name in (".", ".."):
continue
facts = {}
for kv in facts_s.split(";"):
k, _, v = kv.partition("=")
if k:
facts[k.lower()] = v
t = facts.get("type", "").lower()
if t not in ("file", "dir"):
continue
mt = facts.get("modify")
try:
mt = int(_t.mktime(_t.strptime(mt[:14], "%Y%m%d%H%M%S"))) if mt else None
except Exception:
mt = None
mode = facts.get("unix.mode")
try:
mode = int(mode, 8) if mode else None
except ValueError:
mode = None
try:
size = int(facts.get("size") or 0)
except ValueError:
size = 0
out.append((name, {"type": t, "size": size, "mtime": mt, "mode": mode}))
return out
except ftplib.error_perm as e:
if str(e).startswith("550"):
raise
finally:
try:
f.voidcmd("TYPE I")
except Exception:
pass
# servidor sin MLSD: LIST al estilo "ls -l"
lines = []
try:
f.retrlines("LIST", lines.append)
finally:
try:
f.voidcmd("TYPE I")
except Exception:
pass
for ln in lines:
parts = ln.split(None, 8)
if len(parts) < 9 or parts[8] in (".", ".."):
continue
kind = "dir" if ln.startswith("d") else ("file" if ln.startswith("-") else None)
if not kind:
continue
try:
size = int(parts[4])
except ValueError:
size = 0
out.append((parts[8], {"type": kind, "size": size, "mtime": _list_mtime(parts[5], parts[6], parts[7]),
"mode": _list_mode(parts[0])}))
return out
def ftp_sizes(f, path):
"""{nombre: tamano} de los archivos de una carpeta remota (None si no existe)."""
try:
return _ftp_sizes(f, path)
finally:
try:
f.voidcmd("TYPE I") # MLSD/LIST dejan la conexion en ASCII y REST fallaria
except Exception:
pass
def _ftp_sizes(f, path):
try:
ents = ftp_listdir(f, path)
except ftplib.error_perm:
return None
return {n: x["size"] for n, x in ents if x["type"] == "file"}
def upload_tree(cfg, src, remote_root, cancel, log, progress, workers=None, on_plan=None):
"""Manda una FolderSource a remote_root. Salta los archivos que ya estan con el mismo
tamano, continua los que se cortaron (mas pequenos) y vuelve a mandar los demas.
Usa varias conexiones a la vez (cfg parallel_files). progress(bytes_hechos, ruta_actual).
on_plan(bytes_que_faltan), si se da, se llama tras comparar y antes de enviar nada
(para comprobar el espacio libre); puede lanzar una excepcion para no seguir.
Devuelve (enviados, saltados, continuados)."""
import queue
by_dir = {}
for rel, size in src.files:
d, _, n = rel.rpartition("/")
by_dir.setdefault(d, []).append((n, size, rel))
workers = max(1, min(4, int(workers or cfg.get("parallel_files", 2) or 1)))
lock = threading.Lock()
st = {"done": 0, "sent": 0, "skipped": 0, "resumed": 0, "err": None}
tasks = queue.Queue()
# 1) una sola conexion: crear carpetas y ver que hay ya en la consola
w = _FtpWriter(cfg, cancel, log)
try:
w.mkdir(remote_root)
for d in src.dirs:
w.mkdir(remote_root + "/" + d)
for d in sorted(by_dir):
rdir = remote_root + ("/" + d if d else "")
w.mkdir(rdir)
have = w._retry(lambda: ftp_sizes(w.f, rdir)) or {}
for name, size, rel in by_dir[d]:
got = have.get(name)
if got == size:
st["skipped"] += 1
st["done"] += size
continue
offset = got if (got is not None and 0 < got < size) else 0
st["done"] += offset # lo que ya habia en la consola cuenta como hecho
tasks.put((rdir + "/" + name, rel, size, offset))
finally:
w.close()
if on_plan is not None:
on_plan(max(0, src.size - st["done"]))
progress(st["done"], "")
if tasks.empty():
return 0, st["skipped"], 0
# 2) varias conexiones subiendo archivos a la vez
def worker():
ww = _FtpWriter(cfg, cancel, log)
try:
while st["err"] is None:
try:
rpath, rel, size, offset = tasks.get_nowait()
except queue.Empty:
return
if cancel.is_set():
raise Cancelled()
if offset:
with lock:
st["resumed"] += 1
log("Continuando %s desde %s MB" % (rel, offset // MiB))
local = os.path.join(src.path, *rel.split("/"))
ww.begin(rpath, offset)
pos = offset
with open(local, "rb") as fh:
fh.seek(offset)
while True:
if cancel.is_set() or st["err"] is not None:
raise Cancelled()
chunk = fh.read(2 * MiB)
if not chunk:
break
ww.write(chunk)
pos += len(chunk)
with lock:
st["done"] += len(chunk)
d = st["done"]
progress(d, rel)
ww.end(size)
with lock:
st["sent"] += 1
except Exception as e:
with lock:
if st["err"] is None:
st["err"] = e
finally:
ww.close()
ths = [threading.Thread(target=worker, daemon=True) for _ in range(min(workers, tasks.qsize()))]
for t in ths:
t.start()
for t in ths:
t.join()
if st["err"] is not None:
if cancel.is_set() or isinstance(st["err"], Cancelled):
raise Cancelled()
raise st["err"]
return st["sent"], st["skipped"], st["resumed"]
def ftp_download(cfg, remote, local, cancel, progress, size=None):
"""Baja un archivo de la PS5 al PC (continua si ya hay un .part)."""
os.makedirs(os.path.dirname(local) or ".", exist_ok=True)
part = local + ".part"
retries = int(cfg.get("retries", 8))
for attempt in range(retries + 1):
if cancel.is_set():
raise Cancelled()
off = os.path.getsize(part) if os.path.isfile(part) else 0
f = None
try:
f = Ftp(cfg).connect()
with open(part, "ab") as fh:
state = {"n": off}
def cb(data):
if cancel.is_set():
raise Cancelled()
fh.write(data)
state["n"] += len(data)
progress(state["n"])
f.retrbinary("RETR " + remote, cb, blocksize=MiB, rest=off or None)
if size is not None and os.path.getsize(part) != size:
raise PipeError("descarga incompleta")
os.replace(part, local)
return
except Cancelled:
raise
except Exception as e:
if attempt >= retries:
raise PipeError("No pude bajar %s: %s" % (remote, e))
time.sleep(min(30, 2 * (attempt + 1)))
finally:
if f is not None:
try:
f.close()
except Exception:
pass
def concat_stream(parts, offset, cfg, cancel, meter):
"""Lee varias fuentes como si fueran un unico archivo (para unir .001 .002 ...)."""
base = 0
@@ -516,9 +1036,39 @@ def concat_stream(parts, offset, cfg, cancel, meter):
# FTP de la PS5
# ---------------------------------------------------------------------------
def clean_host(text):
"""Deja solo la IP/nombre de la PS5 aunque se escriba con espacios, ftp://, puerto o
comas: ' ftp://192,168,1,50:2121/ ' -> ('192.168.1.50', 2121)."""
t = re.sub(r"[\s\u200b\u00a0\ufeff]+", "", str(text or ""))
t = re.sub(r"^[a-z][a-z0-9+.-]*://", "", t, flags=re.I)
t = t.split("/", 1)[0].split("@")[-1]
port = None
m = re.match(r"^(.*?):(\d{1,5})$", t)
if m and m.group(1).count(":") == 0:
t, port = m.group(1), int(m.group(2))
if re.fullmatch(r"[\d,.]+", t):
t = t.replace(",", ".")
return t.strip(".").strip("[]"), port
def raw_mode(f):
"""ftpsrv (ps5-payload-dev) descifra al vuelo los SELF (eboot.bin, .prx, .sprx): al bajarlos
llega el ELF de dentro, con otro tamano, y los listados tambien dan ese tamano. Su comando
SELF lo activa/desactiva en cada conexion: lo dejamos apagado para ver los archivos tal
cual estan. Los servidores que no lo conocen responden con error y no pasa nada.
(Gracias a RichyMX por encontrarlo.)"""
try:
r = f.sendcmd("SELF")
if "enabled" in r.lower():
r = f.sendcmd("SELF")
return "disabled" in r.lower()
except ftplib.all_errors:
return False
class Ftp:
def __init__(self, cfg):
self.host = cfg["ps5_ip"]
self.host = clean_host(cfg["ps5_ip"])[0]
self.port = int(cfg.get("ftp_port", 2121))
self.user = cfg.get("ftp_user") or "anonymous"
self.pw = cfg.get("ftp_pass") or ""
@@ -528,10 +1078,15 @@ class Ftp:
raise PipeError("Falta la IP de la PS5: ponla en Ajustes")
f = ftplib.FTP()
f.encoding = "utf-8"
f.connect(self.host, self.port, timeout=30)
try:
f.connect(self.host, self.port, timeout=30)
except socket.gaierror:
raise PipeError("La IP de la PS5 no es valida (%s): en Ajustes escribe solo los numeros, "
"por ejemplo 192.168.1.50, sin ftp:// ni puerto" % self.host)
f.login(self.user, self.pw)
f.set_pasv(True)
f.voidcmd("TYPE I")
raw_mode(f)
try:
f.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
except Exception:
@@ -679,7 +1234,7 @@ def upload(cfg, remote_final, total, make_iter, progress, cancel, log, resume=Tr
class BFpilot:
def __init__(self, cfg):
self.base = "http://%s:%s" % (cfg["ps5_ip"], int(cfg.get("bf_port", 5905)))
self.base = "http://%s:%s" % (clean_host(cfg["ps5_ip"])[0], int(cfg.get("bf_port", 5905)))
self.cfg = cfg
def _req(self, method, path, params=None, form=None, timeout=20):
@@ -802,11 +1357,16 @@ class BFpilot:
except Exception:
return ""
def wait_job(self, cancel, timeout=3600):
def wait_job(self, cancel, timeout=3600, on_tick=None):
t0 = time.time()
while time.time() - t0 < timeout:
if cancel is not None and cancel.is_set():
raise Cancelled()
if on_tick is not None:
try:
on_tick()
except Exception:
pass
j = self._req("GET", "/api/fs/job/status")
if not j.get("busy"):
if j.get("error"):
@@ -815,7 +1375,7 @@ class BFpilot:
time.sleep(1)
raise PipeError("BFpilot tarda demasiado")
def delete(self, path, cancel=None):
def delete(self, path, cancel=None, on_tick=None):
for _ in range(60):
try:
self._req("POST", "/api/fs/delete", form={"path": path, "recursive": "1"})
@@ -827,12 +1387,12 @@ class BFpilot:
if "No such file" in str(e) or "not found" in str(e).lower():
return
raise
self.wait_job(cancel)
self.wait_job(cancel, timeout=4 * 3600, on_tick=on_tick)
def du(self, path):
def du(self, path, timeout=20):
"""Tamano total de una carpeta (o archivo), o None."""
try:
return int(self._req("GET", "/api/fs/du", {"path": path}).get("size") or 0)
return int(self._req("GET", "/api/fs/du", {"path": path}, timeout=timeout).get("size") or 0)
except Exception:
return None
@@ -1047,18 +1607,18 @@ class _FtpWriter:
else:
c = self.f.transfercmd("STOR " + path)
try:
c.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2 * MiB)
c.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 4 * MiB)
except Exception:
pass
return c
def begin(self, path):
def begin(self, path, offset=0):
self.path = path
self.sent = 0
self.sent = offset
self.tail = deque()
self.tail_len = 0
self.mkdir(path.rsplit("/", 1)[0] or "/")
self.conn = self._retry(lambda: self._open_data(path, 0))
self.conn = self._retry(lambda: self._open_data(path, offset))
def _remember(self, data):
self.tail.append(data)
@@ -1231,3 +1791,76 @@ def stream_extract_7z(exe, archive, entries, password, remote_root, cfg, cancel,
proc.kill()
except Exception:
pass
class _CountReader:
"""Envuelve un archivo y cuenta lo leido (para el progreso del .tar.gz)."""
def __init__(self, f):
self.f, self.n = f, 0
def read(self, k=-1):
d = self.f.read(k)
self.n += len(d)
return d
def stream_extract_tar(path, remote_root, cfg, cancel, log, progress, on_file=None, skip=0):
"""Descomprime un .tar / .tar.gz / .tar.bz2 / .tar.xz del PC sobre la marcha y sube cada
archivo a remote_root. progress(bytes_del_comprimido_leidos, total_comprimido, ruta).
skip: miembros ya subidos antes (se leen y se descartan).
Devuelve (archivos, bytes, {ruta de sce_sys/param.json: contenido})."""
import tarfile
total = os.path.getsize(path)
nfiles = nbytes = 0
params = {}
w = _FtpWriter(cfg, cancel, log)
try:
with open(path, "rb") as raw:
cr = _CountReader(raw)
with tarfile.open(fileobj=cr, mode="r|*") as tf:
for i, m in enumerate(tf):
if cancel.is_set():
raise Cancelled()
parts = [x for x in m.name.replace("\\", "/").split("/") if x not in ("", ".")]
if not parts or ".." in parts:
raise PipeError("Ruta peligrosa dentro del comprimido: %s" % m.name)
remote = remote_root + "/" + "/".join(parts)
rel = "/".join(parts)
if m.isfile() and rel.lower().endswith("sce_sys/param.json") and m.size < MiB:
params[rel] = tf.extractfile(m).read()
if i < skip:
continue
w.begin(remote)
w.write(params[rel])
w.end(m.size)
nfiles += 1
nbytes += m.size
if on_file:
on_file(i + 1)
continue
if i < skip:
continue
if m.isdir():
w.mkdir(remote)
elif m.isfile():
fh = tf.extractfile(m)
w.begin(remote)
while True:
data = fh.read(4 * MiB)
if not data:
break
w.write(data)
progress(cr.n, total, m.name)
w.end(m.size)
nfiles += 1
nbytes += m.size
else:
log("Me salto %s (enlace o archivo especial)" % m.name)
if on_file:
on_file(i + 1)
progress(cr.n, total, m.name)
except tarfile.TarError as e:
raise PipeError("El .tar esta danado o no es un tar: %s" % e)
finally:
w.close()
return nfiles, nbytes, params
+17 -3
View File
@@ -1,3 +1,4 @@
const EN = !(navigator.language || "es").toLowerCase().startsWith("es");
// PS5 Directo - captura de enlaces.
// Cuando el navegador empieza a descargar un archivo comprimido o paquete (.rar, .7z, .zip, .pkg...),
// manda el enlace FINAL (despues de redirecciones) a PS5 Directo y cancela la descarga.
@@ -43,11 +44,24 @@ async function handle(item) {
chrome.action.setBadgeText({ text: "off" });
return;
}
// Como los gestores de descargas: pasamos las cookies de ese alojamiento (sesion, cuenta
// premium), el navegador y la pagina de origen, para que el servidor nos trate igual.
// Solo van a PS5 Directo en este PC (127.0.0.1), a ningun otro sitio.
const cookies = {};
for (const u of [url, item.url]) {
try {
const host = new URL(u).host.toLowerCase();
if (host in cookies) continue;
const list = await chrome.cookies.getAll({ url: u });
cookies[host] = list.map(c => `${c.name}=${c.value}`).join("; ");
} catch (e) { /* sin permiso o enlace raro: sin cookies */ }
}
try {
const r = await fetch(`http://127.0.0.1:${app.port}/api/ext/capture`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url, original: item.url, name })
body: JSON.stringify({ url, original: item.url, name, cookies,
ua: navigator.userAgent, referrer: item.referrer || "" })
});
if (!r.ok) return;
} catch (e) { return; }
@@ -58,8 +72,8 @@ async function handle(item) {
chrome.action.setBadgeBackgroundColor({ color: "#2563eb" });
chrome.action.setBadgeText({ text: String(n % 1000) });
chrome.notifications.create({
type: "basic", iconUrl: "icon128.png", title: "Enviado a PS5 Directo",
message: (name || "Enlace") + " — no se descarga en el PC."
type: "basic", iconUrl: "icon128.png", title: EN ? "Sent to PS5 Directo" : "Enviado a PS5 Directo",
message: (name || (EN ? "Link" : "Enlace")) + (EN ? " — not downloaded to the PC." : " — no se descarga en el PC.")
});
}
+29 -8
View File
@@ -1,11 +1,32 @@
{
"manifest_version": 3,
"name": "PS5 Directo - Capturar enlaces",
"version": "1.0.0",
"description": "Cuando descargas un .rar/.7z/.zip/.pkg, manda el enlace a PS5 Directo en vez de bajarlo al PC.",
"permissions": ["downloads", "storage", "notifications"],
"host_permissions": ["http://127.0.0.1/*"],
"background": { "service_worker": "bg.js" },
"action": { "default_popup": "popup.html", "default_title": "PS5 Directo", "default_icon": { "16": "icon16.png", "32": "icon32.png" } },
"icons": { "16": "icon16.png", "48": "icon48.png", "128": "icon128.png" }
}
"version": "1.1.0",
"description": "Cuando descargas un .rar/.7z/.zip/.pkg, manda el enlace (con la sesion del navegador) a PS5 Directo en vez de bajarlo al PC.",
"permissions": [
"downloads",
"storage",
"notifications",
"cookies"
],
"host_permissions": [
"http://127.0.0.1/*",
"<all_urls>"
],
"background": {
"service_worker": "bg.js"
},
"action": {
"default_popup": "popup.html",
"default_title": "PS5 Directo",
"default_icon": {
"16": "icon16.png",
"32": "icon32.png"
}
},
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
}
}
+2 -2
View File
@@ -11,10 +11,10 @@ button{background:#1f2937;color:#e6edf3;border:1px solid #374151;border-radius:6
</style></head>
<body>
<h1>PS5 Directo</h1>
<div class="row"><label for="en">Capturar enlaces</label><input type="checkbox" id="en"></div>
<div class="row"><label for="en" id="lblEn">Capturar enlaces</label><input type="checkbox" id="en"></div>
<div class="st" id="st">Comprobando…</div>
<div class="st" id="cnt"></div>
<div class="row"><span></span><button id="reset">Poner contador a 0</button></div>
<small>Pasa el captcha y pulsa Descargar como siempre: si es un .rar, .7z, .zip, .pkg… y PS5 Directo está abierto, el enlace va a su cuadro de enlaces y el navegador no descarga nada. Si PS5 Directo está cerrado, la descarga sigue normal.</small>
<small id="help">Pasa el captcha y pulsa Descargar como siempre: si es un .rar, .7z, .zip, .pkg… y PS5 Directo está abierto, el enlace va a su cuadro de enlaces y el navegador no descarga nada. Si PS5 Directo está cerrado, la descarga sigue normal.</small>
<script src="popup.js"></script>
</body></html>
+19 -3
View File
@@ -1,3 +1,19 @@
const EN = !(navigator.language || "es").toLowerCase().startsWith("es");
const T = EN ? {
capture: "Capture links", checking: "Checking…", reset: "Reset counter",
help: "Pass the captcha and click Download as usual: if it's a .rar, .7z, .zip, .pkg… and PS5 Directo is open, the link goes to its link box and the browser downloads nothing. If PS5 Directo is closed, the download goes ahead normally.",
sent: "Sent", last: "last", connected: "● Connected", to: "to PS5 Directo", closed: "● PS5 Directo is not open", normal: "(downloads will work normally)"
} : {
capture: "Capturar enlaces", checking: "Comprobando…", reset: "Poner contador a 0",
help: null, sent: "Enviados", last: "último", connected: "● Conectado", to: "a PS5 Directo", closed: "● PS5 Directo no está abierto", normal: "(las descargas seguirán normales)"
};
if (EN) {
document.documentElement.lang = "en";
document.getElementById("lblEn").textContent = T.capture;
document.getElementById("st").textContent = T.checking;
document.getElementById("reset").textContent = T.reset;
document.getElementById("help").textContent = T.help;
}
async function findApp() {
for (const port of [8777, 8778, 8779]) {
try {
@@ -13,7 +29,7 @@ async function findApp() {
en.checked = cfg.enabled;
en.onchange = () => chrome.storage.local.set({ enabled: en.checked });
document.getElementById("cnt").textContent =
cfg.captured ? `Enviados: ${cfg.captured}${cfg.last ? " (último: " + cfg.last + ")" : ""}` : "";
cfg.captured ? `${T.sent}: ${cfg.captured}${cfg.last ? " (" + T.last + ": " + cfg.last + ")" : ""}` : "";
document.getElementById("reset").onclick = async () => {
await chrome.storage.local.set({ captured: 0, last: "" });
chrome.action.setBadgeText({ text: "" });
@@ -21,6 +37,6 @@ async function findApp() {
};
const app = await findApp();
const st = document.getElementById("st");
if (app) { st.innerHTML = `<span class="ok">● Conectado</span> a PS5 Directo v${app.version}`; chrome.action.setBadgeText({ text: "" }); }
else st.innerHTML = '<span class="bad">● PS5 Directo no está abierto</span> (las descargas seguirán normales)';
if (app) { st.innerHTML = `<span class="ok">${T.connected}</span> ${T.to} v${app.version}`; chrome.action.setBadgeText({ text: "" }); }
else st.innerHTML = `<span class="bad">${T.closed}</span> ${T.normal}`;
})();
+1333
View File
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

+2303 -50
View File
File diff suppressed because it is too large. Load diff