Forums de Grospixels
Bienvenue sur le forum de Grospixels : [ S'Enregistrer ]
Déjà inscrit ? [ Connexion ]
 
retour sur le site
rechercher
Index du Forum » » Technique » » Retropie : récupérer des informations JSON
48 messages • page
123
Auteur Retropie : récupérer des informations JSON
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-16 16:56
Citation :
Le 2021-01-16 11:09, MTF a écrit :
Bon, merci à vous de vous être penché sur ce truc, mais je vais laisser tomber :/ Je ne parviens pas à faire ça, et il me faudrait vraiment repartir de zéro en code pour y parvenir...

Oui ça me parait ambitieux si tu n'as pas quelques prérequis tels que pratiquer le javascript. Et les conseils par écrits ça montre très vite ses limites. Ceci dit je pense que la solution tient en quelques lignes.

Citation :
Le 2021-01-16 10:44, Kaede a écrit :
On peut avoir tout le code ? (il n'y a que ça, ou c'est un extrait ?).
Le top ce serait qu'on puisse lancer ton truc, mais j'imagine qu'il faut retropie et tout le bouzin donc ça me paraît compliqué ...

On doit pouvoir faire un proof of concept avec juste un kit de développement qt/qml mais pour le moment j'arrive pas à savoir quels sont les outils à récupérer.
https://en.wikipedia.org/wiki/Qt_(software)

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-16 19:52
@ Youpla & Kaede : il y a ça sur la doc du frontend que j'utilise : c'est l'indication qu'il vous faut ?

https://pegasus-frontend.org/docs/themes/qml-modules/

  Voir le site web de MTF
MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-16 22:26
Alors... Ma copine est têtue ^^ Du coup, elle essaie de me scripter tout ça. QML permet d'importer directement du javascript... mais ma copine connaît que le python. Alors elle m'a fait un script python qui marche super :

Code :
def get_current_info():

import requests

# Define JSon URL to be parsed.
url = "https://rainwave.cc/api4/info"

# Request JSon from URL with required parameters.
# Information on required parameters at https://rainwave.cc/api4/help/api4/info .
raw_json = requests.get(url, params = ({"sid":"5"}))

# Parse JSon.
parsed_json = raw_json.json()

# Put the info you want into three variables.
current_title = parsed_json["sched_current"]["songs"][0]["title"]
current_album = parsed_json["sched_current"]["songs"][0]["albums"][0]["name"]
current_artist = parsed_json["sched_current"]["songs"][0]["artists"][0]["name"]

# Use the three variables to make one character string.
output_string = 'En lecture : « ' + current_title + ' » de l’album « ' + current_album + ' » par ' + current_artist + "."

# Return the string.
return output_string



...et on essaie de le "traduire" en javascript, sauf que ça bloque à l'étape 4 :

Code :


// 1. Create a new XMLHttpRequest object
var xhr = new XMLHttpRequest();

// 2. Configure it: GET-request for the URL /article/.../load
// Copied from https://rainwave.cc/api4/help/ page.
xhr.open("POST", "https://rainwave.cc/api4/info", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.responseType = 'json';

// 3. Send the request over the network
xhr.send("sid=5&user_id == 1");

// 4. Parse JSon response.
var jsonObject = JSON.parse(xhr.response);

// 5. Get the particupar info we want.
var jsonTitle = JSON.stringify(jsonObject["sched_current"]["songs"][0]["title"]);
// var jsonAlbum = JSON.stringify(jsonObject["sched_current"]["songs"][0]["albums"][0]["name"]);
// var jsonArtist = JSON.stringify(jsonObject["sched_current"]["songs"][0]["artists"][0]["name"]);

// 6. Return some string.

console.log(jsonTitle);


On nous renvoie une erreur "Uncaught TypeError: jsonObject is null"... Une idée de pourquoi que c'est ?

  Voir le site web de MTF
Kaede
Pixel visible depuis la Lune


Inscrit : Mar 06, 2002
Messages : 5248

Hors ligne
Posté le: 2021-01-16 23:34   [ Edité le: 2021-01-17 00:07 ]
Citation :
Le 2021-01-16 19:52, MTF a écrit :

@ Youpla & Kaede : il y a ça sur la doc du frontend que j'utilise : c'est l'indication qu'il vous faut ?

https://pegasus-frontend.org/docs/themes/qml-modules/

Ca doit pouvoir servir, mais je ne saurais pas trop te dire. Je ne suis pas un as en javascript, mais surtout je n'ai jamais utilisé Qt.

Citation :
Le 2021-01-16 22:26, MTF a écrit :

Alors... Ma copine est têtue ^^ Du coup, elle essaie de me scripter tout ça. QML permet d'importer directement du javascript... mais ma copine connaît que le python. Alors elle m'a fait un script python qui marche super :

...et on essaie de le "traduire" en javascript, sauf que ça bloque à l'étape 4 :

Je vois 2 problèmes avec le code javascript que tu as posté

a) en Python, dans l'exemple que vous avez écrit c'est la méthode GET (https://developer.mozilla.org/fr/docs/Web/HTTP/M%C3%A9thode/GET) qui est utilisée.
En javascript, vous avez utilisé POST ? Je pense que c'est incorrect. C'est une API pour consulter des données donc c'est logique que ce soit du GET.

b) par défaut, XMLHttpRequest est asynchrone, donc le code ne fonctionnera pas (ce n'est pas 1] j'appelle send, 2] la ligne d'après, j'ai la réponse, ça passe par un callback).
Tu peux, au choix, travailler en asynchrone et utiliser un callback (c'est la bonne pratique, après dans ton cas je ne sais pas si ça "bloquera" de façon visible à l'écran si ton propre code bloque, j'en doute ...) ou utiliser une requête synchrone (ton code "bloquera" jusqu'à réception de la réponse).
Je te recommande la doc' de chez Mozilla, elle est très bien faite : https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
La page est longue pour bien expliquer, mais le petit bout de code sous "Example: HTTP synchronous request" est ce qui te suffira (pour une requête synchrone).
tl;dr: remplace true par false dans la ligne avec xhr.open

