Marquer les messages dans le sujet comme "lus"

J’ai essayé d’effectuer une rétro-ingénierie du site en envoyant des requêtes POST à « https://{hostUrl}/topics/timings » avec le content-type, le jeton csrf et l’agent utilisateur.

Voici à quoi ressemble le corps (json) :

payload = {
  "topic_id": topic_id,
  "topic_time": post_count * 60000,
  "timings": timings
}

Il renvoie un code d’état de 200 mais l’historique de lecture ne change jamais à https://{hostUrl}/u/USERNAME/activity/read

J’ai essayé de consulter ce post mais il n’a pas été très utile :

Voici une bonne partie du code :

def get_csrf(session):
    r = session.get(f"https://{hostUrl}/session/csrf.json")

    if r.status_code != 200:
        raise RuntimeError("Échec de l'obtention du CSRF")

    data = r.json()

    if "csrf" not in data:
        raise RuntimeError("Pas de CSRF dans la réponse")

    return data["csrf"]

def load_topics(session, page):
    print(f"[Sujets] Page {page}")

    r = session.get(
        f"https://{hostUrl}/latest.json?page={page}"
    )

    if r.status_code != 200:
        return []

    data = r.json()

    return [
        {
            "id": t["id"],
            "posts_count": t["posts_count"]
        }
        for t in data["topic_list"]["topics"]
    ]

def mark_post_as_read(session, topic_id, post_count):
    url = f"https://{hostUrl}/topics/timings"

    timings = {
        str(i): 60000
        for i in range(1, post_count + 1)
    }

    payload = {
        "topic_id": topic_id,
        "topic_time": post_count * 60000,
        "timings": timings
    }

    csrf = get_csrf(session)

    r = session.post(
        url,
        json=payload,
        headers={
            "X-CSRF-Token": csrf,
            "User-Agent": "Mozilla/5.0",
            "Content-Type": "application/json"
        }
    )

    print(f"[Lecture] {topic_id} → {r.status_code}")

    if r.status_code != 200:
        print(r.text[:300])

def tab_worker(session):
    page = 1

    while True:
        topics = load_topics(session, page)

        if not topics:
            break

        for t in topics:
            mark_post_as_read(
                session,
                t["id"],
                t["posts_count"]
            )

            time.sleep(0.4)

        page += 1

Je fais remonter ceci car j’ai toujours besoin de la réponse.

Merci

Et si vous envoyiez ceci comme un "timings[post_number]": [duration_in_ms] plat ? Est-ce que ça marche ?

2 « J'aime »

Il ne semble pas que cela fonctionne exactement.

Voici l’extrait de code que j’ai modifié.

def mark_post_as_read(session, topic_id, post_count):
    url = f"https://{hostUrl}/topics/timings"

    payload = {
        "topic_id": topic_id,
        "topic_time": post_count * 60000
    }

    for i in range(1, post_count):
        payload[f"timings[{i}]"] = 60000

    csrf = get_csrf(session)

    r = session.post(
        url,
        json=payload,
        headers={
            "X-CSRF-Token": csrf,
            "User-Agent": "Mozilla/5.0",
            "Content-Type": "application/json"
        }
    )

    print(f"[Read] {topic_id} → {r.status_code}")

    if r.status_code != 200:
        print(r.text[:300])

Il retourne toujours 200 mais n’est pas mis à jour.

Merci

Le code semble correct, je ne suis pas sûr d’où vient le problème. :confused:
Mon instinct me dit qu’il nous manque juste quelque chose d’évident quelque part :sweat_smile:

Ceci fonctionne :

def load_topics(session, page):
    print(f"[Topics] Chargement de la page {page}")
    r = session.get(f"https://{hostUrl}/latest.json?page={page}")
    if r.status_code != 200:
        return []
    return [{"id": t["id"], "posts_count": t["posts_count"]} for t in r.json()["topic_list"]["topics"]]
    timings = {
        str(i): 60000
        for i in range(1, post_count + 1)
    }
    payload = {
        "topic_id": topic_id,
        "topic_time": post_count * 60000,
        "timings": timings 
    }    

    # Utiliser json=payload pour envoyer en tant que application/json
    r = session.post(url, json=payload, headers = {
        "X-CSRF-Token": csrf,
        "User-Agent": "Mozilla/5.0",
        "X-Requested-With": "XMLHttpRequest",
        "Content-Type": "application/json"
      }
    )
1 « J'aime »

Merci BEAUCOUP !!!

Cela fonctionne enfin.

1 « J'aime »

En fait, encore une chose.

C’est plutôt intéressant !

  1. Il MET À JOUR l’historique de lecture des publications :white_check_mark:
  2. Le nombre de lectures des publications augmente :white_check_mark:

MAIS :

  1. Le nombre de lectures des sujets n’augmente pas :cross_mark:

Ce sont les 2 dont je parle !

Plutôt intéressant.

Je ne serais pas surpris si ces statistiques étaient mises à jour par une tâche périodique (sidekick job) classique, pour des raisons de performance.

Quel est votre cas d’utilisation pour mettre à jour les horaires avec un script ?

Je peux dire avec une certitude de 100% que cette affirmation est vraie !
Le nombre de messages lus a été mis à jour plusieurs fois, mais pas celui des sujets lus. Sont-ils sur des intervalles différents ? Cela fait environ 20 heures et le nombre de messages lus continue d’augmenter, mais celui des sujets lus ne bouge pas.

Je veux juste essayer de faire de l’ingénierie inverse des endpoints ! C’est cool.

Je pense que je devrais attendre un peu avant de revenir voir si les valeurs ont changé.

Vous pouvez déclencher le travail sidekiq manuellement dans /sidekiq/scheduler si vous trouvez lequel c’est :slight_smile:

Peut-être est-ce Jobs::DirectoryRefreshDaily.

Voyez-vous la même chose dans l’annuaire des utilisateurs à l’adresse /u?period=daily ou hebdomadaire ? Là, vous pouvez voir quand les chiffres ont été mis à jour en haut.
image

Je pense que les chiffres pour « aujourd’hui » sont mis à jour une fois par heure, tandis que les autres périodes ne sont mises à jour qu’une fois par jour.

1 « J'aime »

@Canapin, je ne suis pas le propriétaire du site web. Si je peux toujours le déclencher simplement en étant connecté en tant qu’utilisateur normal, faites-moi savoir la méthode pour le faire.

@Moin
Le site que j’utilise a désactivé cela et renverra toujours « Une liste des membres de la communauté montrant leur activité sera affichée ici. Pour l’instant, la liste est vide car votre communauté est toute nouvelle ! »

Dans son cas, vous ne pouvez pas. Être un utilisateur normal n’est pas idéal pour faire de l’ingénierie inverse de l’API.
Si vous le pouvez, essayez une installation de développement locale ou une installation de production sur un VPS bon marché (un serveur à 3-4 $ suffit), car Discourse n’exige plus de nom d’hôte ni de SMTP.

1 « J'aime »

Salut @Canapin, merci pour ton aide continue.

Comment ferais-je cela ? Il est actuellement indiqué 22 sujets lus et 2,6 M de messages lus