Kheys
423
modifications
(correction d'informations devenues erronées) |
|||
| (49 versions intermédiaires par 5 utilisateurs non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
{{Bannière Info|Contenu=Cette page documente l'API v4 de jeuxvideo.com. Le fonctionnement du site est quant à lui détaillé sur [[Fonctionnement technique de Jeuxvideo.com]].}} | |||
L'API | L''''API de [[jeuxvideo.com]]''', conçue par les développeurs du site pour l'application mobile, permet de programmatiser l'envoi de requêtes à JVC. | ||
Étant à l'origine réservée à un usage privé, on ne dispose pas de sa documentation officielle. Toutefois, il est possible de détailler son fonctionnement grâce à un travail de rétro-ingéniérie. | |||
L'API | En juin 2025, l'API est hébergée sur le sous-domaine ''api'', et est à sa quatrième version (''v4''). | ||
L'ancienne API ''jvc.gg'' était hébergée à ''api.jvc.gg'' jusqu'à son abandon en février 2025. Elle était utilisée par les pages Phoenix du site, notamment pour la recherche des jeux. Sa documentation (non-officielle) est toujours consultable sur cet article. | |||
Les anciennes versions sont toujours exploitables avec les ''tokens'' qui leur sont propres{{Commentaire|Autre=très probablement obsolète}}, mais certains ''endpoints'' renvoient des erreurs HTTP 403. | |||
<div id="jvclient"></div> | |||
=JVClient= | |||
[[File:icon-512x512.png|vignette|256px|Le logo de JVClient : « Le pouvoir par les données ».]] | |||
[https://www.npmjs.com/package/jv-client '''JVClient'''] est une '''librairie Node.js''' écrite en TypeScript qui fournit des classes et des fonctions permettant d'interagir avec l'API v4 de jeuxvideo.com ainsi que le site JVC lui-même. | |||
Publiée en février 2025, son objectif est de servir de base aux programmeurs pour le ''scraping'' de données sur des jeux, articles, forums, topics, etc. et pour l'exécution d'opérations nécessitant un compte connecté (comme poster des topics). Le code est ''open source'' et disponible sur Github<ref>https://github.com/Contrapunctus-XIV/jv-client</ref>. | |||
Elle dispose également d'une documentation complète<ref>https://contrapunctus-xiv.github.io/jv-client/</ref> qui explique en détail l'organisation des données de jeuxvideo.com. | |||
{{clear}} | |||
=Rétro-ingénierie de l'application mobile JVC= | =Rétro-ingénierie de l'application mobile JVC= | ||
| Ligne 11 : | Ligne 27 : | ||
=== Mise en place du processus de décompilation === | === Mise en place du processus de décompilation === | ||
Pour pouvoir décompiler l'application mobile, vous aurez besoin des outils suivants : | Pour pouvoir décompiler l'application mobile, vous aurez besoin des outils suivants : | ||
* [https://www.java.com/en/download/ Java 8 ou plus] | |||
* [https://apktool.org/ apktool] | |||
* [https://github.com/skylot/jadx JADX] | |||
Il faut également le fichier ''.apk'' de l'application mobile, téléchargeable [https://apkpure.fr/fr/jeuxvideo-com-pc-et-consoles/com.jeuxvideo ici] (privilégiez les versions supérieures à la 5.4.3, sans quoi vous devrez extraire le fichier ''.xapk'' et appliquer le processus de décompilation sur le fichier ''.apk'' principal). | Il faut également le fichier ''.apk'' de l'application mobile, téléchargeable [https://apkpure.fr/fr/jeuxvideo-com-pc-et-consoles/com.jeuxvideo ici] (privilégiez les versions supérieures à la 5.4.3, sans quoi vous devrez extraire le fichier ''.xapk'' et appliquer le processus de décompilation sur le fichier ''.apk'' principal). | ||
| Ligne 26 : | Ligne 42 : | ||
=== JvApiService === | === JvApiService === | ||
Une fois le code Java disponible, on peut ouvrir | Une fois le code Java disponible, on peut ouvrir l'interface '''JvApiService''' (située dans ''com.jeuxvideo.api.web''), qui contient tous les ''endpoints''. L'application utilise le bibliothèque [https://square.github.io/retrofit/ Retrofit 2.x] pour gérer l'API, et la classe contient tous les ''endpoints'' formels de l'API. | ||
'' | ''Extrait de l'interface JvApiService'' | ||
<pre> | <pre> | ||
@POST("contents/{contentID}/comments") | @POST("contents/{contentID}/comments") | ||
| Ligne 37 : | Ligne 53 : | ||
</pre> | </pre> | ||
=== | Interface complète disponible [https://pastebin.com/WiQiutAf ici]. | ||
La classe '' | |||
=== SigningInterceptor === | |||
La classe '''SigningInterceptor''' (du package ''com.jeuxvideo.api.utils''), permet de déduire la valeur du ''header Jvc-Authorization'' à envoyer dans les requêtes à l'API. | |||
<pre> | <pre> | ||
public static String | public static String m27149f(String str, String str2, String str3, String str4, String str5) { | ||
StringBuilder sb2 = new StringBuilder(); | StringBuilder sb2 = new StringBuilder(); | ||
sb2.append("550c04bf5cb2b\n"); | sb2.append("550c04bf5cb2b\n"); | ||
| Ligne 55 : | Ligne 73 : | ||
} | } | ||
sb2.append(str5); | sb2.append(str5); | ||
String | String m14428b = CryptoUtils.m14428b("d84e9e5f191ea4ffc39c22d11c77dd6c", sb2.toString()); | ||
return "PartnerKey=550c04bf5cb2b, Signature=" + | return "PartnerKey=550c04bf5cb2b, Signature=" + m14428b + ", Timestamp=" + str; | ||
} | } | ||
</pre> | </pre> | ||
Classe complète disponible [https://pastebin.com/sMpiYDqQ ici]. | |||
=== JVApi et UserAgentInterceptor === | === JVApi et UserAgentInterceptor === | ||
''JVApi'' (du package arbitrairement nommé ''p379s3'' car nom perdu lors de la compilation) et ''UserAgentInterceptor'' (du package ''com.jeuxvideo.api.utils'') permettent de déduire le ''user-agent'' et la valeur des ''headers'' contenant des informations sur la version et la plateforme. | '''JVApi''' (du package arbitrairement nommé ''p379s3'' car nom perdu lors de la compilation) et '''UserAgentInterceptor''' (du package ''com.jeuxvideo.api.utils'') permettent de déduire le ''user-agent'' et la valeur des ''headers'' contenant des informations sur la version et la plateforme. | ||
=== JVApiManager === | === JVApiManager === | ||
La classe ''JVApiManager'' (du package arbitrairement nommé ''p379s3'' car nom perdu lors de la compilation) est celle qui envoie les requêtes à l'API. Elle permet de savoir quelles variables sont passées à la requête vers tel ''endpoint''. | La classe '''JVApiManager''' (du package arbitrairement nommé ''p379s3'' car nom perdu lors de la compilation) est celle qui envoie les requêtes à l'API. Elle permet de savoir quelles variables sont passées à la requête vers tel ''endpoint''. | ||
Classe complète disponible [https://pastebin.com/hDWMZwbq ici]. | |||
<div id="jvc-auth-header"></div> | |||
=== Le cas Jvc-Auth-Header === | === Le cas Jvc-Auth-Header === | ||
''Jvc-Auth-Header'' est le ''header'' envoyé à l'''endpoint'' nommé ''accounts/register''. Cet ''endpoint'' est crucial en ce qu'il représente l''''unique manière de créer un compte JVC sans le système reCaptcha'''. | '''Jvc-Auth-Header''' est le ''header'' envoyé à l'''endpoint'' nommé ''accounts/register''. Cet ''endpoint'' est crucial en ce qu'il représente l''''unique manière de créer un compte JVC sans le système reCaptcha'''. | ||
Il est actuellement impossible que la requête soit validée par l'API sans ce ''header''. | Il est actuellement impossible que la requête soit validée par l'API sans ce ''header''. | ||
| Ligne 73 : | Ligne 96 : | ||
Il s'avère que ''Jvc-Auth-Header'' contient le [https://stackoverflow.com/questions/37671380/what-is-fcm-token-in-firebase token FCM], un token créé par la plateforme ''FireBase'' de Google et utilisé par l'application mobile pour accéder aux bases de données. Ce token est unique à chaque appareil et est créé à chaque installation de l'application mobile. En outre, il permet à l'API de savoir si l'application a déjà effectué une requête d'inscription dans les dernières 24 heures et, le cas échéant, de bloquer les requêtes d'inscription. | Il s'avère que ''Jvc-Auth-Header'' contient le [https://stackoverflow.com/questions/37671380/what-is-fcm-token-in-firebase token FCM], un token créé par la plateforme ''FireBase'' de Google et utilisé par l'application mobile pour accéder aux bases de données. Ce token est unique à chaque appareil et est créé à chaque installation de l'application mobile. En outre, il permet à l'API de savoir si l'application a déjà effectué une requête d'inscription dans les dernières 24 heures et, le cas échéant, de bloquer les requêtes d'inscription. | ||
Il semble malheureusement impossible de générer de tels tokens « à la demande », en tout cas sans connaître les noms et clés des services FireBase dédiés à l'application. | Il semble malheureusement impossible de générer de tels tokens « à la demande », en tout cas sans connaître les noms et clés des services FireBase dédiés à l'application. Une alternative "temporaire" consisterait à spawner des Android virtualisés, d'y installer de façon automatisée l'APK de JVC, puis de créer des comptes. Mais dans ce type de contexte, ce n'est plus vraiment de la rétro-ingiénierie. | ||
<div id="interception"></div> | |||
== Interception du trafic == | == Interception du trafic == | ||
| Ligne 97 : | Ligne 122 : | ||
Vous pouvez désormais voir quelles requêtes sont passées à l'API, ainsi que les ''headers'' et ''body'' associés. Par exemple lorsque l'on se connecte : | Vous pouvez désormais voir quelles requêtes sont passées à l'API, ainsi que les ''headers'' et ''body'' associés. Par exemple lorsque l'on se connecte : | ||
[[File:http_toolkit.png| | [[File:http_toolkit.png|center|500px]] | ||
=API v4= | =API v4= | ||
| Ligne 114 : | Ligne 139 : | ||
Où ''header'' est égal à une chaîne de caractères de la forme ''"PartnerKey=partner_key, Signature=signature, Timestamp=timestamp". | Où ''header'' est égal à une chaîne de caractères de la forme ''"PartnerKey=partner_key, Signature=signature, Timestamp=timestamp". | ||
Veuillez consulter l'[[#annexe | annexe]] pour trouver un script Python permettant de créer ce ''header''. | Veuillez consulter l'[[#annexe|annexe]] pour trouver un script Python permettant de créer ce ''header''. | ||
===Authentification=== | ===Authentification=== | ||
Comme pour l'ancienne API, le cookie ''coniunctio'' est toujours le cookie de session utilisateur. Il doit être récupéré avec l'appel au point d'entrée ''accounts/login'' (voir tableau POST) puis il doit être envoyé dans une en-tête HTTP <code>"Cookie" : "coniunctio={coniunctio}"</code> pour chaque appel. | Comme pour l'ancienne API, le cookie ''coniunctio'' est toujours le cookie de session utilisateur. Il doit être récupéré avec l'appel au point d'entrée ''accounts/login'' (voir tableau POST) puis il doit être envoyé dans une en-tête HTTP <code>"Cookie" : "coniunctio={coniunctio}"</code> pour chaque appel. | ||
== Comportement du sous-domaine == | <div id="sous-domaine"></div> | ||
Il est intéressant de remarquer que l'API se comporte souvent en véritable | == Comportement du sous-domaine pour les forums == | ||
Il est intéressant de remarquer que l'API se comporte souvent en véritable site Web, qui réplique les forums du site www.jeuxvideo.com : par exemple, si vous êtes sur un [[topic]] ou un [[forum]], il vous suffit de remplacer dans l'URL « www » par « api » et vous vous trouverez sur une page aux informations identiques quoique présentées de manière différente. Ainsi, les URL seront de la forme <code>https://api.jeuxvideo.com/forums/0-51-0-1-0-1-0-blabla-18-25-ans.htm</code>. Il manque cependant de nombreuses fonctionnalités comme les pages de profils sur le sous-domaine API. | |||
[[File:forum_api.png|vignette| | [[File:forum_api.png|vignette|350px|Le forum [[Blabla 18-25 ans]] sur le site de l'API.]] | ||
L'API ne fonctionne donc pas que par ''endpoints''. | L'API ne fonctionne donc pas que par ''endpoints''. | ||
| Ligne 128 : | Ligne 154 : | ||
{{clear}} | {{clear}} | ||
==Endpoints | ==Endpoints de service== | ||
Il s'agit des ''endpoints'' « documentés » dans le code de l'application mobile et qui se comportent différemment des services de l'API qui ne se contentent que de « copier » le contenu JVC (voir sous-section précédente). | Il s'agit des ''endpoints'' « documentés » dans le code de l'application mobile et qui se comportent différemment des services de l'API qui ne se contentent que de « copier » le contenu JVC (voir sous-section précédente). | ||
On rappelle que l'accès à ces ''endpoints'' nécessite un token d'authentification à fournir dans le header ''Jvc-Authorization''. Voir l'[[#annexe|annexe]] pour le générer. | |||
'''URL de base''': ''<nowiki>https://api.jeuxvideo.com/v4/</nowiki>'' | '''URL de base''': ''<nowiki>https://api.jeuxvideo.com/v4/</nowiki>'' | ||
*''' | *'''PATH''': chemin d'accès de l'''endpoint'' | ||
*'''PARAMS, HEADERS''': | *'''PARAMS, HEADERS''': | ||
** ''' | ** '''param''' : variable entre accolades à remplacer dans l'URL, suivie dans la documentation de son type (''str'' ou ''int''). Par exemple, <code>contents/{contentID}/comments</code> doit être appelé comme suit : <code>contents/123456/comments</code>. <br> Note : dans la plupart des cas, le paramètre <code>accountId</code> peut être remplacé par la valeur <code>me</code> lorsque la requête doit pointer sur le compte connecté. | ||
** '''header''' : ''header'' particulier à inclure dans l'en-tête de la requête. Si pas de spécification, l'en-tête ne contient que les ''headers'' de base spécifiés plus haut (''User-Agent'', ''Jvc-Authorization'', etc.). | ** '''header''' : ''header'' particulier à inclure dans l'en-tête de la requête. Si pas de spécification, l'en-tête ne contient que les ''headers'' de base spécifiés plus haut (''User-Agent'', ''Jvc-Authorization'', etc.). | ||
*'''QUERY''': par exemple pour les deux query ''page'', ''perPage'' int, l'URL devra être: <code>api.jeuxvideo.com/v4/contents/1234ID/comments?page=1&perPage=30</code> | *'''QUERY''': par exemple pour les deux query ''page'', ''perPage'' int, l'URL devra être: <code>api.jeuxvideo.com/v4/contents/1234ID/comments?page=1&perPage=30</code> | ||
*'''BODY''': Corps de la requête au format JSON | *'''BODY''': Corps de la requête au format JSON | ||
Le fichier JSON contenant les <code>id</code> des ''params'' et des ''query strings'' <code>chronicles</code> <code>modes</code> <code>genres</code> <code>events</code> <code>machine</code> <code>categories</code> (obtenu via la requête ''GET config'') est disponible [https://pastebin.com/ | Le fichier JSON contenant les <code>id</code> des ''params'' et des ''query strings'' <code>chronicles</code> <code>modes</code> <code>genres</code> <code>events</code> <code>machine</code> <code>categories</code> (obtenu via la requête ''GET config'') est disponible [https://pastebin.com/bnAu6tFL ici]. | ||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
|+POST | |+POST | ||
!NOM | !NOM | ||
! | !PATH | ||
!PARAMS, HEADERS | !PARAMS, HEADERS | ||
!BODY | !BODY | ||
| Ligne 150 : | Ligne 177 : | ||
|addComment | |addComment | ||
|contents/{contentID}/comments | |contents/{contentID}/comments | ||
|'''contentID''' | |'''contentID''' int | ||
|<pre>"content": "commentaire"</pre> | |<pre>"content": "commentaire"</pre> | ||
|- | |- | ||
|addCommentVote | |addCommentVote | ||
|contents/{contentID}/comments/{commentID}/vote | |contents/{contentID}/comments/{commentID}/vote | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
|<pre>"type": 1 ou -1</pre> | |<pre>"type": 1 ou -1</pre> | ||
|- | |- | ||
|addReply | |addReply | ||
|contents/{contentID}/comments/{commentID}/answers | |contents/{contentID}/comments/{commentID}/answers | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
|"content": "Super jeu !" | |<pre>"content": "Super jeu !"</pre> | ||
|- | |- | ||
|addReview | |addReview | ||
|games/{id}/{machine}/reviews/users | |games/{id}/{machine}/reviews/users | ||
|'''id''' int | |'''id''' int | ||
'''machine''' | '''machine''' int | ||
|<pre>"content": "Super jeu !", | |<pre>"content": "Super jeu !", | ||
"mark": 4, | "mark": 4, | ||
"onProfile": true | "onProfile": true | ||
</pre> | </pre> | ||
| Ligne 178 : | Ligne 204 : | ||
|accounts/login | |accounts/login | ||
| | | | ||
|"alias": "pseudo", | |<pre>"alias": "pseudo", | ||
"password": "mot_de_passe"</pre> | |||
"password": "mot_de_passe" | |||
|- | |- | ||
|logout | |logout | ||
| Ligne 201 : | Ligne 226 : | ||
|<pre>"alias": "pseudo", | |<pre>"alias": "pseudo", | ||
"password": "nouveau", | "password": "nouveau", | ||
"session": "", | "session": "", | ||
"captcha": { | "captcha": { | ||
"imageKey": "", | "imageKey": "", | ||
| Ligne 209 : | Ligne 232 : | ||
"imageValues": [ | "imageValues": [ | ||
"val1", | "val1", | ||
"val2" ]} | "val2" | ||
] | |||
} | |||
</pre> | </pre> | ||
|- | |- | ||
|reportAccount | |reportAccount | ||
|accounts/{accountId}/report | |accounts/{accountId}/report | ||
|'''accountId''' | |'''accountId''' int | ||
|"reason": 1, | |<pre>"reason": 1, | ||
"message": "Raison"</pre> | |||
"message": "Raison" | |||
|- | |- | ||
| reportComment | | reportComment | ||
|contents/{contentID}/comments/{commentID}/report | |contents/{contentID}/comments/{commentID}/report | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
|<pre>"reason": 1, | |<pre>"reason": 1, | ||
"message": "Raison", | "message": "Raison", | ||
| Ligne 235 : | Ligne 259 : | ||
|games/{id}/{machine}/reviews/users/{reviewId}/report | |games/{id}/{machine}/reviews/users/{reviewId}/report | ||
|'''id''' int | |'''id''' int | ||
'''machine''' | '''machine''' int | ||
'''reviewId''' int | '''reviewId''' int | ||
|<pre>"reason": 1, | |<pre>"reason": 1, | ||
| Ligne 247 : | Ligne 271 : | ||
|restoreComment | |restoreComment | ||
|contents/{contentID}/comments/{commentID} | |contents/{contentID}/comments/{commentID} | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
|"content" : "comment" | |<pre>"content" : "comment"</pre> | ||
|- | |- | ||
|validateAccount | |validateAccount | ||
| Ligne 270 : | Ligne 294 : | ||
|accounts/me/favorites/forums | |accounts/me/favorites/forums | ||
| | | | ||
| | |<code>"forums" : [50,51,52] # ID des forums</code> | ||
|- | |- | ||
|addFavoritesGames | |addFavoritesGames | ||
|accounts/me/favorites/games | |accounts/me/favorites/games | ||
| | | | ||
| | |<code>"games" : [{"id":"ID du jeu", "machine":"ID de la machine"}]</code> | ||
|- | |- | ||
|addFavoritesTopics | |addFavoritesTopics | ||
|accounts/me/favorites/topics | |accounts/me/favorites/topics | ||
| | | | ||
| | |<code>"topics" : [74229153, 74229154] # ID des forums</code> | ||
|} | |} | ||
Ci-dessous figurent les requêtes ''GET'', qui se comportent comme des recherches selon les filtres passés en ''queries''. | |||
Les ''queries'' de type <code>str</code> (chaînes de caractère) représentent des ID répertoriées dans la réponse à la requête <code>general/config</code> (sous forme de fichier JSON, disponible [https://pastebin.com/bnAu6tFL ici]). | |||
Si l'on souhaite filtrer les résultats selon leur nature (''news'', vidéos, ''previews'', etc.), on dispose du dictionnaire suivant (provenant de l'application mobile) qui à chaque nature de document associe l'ID des catégories associées : | |||
<pre> | |||
{'videos': '6,13,14,15,16,17,145,19,20', | |||
'news': '50', | |||
'previews': '55', | |||
'tests': '56,57', | |||
'all': '6,13,14,15,16,17,145,50,19,20,53,55,56,57'} | |||
</pre> | |||
Pour plus de détails, veuillez consulter le fichier JSON de configuration. | |||
Comment vous pouvez le constater, contrairement aux variables de type <code>int</code>, les <code>str</code> peuvent contenir plusieurs valeurs, séparées par des virgules : dans ce cas, elles devront être ''parsées'' selon l'encodage URL (voir l'[[#Annexe|annexe]] où un script Python réalisant cette tâche est mis à disposition). | |||
Les ''queries page'' et ''perPage'', toujours des entiers, représentent respectivement : le numéro de la page de recherche et le nombre d'objets à afficher par page. | |||
Les ID comme ''accountID'' et ''commentID'' sont des entiers. Il est à noter que dans la plupart des cas, ''accountID'' peut être remplacé par la chaîne de caractères ''me'' qui représente l'utilisateur connecté (connu grâce au cookie ''coniunctio'' passé en en-tête de la requête). | |||
{| class="wikitable" | {| class="wikitable" | ||
|+GET | |+GET | ||
!NOM | !NOM | ||
! | !PATH | ||
!PARAMS, HEADERS | !PARAMS, HEADERS | ||
!QUERY | !QUERY | ||
| Ligne 296 : | Ligne 337 : | ||
|getAccount | |getAccount | ||
|accounts/{accountId} | |accounts/{accountId} | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
|getAllFavorisGames | |getAllFavorisGames | ||
|accounts/{accountId}/favorites/games/all | |accounts/{accountId}/favorites/games/all | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
| Ligne 308 : | Ligne 349 : | ||
|'''id''' int | |'''id''' int | ||
| | | | ||
|- | |- | ||
|getCaptcha | |getCaptcha | ||
| Ligne 328 : | Ligne 362 : | ||
|getComment | |getComment | ||
|contents/{contentID}/comments/{commentID} | |contents/{contentID}/comments/{commentID} | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
| | | | ||
|- | |- | ||
|getCommentAnswers | |getCommentAnswers | ||
|contents/{contentID}/comments/{commentID}/answers | |contents/{contentID}/comments/{commentID}/answers | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
| | | | ||
|- | |- | ||
|getComments | |getComments | ||
|contents/{contentID}/comments | |contents/{contentID}/comments | ||
|'''contentID''' | |'''contentID''' int | ||
|'''page''' int | |'''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
| Ligne 357 : | Ligne 391 : | ||
'''machines''' str | '''machines''' str | ||
'''page''' int | '''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
|- | |- | ||
|getCurrentAccountReport | |getCurrentAccountReport | ||
|accounts/{accountId}/report | |accounts/{accountId}/report | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
|getCurrentCommentReport | |getCurrentCommentReport | ||
|contents/{contentID}/comments/{commentID}/report | |contents/{contentID}/comments/{commentID}/report | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
| | | | ||
|- | |- | ||
| Ligne 380 : | Ligne 413 : | ||
|getFavorites | |getFavorites | ||
|accounts/{accountId}/favorites | |accounts/{accountId}/favorites | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
|getFavoritesForum | |getFavoritesForum | ||
|accounts/{accountId}/favorites/forums | |accounts/{accountId}/favorites/forums | ||
|'''accountId''' | |'''accountId''' int | ||
|'''page''' int | |'''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
| Ligne 391 : | Ligne 424 : | ||
|getFavoritesGames | |getFavoritesGames | ||
|accounts/{accountId}/favorites/games | |accounts/{accountId}/favorites/games | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
|getFavoritesTopics | |getFavoritesTopics | ||
|accounts/{accountId}/favorites/topics | |accounts/{accountId}/favorites/topics | ||
|'''accountId''' | |'''accountId''' int | ||
|'''page''' int | |'''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
| Ligne 432 : | Ligne 465 : | ||
'''mode''' str | '''mode''' str | ||
'''page''' int | '''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
|- | |- | ||
|getGameNews | |getGameNews | ||
| Ligne 525 : | Ligne 557 : | ||
|getPageContents | |getPageContents | ||
|accounts/{accountId}/page/contents | |accounts/{accountId}/page/contents | ||
|'''accountId''' | |'''accountId''' int | ||
|'''page''' int | |'''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
| Ligne 531 : | Ligne 563 : | ||
|getPageReviews | |getPageReviews | ||
|accounts/{accountId}/page/reviews | |accounts/{accountId}/page/reviews | ||
|'''accountId''' | |'''accountId''' int | ||
|'''page''' int | |'''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
| Ligne 537 : | Ligne 569 : | ||
|getProfile | |getProfile | ||
|accounts/{accountId}/profile | |accounts/{accountId}/profile | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
|getProfilePage | |getProfilePage | ||
|accounts/{accountId}/page | |accounts/{accountId}/page | ||
|'''accountId''' | |'''accountId''' int | ||
| | | | ||
|- | |- | ||
| Ligne 562 : | Ligne 594 : | ||
|'''page''' int | |'''page''' int | ||
'''perPage''' int | '''perPage''' int | ||
|- | |- | ||
|getStores | |getStores | ||
| Ligne 587 : | Ligne 614 : | ||
|getTopsComments | |getTopsComments | ||
|contents/{contentID}/comments/tops | |contents/{contentID}/comments/tops | ||
|'''contentID''' | |'''contentID''' int | ||
| | | | ||
|- | |- | ||
| Ligne 594 : | Ligne 621 : | ||
|'''id''' int | |'''id''' int | ||
| | | | ||
|- | |- | ||
|getVideosSummary | |getVideosSummary | ||
| Ligne 611 : | Ligne 628 : | ||
|- | |- | ||
|search | |search | ||
| | |search | ||
| | | | ||
|'''q''' str | |'''q''' str | ||
| Ligne 663 : | Ligne 680 : | ||
|+PUT | |+PUT | ||
!NOM | !NOM | ||
! | !PATH | ||
!PARAMS, HEADERS | !PARAMS, HEADERS | ||
!BODY | !BODY | ||
| Ligne 670 : | Ligne 687 : | ||
|accounts/me/profile/description | |accounts/me/profile/description | ||
| | | | ||
|"description": "Ma description" | |<pre>"description": "Ma description"</pre> | ||
|- | |- | ||
|saveExcludedMachines | |saveExcludedMachines | ||
|accounts/me/profile/excluded-machines | |accounts/me/profile/excluded-machines | ||
| | | | ||
|"machines" : [1, 2, 3, 4] // id des machines | |<pre>"machines" : [1, 2, 3, 4] // id des machines</pre> | ||
|- | |- | ||
|saveMachines | |saveMachines | ||
|accounts/me/profile/machines | |accounts/me/profile/machines | ||
| | | | ||
|"machines" : [1, 2, 3, 4] // id des machines | |<pre>"machines" : [1, 2, 3, 4] // id des machines</pre> | ||
|- | |||
|setFavorisForum | |||
|accounts/me/favorites/forums | |||
| | |||
|<code>"forums" : [50,51,52] # ID des forums</code> | |||
|- | |||
|setFavorisGames | |||
|accounts/me/favorites/games | |||
| | |||
|<code>"games" : [{"id":"ID du jeu", "machine":"ID de la machine"}]</code> | |||
|- | |||
|setFavorisTopics | |||
|accounts/me/favorites/topics | |||
| | |||
|<code>"topics" : [74229153, 74229154] # ID des topics</code> | |||
|- | |- | ||
|updateComment | |updateComment | ||
|contents/{contentID}/comments/{commentID} | |contents/{contentID}/comments/{commentID} | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
|"content": "Super jeu !" | |<pre>"content": "Super jeu !"</pre> | ||
|- | |- | ||
|uploadAvatar | |uploadAvatar | ||
|accounts/me/avatar | |accounts/me/avatar | ||
| '''header''' : <code>"Content-Type": "application/octet-stream"</code> | | '''header''' : <code>"Content-Type": "application/octet-stream"</code> <br> | ||
|objet <code>bytes</code> (conversion du fichier image en octets, pas de clé associée) | |'''body''' : objet <code>bytes</code> (conversion du fichier image en octets, pas de clé associée) | ||
|- | |- | ||
|uploadCover | |uploadCover | ||
|accounts/me/cover | |accounts/me/cover | ||
| '''header''' : <code>"Content-Type": "application/octet-stream"</code> | | '''header''' : <code>"Content-Type": "application/octet-stream"</code> <br> | ||
|objet <code>bytes</code> (conversion du fichier image en octets, pas de clé associée) | |'''body''' : objet <code>bytes</code> (conversion du fichier image en octets, pas de clé associée) | ||
|} | |} | ||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
|+DELETE | |+DELETE | ||
!NOM | !NOM | ||
! | !PATH | ||
!PARAMS, HEADERS | !PARAMS, HEADERS | ||
!BODY | !BODY | ||
| Ligne 708 : | Ligne 740 : | ||
|deleteComment | |deleteComment | ||
|contents/{contentID}/comments/{commentID} | |contents/{contentID}/comments/{commentID} | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
| | | | ||
|- | |- | ||
|deleteCommentVote | |deleteCommentVote | ||
|contents/{contentID}/comments/{commentID}/vote | |contents/{contentID}/comments/{commentID}/vote | ||
|'''contentID''' | |'''contentID''' int | ||
'''commentID''' | '''commentID''' int | ||
| | | | ||
|- | |- | ||
| Ligne 721 : | Ligne 753 : | ||
|accounts/me/favorites/forums | |accounts/me/favorites/forums | ||
| | | | ||
| | |<code>"forums" : [50,51,52] # ID des forums</code> | ||
|- | |- | ||
| deleteFavorisGames | | deleteFavorisGames | ||
|accounts/me/favorites/games | |accounts/me/favorites/games | ||
| | | | ||
| | |<code>"games" : [{"id":"ID du jeu", "machine":"ID de la machine"}]</code> | ||
|- | |- | ||
|deleteFavorisTopics | |deleteFavorisTopics | ||
|accounts/me/favorites/topics | |accounts/me/favorites/topics | ||
| | | | ||
| | |<code>"topics" : [74229153, 74229154] # ID des topics</code> | ||
|} | |} | ||
| Ligne 752 : | Ligne 784 : | ||
parsed_url = urllib.parse.urlparse(f"https://{DOMAIN}/v{API_VERSION}/{path}") | parsed_url = urllib.parse.urlparse(f"https://{DOMAIN}/v{API_VERSION}/{path}") | ||
if query: | if query: | ||
parsed_url = parsed_url._replace(query=urllib.parse.urlencode( | sorted_query = dict(sorted(query.items())) | ||
parsed_url = parsed_url._replace(query=urllib.parse.urlencode(sorted_query)) | |||
# Création de la chaîne à hash | # Création de la chaîne à hash | ||
| Ligne 773 : | Ligne 806 : | ||
from requests import Response | from requests import Response | ||
def call(path: str, method: str = 'GET', query: dict = None, data: dict = None, cookies: dict = | DOMAIN = 'api.jeuxvideo.com' | ||
API_VERSION = 4 | |||
def call(path: str, method: str = 'GET', query: dict = None, data: dict = None, cookies: dict = None) -> Response: | |||
url = f"https://{DOMAIN}/v{API_VERSION}/{path}" | url = f"https://{DOMAIN}/v{API_VERSION}/{path}" | ||
jv_auth = auth_header(path, method=method, query=query) | jv_auth = auth_header(path, method=method, query=query) | ||
| Ligne 791 : | Ligne 827 : | ||
</pre> | </pre> | ||
=== Parsing | === ''Parsing'' des ''queries'' === | ||
Lors de l'appel à ''contents'', vous pouvez passer en ''query'' | Lors de l'appel à ''contents'' par exemple, vous pouvez passer en ''query'' des chaînes de caractère comme ''categories'' ou ''types''. Ces ''queries'', s'il contiennent plusieurs valeurs, doivent être encodés au format d'encodage URL, ce qui peut être fait en Python : | ||
<pre> | <pre> | ||
from urllib.parse import quote | from urllib.parse import quote | ||
| Ligne 803 : | Ligne 839 : | ||
# vous pouvez désormais passer ce dictionnaire en query | # vous pouvez désormais passer ce dictionnaire en query | ||
</pre> | </pre> | ||
== Accès aux forums == | |||
Étrangement, il n'existe pas d'''endpoint'' particulier pour envoyer un message ou un topic sur les [[forum|forums]] de jeuxvideo.com. | |||
Lorsque l'application mobile souhaite récupérer les pages des forums, elle envoie une requête au lien usuel de la ressource à ceci près que ''www'' est remplacé par ''api''. La requête renvoie alors une page HTML en guise de réponse, voir la [[#sous-domaine|rubrique en question]]. | |||
Ainsi, lorsque l'on cherche à interagir avec les forums, il n'y a pas d'avantage à envoyer des requêtes à l'API plutôt qu'au site de base en l'état. | |||
=== Principe général === | |||
En premier lieu, afin d'envoyer un message ou un topic sur un forum, il faut bien évidemment que vous soyez connecté et vus devrez donc passer en en-tête de la requête votre cookie ''coniunctio'', récupérable à partir d'une requête à l'''endpoint'' <code>accounts/login</code> envoyant vos identifiants. | |||
[[File:js_form.png|vignette|400px|Les ''inputs'' cachés contenant les valeurs à envoyer dans les requêtes visibles depuis les outils de développeur.]] | |||
En second lieu, vous ne devrez pas seulement envoyer aux serveurs le contenu de votre message (et le titre du topic si besoin) : la requête ''POST'' devra aussi contenir des paires clés-valeurs générées par le site lui-même et qui agissent comme une sorte de protection. Celles-ci sont : ''fs_session'', ''fs_timestamp'', ''fs_version'', ''form_alias_rang'' ainsi qu'un ''hash''. | |||
'''Depuis mai 2025''', suite à une mise à jour de JVC, les informations ''"fs_" '', sont offusqués dans une chaîne en base 64. | |||
Les fs_ sont récupérables via la balise script : ''window.jvc.forumsAppPayload'' | |||
<script>window.jvc=window.jvc||{};window.jvc.forumsAppPayload=[CHAINE_A_RECUPERER]</script> | |||
Pour récupérer les valeurs dans la chaîne : | |||
const forumsAppPayload = [...document.scripts].map(s => s.textContent.match(/forumsAppPayload\s*=\s*["']([^"']+)["']/)).filter(Boolean)[0][1]; | |||
const decoded = JSON.parse(atob(forumsAppPayload)); | |||
Auparavant, ces valeurs étaient disponibles depuis des ''inputs'' cachées dans le code HTML des pages de forums/topics et situées dans la ''div'' nommée ''js-form-session-data''. | |||
Si l'on veut envoyer un message sur un topic (ou un forum), il faudra d'abord envoyer une requête ''GET'' à l'URL associée et récupérer ces valeurs chiffrées avant d'envoyer une requête ''POST'' à l'URL avec le contenu du message en plus de ces dernières. | |||
'''Pour poster un message''', la requête POST devra être faite à <code>https://www.jeuxvideo.com/forums/message/add</code> avec le ''header'' <code>Content-Type</code> valant <code>multipart/form-data</code> et les données suivantes en ''body'' : | |||
<pre> | |||
text : le contenu du message | |||
topicId : ID du topic cible | |||
topicTitle : titre du topic (si c'est une création du topic) | |||
forumId : ID du forum cible | |||
group : mettre à 1 | |||
messageId : undefined | |||
toutes les clé/valeurs qui commencent par fs_ (à trouver selon la méthode donnée précédemment) + ajax_hash | |||
</pre> | |||
'''Pour poster un topic''', la requête POST devra être faite à <code>https://www.jeuxvideo.com/forums/topic/add</code> avec le ''header'' <code>Content-Type</code> valant <code>multipart/form-data</code> et les données suivantes en ''body'' : | |||
<pre> | |||
text : le contenu du message | |||
topicId : mettre à 0 | |||
topicTitle : titre du topic (si c'est une création du topic) | |||
forumId : ID du forum cible | |||
group : mettre à 1 | |||
messageId : undefined | |||
toutes les clé/valeurs qui commencent par fs_ (à trouver selon la méthode donnée précédemment) + ajax_hash | |||
submitSurvey : true pour ajouter un sondage, false sinon | |||
answerSurvey : titre du sondage s'il y en a un | |||
responsesSurvey[] : une réponse au sondage | |||
</pre> | |||
'''Note''' : À date, ces informations sont uniquement offusquées dans la partie forum. Les messages privés conservent les informations en clair dans le HTML comme mentionné plus haut. | |||
== Limitations == | |||
L'API v4 comporte plusieurs limitations : | |||
* Il est impossible d'outrepasser les protections [[captcha|captchas]] requises par le site notamment pour [[DDB|signaler]] un message. | |||
* Il est impossible de s'inscrire en utilisation l'''endpoint'' <code>accounts/register</code> car celui-ci nécessite un ''header'' contenant le ''token'' FireBase généré lors de l'installation de l'application (voir le [[#jvc-auth-header|paragraphe à ce sujet]]). Une solution serait de créer un grand nombre de machines virtuelles (ou d'en automatiser la création), et pour chacune d'entre elles d'intercepter le trafic de l'application (voir [[#interception|section associée]]) pour récupérer et conserver les ''tokens'' dans un fichier. Cette méthode, longue et fastidieuse, ne permettrait donc pas de générer un nombre infini de comptes. Une autre méthode possible, bien qu'elle n'utilise pas l'API, serait de créer un compte sur le site à l'aide d'un ''webdriver''. Celle-ci fonctionne (l'auteur de ce paragraphe l'a déjà implémentée) mais il serait difficile de la rendre compatible pour toutes les plateformes (du fait de la nécessité d'avoir un VPN gérable depuis un script). | |||
* Il est particulièrement hardu de faire du ''web scraping'' sur les pages de forum puisque l'API renvoie une page HTML et non un fichier JSON dans ce cas. | |||
==Ressources== | ==Ressources== | ||
* | *[https://archive.org/details/jeuxvideo.com-pc-et-consoles-5.4.7-apkpure APK 5.4.7] décompilable avec JADX. | ||
* | *[https://pastebin.com/LWNDQDKy Classe PHP] exploitant l'API (cette classe est incomplète et sera possiblement rendue obsolète dans le temps). | ||
= API jvc.gg (dépréciée) = | |||
{{Bannière Note|Contenu=Le contenu qui va suivre concerne l'ancienne API qui n'existe plus.}} | |||
[[File:phoenix.png|300px|vignette|La page Phoenix des jeux.]] | |||
Cette API était une API distincte de la ''v4'' et utilisée par la partie Phoenix du site, c'est-à-dire les pages listant les jeux, ''reviews'', vidéos, etc., comme [https://www.jeuxvideo.com/tous-les-jeux/ celle-ci]. Elle était hébergée sur le domaine [https://api.jvc.gg api.jvc.gg]. | |||
L'API est fermée début février 2025 à la suite de la refonte des pages Phoenix de JVC qui adoptent désormais le même fonctionnement que les autres pages du site. | |||
{{clear}} | |||
== Rétro-ingénierie == | |||
L'API étant privée, il a fallu procéder par rétro-ingénierie pour la documenter. | |||
Les appels à l'API sont effectués depuis un script chargé par les pages Phoenix. Les noms de variable sont obfusqués mais pas les chaînes de caractère : ainsi une partie des ''endpoints'' y sont lisibles. Ce script est téléchargeable [https://archive.org/details/phoenix_script ici]. | |||
Il est également possible d'observer les URL et les contenus des requêtes depuis le panneau ''Network'' (ou ''Réseau'') des [https://developer.mozilla.org/fr/docs/Learn/Common_questions/Tools_and_setup/What_are_browser_developer_tools outils de développement Web]. | |||
== Préambule == | |||
L'API jvc.gg est basée sur l'utilisation de ''JSON Web Token'' (JWT), un standard utilisé pour créer des jetons de sécurité qui permettent de transférer de l'information de manière sécurisée entre deux parties au format JSON. | |||
Lorsque vous visitez pour la première fois une page Phoenix, le serveur de JVC renvoie une requête comportant un cookie ''accessToken''. La valeur de ce cookie est une chaîne de caractères encodée au format JWT qui contient notamment votre ID de compte et la valeur de votre cookie ''coniunctio''. La fonction Python suivante permet de récupérer le cookie ''accessToken'' en fonction de votre cookie ''coniunctio'' : | |||
<pre> | |||
def get_access_cookie(coniunctio: str) -> str: | |||
cookies = {'coniunctio':coniunctio} | |||
res = requests.get('https://www.jeuxvideo.com/tous-les-jeux/', cookies=cookies) | |||
access_cookie = res.headers['set-cookie'].split(';')[0].replace('accessToken=', '') | |||
return access_cookie | |||
</pre> | |||
Ce cookie vous sera utile lorsque les requêtes envoyées sont destinées à opérer sur votre compte. | |||
== Endpoints == | |||
Le tableau suivant répertorie les ''endpoints'' connus de cette API. Voici la signification de ses colonnes : | |||
*'''PATH''' : chemin de l'''endpoint''. | |||
*'''PARAMS, HEADERS''' : | |||
** '''param''' : variable entre accolades à remplacer dans l'URL, suivie dans la documentation de son type (''str'' ou ''int''). Par exemple, <code>contents/{contentID}/comments</code> doit être appelé comme suit : <code>contents/123456/comments</code>. | |||
** '''header''' : ''header'' particulier à inclure dans l'en-tête de la requête. Si pas de spécification, l'en-tête ne contient que les ''headers'' de base spécifiés plus haut (''User-Agent'', ''Jvc-Authorization'', etc.). | |||
*'''QUERY''' : valeur à ajouter à l'URL permettant si précisée de filtrer les résultats. Par exemple pour les deux query ''page'', ''perPage'' int, l'URL devra être: <code>api.jeuxvideo.com/v4/contents/1234ID/comments?page=1&perPage=30</code> | |||
*'''BODY''' : Corps de la requête au format JSON | |||
=== Les paramètres spéciaux === | |||
* Le paramètre <code>{accessToken}</code> devra toujours être remplacé par la valeur du cookie éponyme. | |||
* Le paramètre <code>{gameCategory}</code> peut être remplacée par les valeurs suivantes, qui proviennent évidemment du système de classification de JVC : | |||
** <code>all</code> pour avoir la liste de tous les jeux ; | |||
** <code>awaited</code> pour avoir la liste des jeux attendus ; | |||
** <code>popular</code> pour avoir la liste des jeux populaires ; | |||
** <code>best</code> pour avoir la liste des meilleurs jeux ; | |||
** <code>currentBest</code> pour avoir la liste des meilleurs jeux du moment ; | |||
** <code>releases</code> pour avoir la liste des jeux pas encore sortis. | |||
=== Queries des jeux === | |||
Les ''queries'' renseignent la plateforme, le genre et le mode du jeu. La liste complète des valeurs des ''queries'' possibles pour ces attributs est disponible au format JSON [https://pastebin.com/1LGEibT8 ici]. | |||
Par exemple, si vous souhaitez obtenir la liste des jeux PS4 de genre action RPG et de forme multi en ligne, votre chaîne de ''queries'' devra être <code>platform=ps4&gameGenre=action_rpg&gameMode=multiplayer_online</code>. | |||
De plus, le ''query'' ''release'' désigne la date de sortie du jeu, '''compatible seulement avec les catégories <code>best</code> et <code>releases</code>'''. Il peut s'agir d'une année ou d'une décennie (dans ce cas, la valeur du ''query'' représentera la première année de la décennie suivie du caractère 'd' ; par exemple, <code>2010d</code> pour les années 2010). Pour les jeux pas encore sortis, ce ''query'' peut également contenir le mois (par exemple : <code>2024-07</code> pour juillet 2024). Incompatible avec la catégorie <code>currentBest</code>. | |||
=== Queries des news === | |||
Les ''queries'' renseignent la plateforme, le type, le genre et l'événement des news. La liste complète des valeurs des ''queries'' possibles pour ces attributs est disponible au format JSON [https://pastebin.com/Dk4SkDkA ici]. | |||
Par exemple, si vous souhaitez obtenir la liste des news de jeux PS5 de genre aventure en rapport avec l'événement ''Game Awards'' publiés en 2022, votre chaîne de ''queries'' devra être <code>publicationType=game_news&platform=ps5&gameGenre=adventure&event=id201395&publicationPeriod=2022</code>. | |||
Le ''query publicationPeriod'' peut être : une année, une année suivie du numéro du mois (<code>2024-07</code> pour juillet 2024) ou une décennie (<code>2010d</code> pour les années 2010). | |||
=== Queries des tests === | |||
Les ''queries'' renseignent la plateforme, le mode et le genre des jeux testés, ainsi que l'encadrement de la note des rédacteurs et la date de publication. La liste complète des valeurs des ''queries'' possibles pour ces attributs est disponible au format JSON [https://pastebin.com/YxKif1DJ ici]. | |||
Par exemple, si vous souhaitez obtenir la liste des tests de jeux PC de genre aventure, de mode solo ayant eu au moins 14 et datant d'il y a au plus 6 mois, votre chaîne de ''queries'' devra être | |||
<code>platform=pc&gameGenre=adventure&gameMode=singleplayer&editorialRatingRange=%5B14%2C)&maxAge=P6M</code> | |||
Notez que le ''query editorialRatingRange'' doit être encodé au format URL avant d'être envoyé. | |||
=== Queries des previews === | |||
Les ''queries'' renseignent la plateforme, le genre et l'événement des jeux testés. La liste complète des valeurs des ''queries'' possibles pour ces attributs est disponible au format JSON [https://pastebin.com/xaqTQPfr ici]. | |||
Par exemple, si vous souhaitez obtenir la liste des ''previews'' des jeux PS5 de genre FPS en rapport avec l'événement ''Find Your Next Game'', votre chaîne de ''queries'' devra être <code>platform=ps5&gameGenre=fps&event=fyng</code>. | |||
=== Queries des vidéos === | |||
Les ''queries'' renseignent le type des vidéos ainsi que la plateforme, le genre et l'événement des jeux traités. La liste complète des valeurs des ''queries'' possibles pour ces attributs est disponible au format JSON [https://pastebin.com/nBUAP4XX ici]. | |||
Par exemple, si vous souhaitez obtenir la liste des vidéos ''gameplays'' des jeux PC de genre Action en rapport avec l'événement E3, votre chaîne de ''queries'' devra être <code>publicationType=gameplay&platform=pc&gameGenre=action&event=e3</code>. | |||
=== Queries des dossiers === | |||
Les ''queries'' renseignent la plateforme, le genre et l'événement des jeux traités. La liste complète des valeurs des ''queries'' possibles pour ces attributs est disponible au format JSON [https://pastebin.com/UGd3b2qJ ici]. | |||
Par exemple, si vous souhaitez obtenir la liste des vidéos ''gameplays'' des jeux PC de genre Action en rapport avec l'événement E3, votre chaîne de ''queries'' devra être <code>publicationType=gameplay&platform=pc&gameGenre=action&event=e3</code>. | |||
=== Queries globaux === | |||
Ce sont les ''queries'' ''offset'' et ''limit'', de type ''int'', qui représentent respectivement l'indice de l'item dans la liste à partir duquel les items sont listés (par défaut 0) et le nombre d'items à lister (par défaut 100). Ils fonctionnent avec toutes les recherches. | |||
=== Requêtes auxiliaires === | |||
En parallèle des requêtes envoyées par le site pour rechercher des jeux, news, previews, vidéos ou tests, des requêtes auxiliaires sont adressées aux serveurs. Elles permettent en particulier de connaître ce qu'il faut afficher sur la page, les URL des pages ainsi que les options (''queries'') restantes selon ce qui a déjà été entré dans le panel de recherche. | |||
Ces requêtes utilisent un ''endpoint'' contenant un token JWT dans lequel sont stockées des informations générales sur la requête (''queries'' notamment). Comme cette clé secrète n'est pas connue, il nous est malheureusement impossible de générer de tels tokens à la demande. | |||
=== Liste des endpoints connus === | |||
{| class="wikitable" | |||
|+GET | |||
!PATH | |||
!PARAMS | |||
!QUERY | |||
!DESCRIPTION | |||
|- | |||
|games/{gameCategory}/popularity.desc | |||
| '''gameCategory''' str | |||
|'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''gameMode''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int <br> | |||
'''release''' str | |||
|Renvoie la liste des jeux de la catégorie <code>{gameCategory}</code> triés par popularité décroissante et satisfaisant les ''queries''. | |||
|- | |||
|games/{gameCategory}/editorialRating.desc | |||
| '''gameCategory''' str | |||
|'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''gameMode''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int <br> | |||
'''release''' str | |||
|Renvoie la liste des jeux de la catégorie <code>{gameCategory}</code> triés par popularité décroissante et satisfaisant les ''queries''. | |||
|- | |||
|games/{gameCategory}/releaseDate.asc | |||
| '''gameCategory''' str | |||
|'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''gameMode''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int <br> | |||
'''release''' str | |||
|Renvoie la liste des jeux de la catégorie <code>{gameCategory}</code> triés par popularité décroissante et satisfaisant les ''queries''. | |||
|- | |||
|games/{gameCategory}/title.asc | |||
| '''gameCategory''' str | |||
|'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''gameMode''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int <br> | |||
'''release''' str | |||
|Renvoie la liste des jeux de la catégorie <code>{gameCategory}</code> triés par popularité décroissante et satisfaisant les ''queries''. | |||
|- | |||
|news/datePublished.desc | |||
| | |||
| '''publicationType''' str <br> | |||
'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''event''' str <br> | |||
'''publicationPeriod''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des actualités triées par date de publication croissante et satisfaisant les ''queries''. | |||
|- | |||
|reviews/datePublished.desc | |||
| | |||
| | |||
'''platform''' str<br> | |||
'''gameGenre''' str<br> | |||
'''gameMode''' str<br> | |||
'''editorialRatingRange''' str<br> | |||
'''maxAge''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des tests triés par date de publication croissante et satisfaisant les ''queries''. | |||
|- | |||
|reviews/editorialRating.desc | |||
| | |||
| | |||
'''platform''' str<br> | |||
'''gameGenre''' str<br> | |||
'''gameMode''' str<br> | |||
'''editorialRatingRange''' str<br> | |||
'''maxAge''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des tests triés par note décroissante des rédacteurs JVC et satisfaisant les ''queries''. | |||
|- | |||
|reviews/gameTitle.asc | |||
| | |||
| | |||
'''platform''' str<br> | |||
'''gameGenre''' str<br> | |||
'''gameMode''' str<br> | |||
'''editorialRatingRange''' str<br> | |||
'''maxAge''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des tests triés par nom croissant du jeu et satisfaisant les ''queries''. | |||
|- | |||
|previews/datePublished.desc | |||
| | |||
|'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''event''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des annonces triées par date de publication croissante et satisfaisant les ''queries''. | |||
|- | |||
|videos/datePublished.desc | |||
| | |||
|'''publicationType''' str <br> | |||
'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''event''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des vidéos triées par date de publication croissante et satisfaisant les ''queries''. | |||
|- | |||
|topics/datePublished.desc | |||
| | |||
|'''platform''' str <br> | |||
'''gameGenre''' str <br> | |||
'''event''' str <br> | |||
'''offset''' int <br> | |||
'''limit''' int | |||
|Renvoie la liste des dossiers triés par date de publication croissante et satisfaisant les ''queries''. | |||
|- | |||
|me/{accessToken}/privateMessages | |||
| '''accessToken''' str | |||
| | |||
|Renvoie la liste des 25 derniers messages privés. | |||
|- | |||
|me/{accessToken}/notifications/subscription | |||
| '''accessToken''' str | |||
| | |||
|Renvoie la liste des dernières notifications. | |||
|- | |||
|me/{accessToken}/notifications/privateMessage/unseenCount | |||
| '''accessToken''' str | |||
| | |||
|Renvoie le nombre de messages privés non-vus. | |||
|- | |||
|me/{accessToken}/notifications/subscription/unseenCount | |||
| '''accessToken''' str | |||
| | |||
|Renvoie le nombre de notifications non-vues. | |||
|- | |||
|me/{accessToken}/profile | |||
| '''accessToken''' str | |||
| | |||
|Informations du profil. | |||
|- | |||
|config/menu | |||
| | |||
| | |||
|Informations à afficher sur les pages Phoenix. | |||
|} | |||
{| class="wikitable" | |||
|+POST | |||
!PATH | |||
!PARAMS | |||
!BODY | |||
!DESCRIPTION | |||
|- | |||
|me/{accessToken}/notifications/subscription/resetUnseenCount | |||
| '''accessToken''' str | |||
| | |||
|Met à zéro le nombre de notifications non-vues. | |||
|- | |||
|me/{accessToken}/notifications/privateMessage/resetUnseenCount | |||
| '''accessToken''' str | |||
| | |||
|Met à zéro le nombre de messages privés non-vus. | |||
|- | |||
|me/{accessToken}/notifications/subscription/resetUnreadCount | |||
| '''accessToken''' str | |||
| | |||
|Met à zéro le nombre de notifications non-lues. | |||
|- | |||
|me/{accessToken}/notifications/privateMessage/resetUnreadCount | |||
| '''accessToken''' str | |||
| | |||
|Met à zéro le nombre de messages privés non-lus. | |||
|- | |||
|me/{accessToken}/notification/{notifId}/setRead | |||
| '''accessToken''' str <br> | |||
'''notifId''' int | |||
| | |||
|Lit une notification. | |||
|- | |||
|me/{accessToken}/privateMessage/{messageId}/setRead | |||
| '''accessToken''' str <br> | |||
'''messageId''' int | |||
| | |||
|Lit un message privé. | |||
|- | |||
|_auth/{accessToken}/logout | |||
| '''accessToken''' str | |||
| | |||
|Se déconnecter. | |||
|} | |||
=Ancienne API (dépréciée) = | =Ancienne API (dépréciée) = | ||
| Ligne 1 157 : | Ligne 1 553 : | ||
[[Catégorie:Fonctionnement technique de Jeuxvideo.com]] | [[Catégorie:Fonctionnement technique de Jeuxvideo.com]] | ||
[[Catégorie:Extensions et outils]] | [[Catégorie:Extensions et outils]] | ||
[[Catégorie:Article de qualité]] | |||
{{Article de qualité}} | |||