EDIT : et vu que c'est du GET et pas du POST, les paramètres ne vont pas dans le body, mais font partie de l'URL. Donc il faut appeler send sans paramètres, et utiliser https://rainwave.cc/api4/info?sid=5 (par exemple) comme URL C'est ce que fait à l'exécution le code Python que tu as posté (pun intended).

Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-17 01:47   [ Edité le: 2021-01-17 01:49 ]
Pas mieux que Kaede.

Tu demandes explicitement à faire une requête asynchrone lors du xhr.open (cf le troisième paramètre que tu positionnes à true), donc après le xhr.send ton code continue à s’exécuter sans attendre la réponse. C'est pour ça qu'en monde asynchrone on passe en paramètre une fonction de callback qui sera automatiquement invoquée quand la réponse arrivera.

Pour paraphraser Kaede, je te recommande fortement de ne pas utiliser le mode synchrone car ça bloque toute l’exécution du javascript jusqu'à réception de la réponse (qui peut mettre longtemps à arriver, ou ne pas arriver du tout si le serveur est HS).

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-17 09:52
Yes ! Avec votre aide précieuse, ça marche

Image

Maintenant, prochaine étape : récupérer le console.log du code javascript pour l'intégrer comme texte dans la page QML... Voilà le code actuel du JS :

Code :
// 1. Create a new XMLHttpRequest object
var xhr = new XMLHttpRequest();

// 2. Configure it: GET-request for the URL /article/.../load
// Copied from https://rainwave.cc/api4/help/ page.
xhr.open("GET", "https://rainwave.cc/api4/info?sid=5", false);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");


// 3. Send the request over the network
xhr.send();

// 4. Parse JSon response.
var jsonObject = JSON.parse(xhr.response);

// 5. Get the particupar info we want.
var jsonTitle = JSON.stringify(jsonObject["sched_current"]["songs"][0]["title"]);
var jsonAlbum = JSON.stringify(jsonObject["sched_current"]["songs"][0]["albums"][0]["name"]);
var jsonArtist = JSON.stringify(jsonObject["sched_current"]["songs"][0]["artists"][0]["name"]);

// 6. Return some string.

console.log("En lecture :", jsonTitle, "de l'album", jsonAlbum, "par", jsonArtist);


  Voir le site web de MTF
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-17 14:16   [ Edité le: 2021-01-17 14:54 ]
Bravo pour ce premier pas franchi, et merci pour ton retour d'expérience.

