Como he comentado en muchas ocasiones, juego videojuegos en mis múltiples PlayStations en gran medida por el placer que siento al obtener los trofeos que se otorgan al cumplir ciertos requisitos; y especialmente cuando obtengo el 100% de los mismos, generalmente alcanzando ese 100% cuando consigo el trofeo de platino de algún juego en particular.
Desde hace años (poco menos de una década) tengo una aplicación de escritorio escrita en Gtk que me permite no nada más ver los trofeos que he obtenido; también me permite visualizar múltiples estadísticas y gráficas, así como ayudarme a decidir qué voy a jugar en lo inmediato, señalándome qué juegos tengo disponibles con trofeos fáciles o de los juegos que he jugado qué trofeos son los más sencillos en obtener.
PlayStation Network Trophies
Después de que excomulgaron mi cuenta original, mi aplicación es todavía más importante para mí, porque es la que me permite mezclar mis dos cuentas en una cuenta virtual y así llevar el seguimiento de mis trofeos en mi cuenta original excomulgada y mi cuenta actual en activo.
PlayStation Network Trophies
Ahora, la aplicación está escrita en Vala con Gtk, pero un componente importante está escrito en PHP porque no quería estar descargando de la fuente original toda la información en las múltiples computadoras que uso, especialmente las imágenes de los juegos y los iconos de los trofeos (que ocupan poco más de 4 gigabytes para los juegos que he registrado hasta el momento), así que hice una API REST y realmente todo eso está en mi servidor (así como la base de datos maestra) y mi aplicación Gtk sólo se sincroniza con él.
Sin embargo, nada de esto explica de dónde sale toda esa información: no únicamente los nombres e imágenes de videojuegos y trofeos, así como sus descripciones y las fechas en que los obtuve, sino cosas más complicadas como qué determina que un trofeo sea o no fácil o difícil de obtener.
Y la respuesta es muy sencilla: originalmente todo venía de PSNProfiles.
El sitio tiene décadas (bueno, quince años) llevando la información de millones de ususarios de la PlayStation Network (aunque no todos). Uno puede usar el sitio gratuitamente con anuncios, pero pagando una módica cantidad (una única vez), los anuncios desaparecen.
Yo pagué; dos veces, una por cada cuenta.
Como sea, lo que comencé a hacer fue sencillamente minar las páginas de PSNProfiles con un programita que yo escribí; inicialmente analizando el HTML a mano buscando cadenas crudas como un troglodita y eventualmente evolucionando al pasar mi programita minero (que está escrito en Python) a que usara BeautifulSoup.
No fui el primero (ni el último) en hacer algo de este estilo; existen varias bibliotecas que hacen exactamente lo mismo.
En su cénit, mi sistema era bastante avanzado: usando mi cliente Gtk yo solicitaba que se minara un nuevo juego (u ocurría automáticamente si ganaba algún trofeo de un juego que no huviera minado anteriormente), lo cual disparaba un método REST que mi servidor recibía y que causaba que se ejecutara mi minero (también en el servidor, pero de forma independiente), incluyendo descargar todas las imágenes correspondientes, y mi cliente Gtk podía sondear (poll) cómo iba este proceso; al terminar el cliente solicitaba la actualización de la base de datos junto con las imágenes correspondientes (que se guardaban en una copia local, por supuesto). La idea era tener que molestar a PSNProfiles lo menos posible; por eso mi servidor en medio.
Funcionaba bastante bien. Demasiado bien; no sé si fuimos todos los que minábamos al pobre sitio de PSNProfiles, o yo en particular (yo minaba juegos que no hubiera jugado, pero que tenía el disco o digitalmente, para justo poder determinar qué juegos iba a jugar más adelante), pero eventualmente se hartaron de nosotros/mí, e implementaron prevención de falsificación de solicitudes entre sitios, también conocida como CSRF por sus siglas en inglés (Cross-Site Request Forgery prevention).
Esto me llevó como cinco minutos darle la vuelta, porque no es terriblemente complicado; básicamente hay que registrar algunos encabezados de HTTP y retransmitirlos. Entonces seguí usando mi sistema.
Acto seguido PSNProfiles contrató Cloudflare, que es un servicio de red de distribución de contenidos o CDN (Content Distribution Network), que además de tratar de detectar cuándo alguien está minando un sitio, ofrece protección contra ataques DDoS y cosas por el estilo. Que, quiero enérgicamente enfatizar, yo no estaba haciendo nada particularmente dañino; además de que nunca miné de múltiples computadoras el sitio (para eso justamente usaba mi servidor), no es como si hubiera tratado de descargar todo el sitio, yo sólo quería la información de mis trofeos y de los potenciales juegos que en el futuro pudiera jugar.
El uso del sitio por mi programa era comparable al que hubiera resultado de que yo usara el sitio normalmente; y de hecho generaba menos tráfico porque una vez minadas las imágenes, yo ya no volvía a hacer solicitudes a PSNProfiles. Y no es como que perdieran dinero por la publicidad que yo no veía; como mencioné, yo pagué por quitar anuncios, así que de por sí no los veo.
Como sea, sí miné un chingo de juegos; desde que tengo PlayStation Plus Premium, tengo disponibles cerca de 1,500 videojuegos, pero los mismos siguen siendo una fracción de los más de 30,000 juegos que tienen trofeos para la PlayStation Network. Por no mencionar que nunca miné la información de algún otro de los millones de usuarios del sitio: ¿para qué haría eso?
Como sea, Cloudfare es básicamente imposible de brincar, porque encima de todo cada cierto tiempo (desesperantemente cada par de horas, al parecer), pide que uno resuelva un captcha, que aunque hay prototipos de cómo superarlos automáticamente, los mismos suelen ser rotos cada quince minutos, porque es un juego del gato y el ratón entre Cloudfare y múltiples monos que quieren poder minar información en la red; Cloudfare es usado por miles de sitios en internet.
Eventualmente terminé escribiendo algunos scripts de Tampermonkey, que usando JavaScript inyectan básicamente lo que uno quiera de un sitio en la red en el navegador. Entonces manualmente tenía que minar mi cuenta o un juego desde mi navegador, mi script me hacía un lindo Zip ya con todo el HTML que necesitara de PSNProfiles, y yo le pasaba esa información a mi servidor para que hacer todo lo demás funcionara automáticamente. Más engorroso que si todo fuera 100% en automático, pero manejable.
Hasta este momento, varios de ustedes, queridos lectores, se han de estar preguntando por qué no sencillamente minaba la información de Sony directamente. La respuesta es muy sencilla: uno, era muy engorroso; y dos, la información recibida estaba incompleta. O al menos así era cuando lo investigué la década pasada.
Para poder minar la información de Sony varios monos en la red se pusieron a olfatear la comunicación entre los PlayStations o las aplicaciones móviles de PlayStation con la nave nodriza, y usando diúrex y salivita armaron una API que era medio engorrosa, pero usable. La API necesitaba varios datos que requerían que uno se conectara vía un navegador con una cuenta válida de PlayStation, ejecutara en la consola JavaScript varios comandos y sacara del resultado esos datos para el sistema que quisiera usar la API: esta era la parte engorrosa.
La parte de que la información fuera incompleta radicaba en el hecho de que, desde sus inicios, los trofeos de PlayStation tienen la capacidad de ser secretos; para que un jugador que esté checando la lista de trofeos no se le vaya a arruinar una sorpresa (spoilers!) al leerlos. En su infinita sabiduría, los de Sony decidieron que la información de trofeos secretos no se transmitiría a las aplicaciones que los solicitaran, excepto obviamente el hecho de que existían y eran secretos. Además, uno nada más podía consultar información de los trofeos en juegos que su usuario autenticado hubiera jugado.
Este era el estado de las cosas la década pasada; y yo no había tenido la necesidad de verificar si las cosas seguían igual o no, porque mi sistema que minaba PSNProfiles sencillamente funcionaba. Incluso cuando implementaron CSFR y después al pasarse a Cloudfare, yo conseguí que mi sistema siguiera funcionando, aunque fuera evadiendo obstáculos.
Hasta hace unas semanas.
Hace menos de un mes, descubrí que PSNProfiles ya no permite ni siquiera bajar páginas usando un script de Tampermonkey; casualmente lo descubrí mientras estaba minando todavía más juegos: como resulta que puedo ver mi biblioteca de juegos disponibles en la PlayStation Network a través del navegador, y existe un userscript que permite exportar esto a JSON, pues me puse a ligar en su totalidad todos los juegos que tenía minados en mi sistema con los juegos en mi biblioteca… y para eso debía minarlos primero.
Mis scripts de Tampermonkey lo que hacían era guardar la página minada (generalmente mi perfil) junto con las páginas ligadas dentro de la página minada (generalmente los juegos individuales de mi cuenta). Bueno, PSNProfiles ya no permite descargar una página que sea ligada de otra página en el sitio: cuando uno carga una página, las misma es mínima, teniendo únicamente algo de JavaScript que genera un URL con un párametro GET con una dispersión (hash) que sirve como desafío para que PSNProfiles verifique que es un ser humano el que siguió la liga. El JavaScript después cambia la ubicación del navegador al URL.
Ahora, esto es superable; tendría que hacerle trutrú al HTML recibido para interpretar el código JavaScript que genera la dispersión (se genera en el cliente; no tendría sentido si nada más lo enviara planamente el servidor), o en el peor de los casos literalmente levantar una máquina virtual de JavaScript para que lo hiciera por mí… pero se estaba poniendo ridículo el asunto. Y encima ahora PSNProfiles ya ni siquiera me permite crear un script para guardar el HTML que ya está en mi navegador y de hecho nada que esté con el tipo de contenido HTML (Content-Type, es un encabezado del protocolo HTTP(S)), aunque sigue funcionando salvar una página manualmente, porque me parece que es básicamente imposible que eviten que eso se pueda hacer.
En general todo este tejemaneje es medio absurdo, porque todo funciona para mí incluso si tengo que salvar las páginas de los juegos manualmente; en general sólo es necesario hacerlo una vez, porque lo peor que ocurre es que ciertas estadísticas (por ejemplo, el porcentaje de jugadores que obtienen un trofeo) se vuelven ligeramente desfasadas, lo cual no es muy grave dado que casi nunca juego juegos que acaben de salir: las estadísticas por definición se van estabilizando a lo largo de la vida de un juego y eventualmente casi no cambian, excepto por algunas centécimas de puntos porcentuales.
Sin embargo, en la página que uno guarda con la información de un juego sólo vienen ligas a las imágenes de los trofeos en resoluciones “pequeña” y “mediana”, que es la terminología que PSNProfiles se inventó: la liga a la imagen del trofeo en resolución “grande” está en la página del trofeo mismo. Y sí estoy dispuesto a guardar las páginas de mis juegos; incluso si son 1,500, lo puedo hacer de manera paulatina porque, como ya expliqué, sólo necesito hacerlo una vez. Lo que no estoy dispuesto a hacer es guardar las páginas de las decenas de miles de trofeos que me interesa tener.
Medio harto, decidí ver alternativas: hay múltiples sitios que hacen más o menos los mismo que PSNProfiles; lamentablemente me parece que ninguno lo hace tan bien, además de que mi sistema está bastante amarrado a PSNProfiles. Por ejemplo, el identificador único para cada juego es el mismo en mi sistema que en el sitio, y aunque podría cambiarlo, la tarea sería pesada, vamos a decir.
Estaba a punto de mandar todo al carajo cuando me dije a mí mismo: “mí mismo, vamos a ver si han habido avances en la API para conectarse con Sony directamente”. Y sorpresivamente, resulta que sí ha habido avances, al parecer impulsados entre otras cosas por la introducción del PlayStation 5 y que ahora algunos trofeos pueden reportar el avance que lleva el usuario para obtenerlos. Esto obligó a Sony a actualizar su protocolo de comunicación, y el mismo es mucho más sencillo.
Sigue siendo todavía algo engorroso, pero mucho menos: uno sólo necesita una cookie del navegador para que todo funcione, y la misma parece tardar mucho en expirar. Además hay que generar una ficha (token) que expira más o menos cada 10 horas; pero es trivial automatizar el cómo obtener una nueva. O bueno, a mí me resultó muy fácil automatizarlo.
Y mejor aún, el problema de que no estuviera completa la información, para motivos prácticos, ha desaparecido: no sólo se puede obtener toda la información de un trofeo (incluyendo el hecho de si es o no secreto); además, me llevó un par de horas descubrir que puedo minar todos los juegos de Sony. Incluyendo imágenes de juegos y trofeos en alta resolución, equivalente a las de PSNProfiles. Lo que es más; puedo minar mi perfil con toda la información que necesito; y también la de cualquier usuario en la PlayStation Network (si la tiene pública). La única restricción es que, en promedio, uno no debe hacer más de una consulta cada 3 segundos.
El único problema es saber el identificador del juego que uno quiere descargar. En la misma biblioteca de Sony (la que uso el userscript para descargarla del sitio de Sony) aparecen identificadores, normalmente de la forma CUSA
, como CUSA01623
para la versión remasterizada de God of War 3 para el PlayStation 4; o de la forma PPSA
, como PPSA08329
para la versión de God of War Ragnarök para el PlayStation 5. Sin embargo, los identificadores que la API necesita para sacar información de juegos, trofeos y progreso de un jugador, están en un formato NPWR
; por ejemplo, para la versión de God of War Ragnarök del PlayStation 5, el identificador es NPWR22392
.
Hay una manera de obtener el identificador NPWR
si uno tiene el identificador CUSA
; lamentablemente, sólo sirve si se tienen registrados trofeos de ese juego (lo que la hace inútil: si los tengo registrados, usando la nueva API puedo obtener la lista de mis juegos ya con el NPWR incluido). Hay listas en internet con múltiples identificadores NPWR
, además de otros sitios que permiten consultar algunos identificadores; pero no todos: por definición todos estos sitios siempre tendrán información incompleta.
Estaba ponderando cómo hacer esto sin usar fuerza bruta, cuando de repente me dije a mí mismo: “mí mismo, ¿por qué no usamos fuerza bruta?”. Los identificadores NPWR
tienen todos 5 dígitos decimales, y al parecer todavía no aparece ningún título en el rango de 50000… entonces sólo tenía que ir haciendo peticiones a la API desde NPWR00000
hasta NPWR49999
; si el API me daba la información, ya ganaba; si me decía que no existe; también ganaba porque ese dato también lo registraba.
Así que procedí a hacer eso: nunca miné todo PSNProfiles, por respeto al sitio; pero que se pudran los de Sony, pueden lidiar con el tráfico, además de que como dije la API tiene límite de peticiones. Pero pues para alguien como yo el hacer un script que descargue todos los juegos de PlayStation a un promedio de uno cada 3 segundos es trivial.
Me llevó algunos días minar todo dejando correr mi script 24×7; según los resultados de mi minado, hay 30,370 conjuntos de trofeos; cada uno no corresponde exactamente a un juego, porque a veces un juego tiene mútliples conjuntos de trofeos, especialmente para distintas regiones en el mundo. No miné todas las imágenes (serían decenas de gigabytes de información); sólo descargué las imágenes de los juegos en mi colección.
Y por supuesto Sony agrega nuevos conjuntos de trofeos cada semana; y desesperantemente no es secuencial el asunto, a veces usan un número de 5 dígitos menor al máximo existente, aunque nunca muchísimo menor: el último que tengo registrado es NPWR48850
, pero el último que fue agregado (que me interese) es NPWR47231
para Infinity Nikki, que, no bromeo, me muero de ganas de jugar.
Estoy seriamente pensando en dejar de molestar a PSNProfiles y usar exclusivamente la información de Sony; en general tiene todo lo que necesito, nada más la de PSNProfiles tiene más sentido. PSNProfiles hace una labor de curación en los jugadores a los que rastrea; por ejemplo da de baja a los jugadores que obviamente hacen trampas si las mismas son para poder obtener muchos trofeos de golpe (por ejemplo, al editar juegos salvados de otros jugadores). También para motivos prácticos ignora cuentas que casi no tienen trofeos y que probablemente sean cuentas alternativas de algunos usuarios.
Sony no hace nada de esto, entonces los porcentajes que muestran sus trofeos son más dudosos; en particular, los promedios de obtención de un trofeo suelen no tener el menor sentido: juegos muy fáciles no es raro que reporten trofeos que menos del 1% de los usuarios los han obtenido. Si todos los trofeos son difíciles, entonces ningún trofeo es difícil.
Así que, por ahora, tuve que resolver el obtener información de PSNProfiles, de preferencia sin tener que salvar la página manualmente, porque sí me interesan sus porcentajes de obtención de trofeos. La solución fue relativamente sencilla: PSNProfiles no permite que uno salve con un script una página del sitio; pero no tiene problemas en que uno construya manualmente una cadena y esa cadena se guarde, siempre y cuando el tipo de contenido no sea HTML.
Así que sencillamente traduje mi programa minero a JavaScript y ahora directamente mino del navegador con un userscript, guardando (con nada más picar un botón) un JSON con la información que me interesa. Este estúpido programa minero ya van como siete veces que lo reescribo, y si no me equivoco es el tercer lenguaje de programación que utilizo para hacerlo: la primera versión con Python, la segunda con Vala porque se me ocurrió que tenía sentido (no lo tenía) y ahora JavaScript. Dato interesante: PSNProfiles, para motivos prácticos, no haya actualizado sustancialmente el formato de sus páginas en todos estos años.
A largo plazo (muy largo plazo) creo que sí me mudaré por completo a usar la información de Sony nada más; no sólo así dejaré de molestar a PSNProfiles, sino que pues es eliminar intermediarios. Saber qué juegos son muy fáciles o muy difíciles obtener todos los trofeos sí me interesa, pero me parece que podré encontrar una fuente de información alterna y que no se ponga tanto los moños como PSNProfiles con su CSFR y Cloudfare. Pero pues sí será una reescritura significativa de mi sistema y ahorita no tengo tiempo de hacerla.
He completado al 100% 152 juegos en mis PlayStations; 112 de ellos con trofeo de platino. En total, he obtenido 5,969 trofeos en poco más de 16 años que llevo jugando en PlayStation, lo que me da un promedio de apenas más de un trofeo por día (1.01, según mi programa). Lo cual me parece razonable.
Sony acaba de sacar el PS5Pro y esto probablemente le dé cerca de un quinquenio extra a la quinta generación de la consola; eventualmente saldrá el PS6 y la comunicación que hacen PS3s y PS4s con la nave nodriza se desfasará y entonces Sony probablemente cambie de nuevo el protocolo.
Pero mientras ese día llega, yo ya tengo una manera de poder obtener toda la información de mis trofeos que me interesa para que funcione mi programita; casi toda de Sony, pero una parte todavía de PSNProfiles (aunque estoy buscando fuentes alternas). Vamos a ver cuánto tiempo permanece funcionando.
Imprimir entrada