Comme j'avais un doute, j'ai fait un test de mon coté qui pourra intéresser Kaede. J'ai repris le code de MTF et j'ai rebasculé en méthode POST :

Code :
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://rainwave.cc/api4/info", false);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("sid=5");

Et ça fonctionne tout aussi bien. La distinction entre les méthodes GET et POST est complètement contre-intuitive si on se fie au nom, mais en réalité elles servent à la même chose.


Citation :
Le 2021-01-17 09:52, MTF a écrit :
Maintenant, prochaine étape : récupérer le console.log du code javascript pour l'intégrer comme texte dans la page QML... Voilà le code actuel du JS :

Si ça fonctionne comme je crois l'avoir compris, c'est juste remplacer le console.log() par ça dans le .qml :
Code :
musicid.text = "En lecture : " + jsonTitle + " de l'album " + jsonAlbum + " par " + jsonArtist



EDIT : par contre j'attire de nouveau ton attention sur l'usage de XMLHttpRequest en mode synchrone. Moi dans la console de mon navigateur, j'ai carrément ce gros avertissement :
Citation :
new 1.html:10 [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.

RainMakeR
Chef de Rubrique Nécrologique
Score au grosquiz
1035015 pts.

Joue à Exoprimal, The Chants, Princess Peach : Showtime

Inscrit : Apr 01, 2003
Messages : 32786
De : Toulouse

Hors ligne
Posté le: 2021-01-17 14:41
T'es t'as super bien avancé MTF, ou madame plutot .

Pour les XMLHttpRequest je les fait d'une autre facon mais si ca marche on s'en fout
_________________

Image


Kaede
Pixel visible depuis la Lune


Inscrit : Mar 06, 2002
Messages : 5248

Hors ligne
Posté le: 2021-01-17 15:27   [ Edité le: 2021-01-17 15:39 ]
Citation :
Le 2021-01-17 14:16, Youpla a écrit :
La distinction entre les méthodes GET et POST est complètement contre-intuitive si on se fie au nom, mais en réalité elles servent à la même chose.

Ca fonctionne aussi bien dans cet exemple, mais c'est parce que l'API de Rainwave est ainsi conçue (je n'avais pas fait attention, bien vu).

Je ne t'apprends sans doute rien, mais pour de nombreuses APIs c'est différent, pour une URL donnée souvent c'est l'un ou l'autre, et pas les deux, et pour de la simple consultation de données, en général c'est GET qui est utilisée.

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-17 16:41
Citation :
Le 2021-01-17 14:16, Youpla a écrit :

Bravo pour ce premier pas franchi, et merci pour ton retour d'expérience.

...

Citation :
Le 2021-01-17 09:52, MTF a écrit :
Maintenant, prochaine étape : récupérer le console.log du code javascript pour l'intégrer comme texte dans la page QML... Voilà le code actuel du JS :

Si ça fonctionne comme je crois l'avoir compris, c'est juste remplacer le console.log() par ça dans le .qml :
Code :
musicid.text = "En lecture : " + jsonTitle + " de l'album " + jsonAlbum + " par " + jsonArtist



Merci pour les encouragements...

...et là je suis à nouveau perdu En fait, je ne parviens pas à comprendre s'il faut que je c/c le code du script directement dans le QML, ou bien que je l'importe dans le header... Il y a le coup des signaux (le fameux Component.onCompleted que tu évoquais sur la page d'avant), dans lequel je m'y perds. Je comprends à quoi ils servent, mais je ne parviens pas à comprendre comment les utiliser...

  Voir le site web de MTF
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-17 17:31   [ Edité le: 2021-01-17 17:35 ]
Citation :
Le 2021-01-17 15:27, Kaede a écrit :
Je ne t'apprends sans doute rien, mais pour de nombreuses APIs c'est différent, pour une URL donnée souvent c'est l'un ou l'autre, et pas les deux, et pour de la simple consultation de données, en général c'est GET qui est utilisée.

Ah je ne connaissais pas cette convention. Tu as raison, le choix est laissé d'implémenter une méthode ou l'autre, ou les deux (sachant qu'en PHP ça doit coûter 2 lignes de codes supplémentaires de gérer les 2). Je pensais que tu disais que la méthode POST n'était pas compatible avec cet usage.


@MTF : avant de te répondre, est-ce que tu arrives à faire fonctionner cet exemple ?
https://www.cfdev.fr/faire-de-l-ajax-avec-qml

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-17 18:31
@Youpla : j'avais déjà testé, mais ça ne marchait pas car il me manque un module dans le frontend (le "import QtQuick.Controls 2.0") qui gère la classe "Button" de l'exemple, du coup, j'avais laissé tomber...

  Voir le site web de MTF
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-17 19:03
J'ai retiré le bouton et j'ai modifié pour utiliser le signal Component.onCompleted à la place.
Ça donne quoi ?

Code :
import QtQuick 2.7
// import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
id: applicationWindow
visible: true
width: 640
height: 480
title: qsTr("Salut Cyril !")

// Fonction requette AJAX
function request(url, callback) {
var http = new XMLHttpRequest();
http.open("GET", url, true);
http.onreadystatechange = function () {
if(http.readyState === XMLHttpRequest.DONE && http.status === 200) {
callback(http)
}
};
http.send();
}

GridLayout {
id: grid
columnSpacing: 10
rowSpacing: 10
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
rows: 2
columns: 1

Component.onCompleted : {
request('https://jsonplaceholder.typicode.com/posts/1', function (o) {
// affiche dans la console le retour JSON
console.log(o.responseText);
// Convertir la reponse en objet
var d = eval('new Object(' + o.responseText + ')');
// Affiche les elements depuis le json
if(d) {
console.log(d);
txtResponse.text = "Titre:n" + d.title + "nnCorps:n" + d.body;
}

});
}

Label {
id: txtResponse
text: "Réponse..."
anchors.horizontalCenter: parent.horizontalCenter
}
}
}

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-17 19:04
Je te dirai ça demain ^^ Là je vais manger, et ensuite je vais ma soirée tranquillement. Mais je regarderai ça, et je te remercie beaucoup du temps que vous passez dans ce petit projet

Edit : je pense pas que ça marchera cependant, la classe "ApplicationWindow" dépend aussi du même module... Mais je vais tenter de le remplacer par une autre classe, type "Rectangle", ça devrait marcher comme ça.

  Voir le site web de MTF
MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-18 15:21
@Youpla : Avec ce code (issu de l'exemple et modifié pour virer les trucs qui appelaient le module Controls) :

Code :


import QtQuick 2.7
// import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

Rectangle {
id: applicationWindow
visible: true
width: 640
height: 480
//title: qsTr("Salut Cyril !")

// Fonction requette AJAX
function request(url, callback) {
var http = new XMLHttpRequest();
http.open("GET", url, true);
http.onreadystatechange = function () {
if(http.readyState === XMLHttpRequest.DONE && http.status === 200) {
callback(http)
}
};
http.send();
}

GridLayout {
id: grid
columnSpacing: 10
rowSpacing: 10
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
rows: 2
columns: 1

Component.onCompleted : {
request('https://jsonplaceholder.typicode.com/posts/1', function (o) {
// affiche dans la console le retour JSON
console.log(o.responseText);
// Convertir la reponse en objet
var d = eval('new Object(' + o.responseText + ')');
// Affiche les elements depuis le json
if(d) {
console.log(d);
txtResponse.text = "Titre:n" + d.title + "nnCorps:n" + d.body;
}

});
}

Text {
id: txtResponse
text: "Réponse..."
anchors.horizontalCenter: parent.horizontalCenter

}
}
}



Le thème ne plante pas et j'ai ça :

Image

En revanche, le lastrun.log me sort ça :

Code :
2021-01-18T14:16:39 [w] file:///home/pi/.config/pegasus-frontend/themes/pegasus-theme-grid-master/layer_music/MusicMD.qml:48:3: QML Text: Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.
2021-01-18T14:16:39 [w] file:///home/pi/.config/pegasus-frontend/themes/pegasus-theme-grid-master/layer_music/MusicMD.qml:14: ReferenceError: XMLHttpRequest is not defined


  Voir le site web de MTF
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-18 20:11
Code :
2021-01-18T14:16:39 [w] file:///home/pi/.config/pegasus-frontend/themes/pegasus-theme-grid-master/layer_music/MusicMD.qml:14: ReferenceError: XMLHttpRequest is not defined


Je ne comprends pas. Tu es censé pouvoir utiliser XMLHttpRequest() en QML mais pour une raison qui m'échappe ton interpréteur dit ne pas connaitre cette méthode (cette fonction si tu préfères).

option 1) c'est juste un petit problème au niveau de ton code. Faut bidouiller un peu.
option 2) Pegasus Frontend intègre un interpréteur QML incomplet. C'est la merde.

Dans ce second cas, je ne peux que te conseiller de soumettre ce problème aux gars qui font Pegasus Frontend ou ceux qui font Retropie.

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-19 07:42
L'option 2 me surprend, mais j'étais arrivé à la même conclusion. Ça me surprend car de ce que je comprends, la méthode XMLHttp... est importé via le module Quick, que je déclare bien dans le header. J'ai trouvé confirmation dans la doc (https://doc.qt.io/archives/qt-4.8/qt-declarative-xml-xmlhttprequest-xmlhttprequest-example-qml.html) et sur cette page : https://retifrav.github.io/blog/2018/06/09/qml-xmlhttprequest/

En revanche, j'ai trouvé ça sur Stack Overflow : https://stackoverflow.com/questions/32604460/xmlhttprequest-module-not-defined-found

Apparemment, la méthode serait incluse de base dans les web browser, mais pas ailleurs ; du coup, je vais essayer de l'installer à part, via npm.

Edit : je viens de poster un message sur le discord du frontend, on verra leur retour...

  Voir le site web de MTF
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-19 08:48   [ Edité le: 2021-01-19 08:49 ]
Citation :
Le 2021-01-19 07:42, MTF a écrit :
En revanche, j'ai trouvé ça sur Stack Overflow : https://stackoverflow.com/questions/32604460/xmlhttprequest-module-not-defined-found

Apparemment, la méthode serait incluse de base dans les web browser, mais pas ailleurs ; du coup, je vais essayer de l'installer à part, via npm.


Le gars rencontre le même problème que toi mais lui programme en Node.js donc je serais très étonné qu'ajouter le package avec npm te sois d'une quelconque utilité.
Par contre peut-être qu'il existe un gestionnaire de package pour QtQuick également, ou plus simplement un paramètre à changer dans un de ses fichiers de configuration.

Mais l'hypothèse que je favorise actuellement c'est que les gars de Pegasus ont compilé QtQuick sans xmlhttprequest .

MTF
Modérateur groovy


Joue à faire l'imbécile.

Inscrit : Jan 28, 2005
Messages : 6671
De : Caen

Hors ligne
Posté le: 2021-01-19 10:17
Yup, je viens d'avoir la confirmation par le créateur sur le discord ^^

Citation :
Yes, XMLHttpRequest is not added to Pegasus


Donc, ce petit projet tombe à l'eau ^^ Dommage ! Je resterai avec juste l'adresse de la radio sous mon Kirby qui danse Merci beaucoup d'avoir pris le temps de me conseiller/de m'expliquer ! Même si cela n'a pas débouché sur ce que je voulais, j'ai la sensation d'avoir beaucoup appris ! Vous êtes géniaux !

PLOT TWIST : le créateur va voir s'il peut l'inclure, mon projet lui semble être une bonne idée ^^ Ce n'est peut-être que le début du chemin...

  Voir le site web de MTF
Youpla
Pixel monstrueux

Score au grosquiz
0002030 pts.

Inscrit : May 13, 2009
Messages : 3446
De : Villeurbanne

Hors ligne
Posté le: 2021-01-19 13:07   [ Edité le: 2021-01-19 13:07 ]
Citation :
Le 2021-01-19 10:17, MTF a écrit :
PLOT TWIST : le créateur va voir s'il peut l'inclure, mon projet lui semble être une bonne idée ^^ Ce n'est peut-être que le début du chemin...

Ah c'est cool ça. Si ça se trouve il l'avait retiré pour alléger au maximum. Ça aurait été bien qu'il signale sur son site qu'il utilise une version amputée de QtQuick, parce que je n'ai vu nulle part que XMLHttpRequest était optionnel.

Par contre Pegasus c'est un truc qui tu installes toi-même dans Retropie, ou bien c'est figé dans Retropie ?


Index du Forum » » Technique » » Retropie : récupérer des informations JSON

48 messages • page
123




Forum www.grospixels.com (© 2011-2019 Grospixels)