Markiere Beiträge im Thema als „gelesen“

Ich habe versucht, die Website zu reverse-engineeren, indem ich POST-Anfragen an „https://{hostUrl}/topics/timings“ mit Content-Type, CSRF-Token und User-Agent gesendet habe.

Hier sieht der Body (JSON) wie folgt aus:

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

Es wird ein Statuscode von 200 zurückgegeben, aber der Leseverlauf ändert sich unter https://{hostUrl}/u/USERNAME/activity/read nie.

Ich habe versucht, diesen Beitrag zu lesen, aber er war nicht sehr hilfreich:

Hier ist ein großer Teil des Codes:

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

    if r.status_code != 200:
        raise RuntimeError("Fehler beim Abrufen von CSRF")

    data = r.json()

    if "csrf" not in data:
        raise RuntimeError("Kein CSRF in der Antwort")

    return data["csrf"]

def load_topics(session, page):
    print(f"[Themen] Seite {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"[Gelesen] {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

Ich pushe das mal hoch, da ich die Antwort immer noch brauche.

Danke

Was würde passieren, wenn Sie dies als flaches "timings[post_number]": [duration_in_ms] senden? Funktioniert es?

2 „Gefällt mir“

Es scheint nicht genau zu funktionieren.

Hier ist der Codeausschnitt, den ich geändert habe.

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])

Es wird immer noch 200 zurückgegeben, aber es wird nicht aktualisiert.

Danke

Der Code sieht in Ordnung aus, ich bin mir nicht sicher, woher das Problem kommt. :confused:
Mein Bauchgefühl sagt mir, dass wir einfach etwas Offensichtliches übersehen haben :sweat_smile:

Das funktioniert:

def load_topics(session, page):
    print(f"[Themen] Lade Seite {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 
    }    

    # Verwende json=payload, um als application/json zu senden
    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 „Gefällt mir“

Vielen, vielen DANK!!!

Das funktioniert endlich.

1 „Gefällt mir“

Tatsächlich noch eine Sache.

Das ist ziemlich interessant!

  1. Es wird der Leseverlauf des Beitrags aktualisiert :white_check_mark:
  2. Die Anzahl der gelesenen Beiträge wird erhöht :white_check_mark:

ABER:

  1. Die Anzahl der gelesenen Themen wird nicht erhöht :cross_mark:

Das sind die 2, über die ich spreche!

Ziemlich interessant.

Ich wäre nicht überrascht, wenn diese Statistiken aus Leistungsgründen durch einen regulären Sidekick-Job aktualisiert würden.

Was ist Ihr Anwendungsfall, um Zeitpunkte mit einem Skript zu aktualisieren?

Ich kann mit 100%iger Sicherheit sagen, dass diese Aussage wahr ist!
Die Beitragslesungen wurden mehrmals aktualisiert, die Themenlesungen jedoch nicht. Sind sie in unterschiedlichen Intervallen? Es ist ungefähr 20 Stunden her und die Anzahl der gelesenen Beiträge steigt weiter an, aber die der gelesenen Themen nicht.

Ich möchte nur versuchen, die Endpunkte umzukehren! Das ist cool.

Ich denke, ich sollte noch etwas warten, bevor ich zurückkomme und sehe, ob sich die Werte geändert haben.

Sie können den Sidekiq-Job manuell unter /sidekiq/scheduler auslösen, wenn Sie herausfinden, um welchen es sich handelt :slight_smile:

Vielleicht ist es Jobs::DirectoryRefreshDaily.

Siehst du dasselbe im Benutzerverzeichnis unter /u?period=daily oder wöchentlich? Dort kannst du oben sehen, wann die Zahlen aktualisiert wurden.
image

Ich denke, die Zahlen für „heute“ werden einmal pro Stunde aktualisiert, während die anderen Zeiträume nur einmal pro Tag aktualisiert werden.

1 „Gefällt mir“

@Canapin, ich bin nicht der Besitzer der Website. Wenn ich es immer noch auslösen kann, indem ich einfach als normaler Benutzer angemeldet bin, teilen Sie mir bitte die Methode mit, dies zu tun.

@Moin
Die Seite, die ich verwende, hat das deaktiviert und gibt immer „Eine Liste von Community-Mitgliedern, die ihre Aktivität anzeigen, wird hier angezeigt. Im Moment ist die Liste leer, da Ihre Community noch brandneu ist!“ zurück.

In seinem Fall können Sie das nicht. Als regulärer Benutzer ist es nicht ideal, die API zu reverse-engineeren.
Wenn Sie können, versuchen Sie eine lokale Entwicklerinstallation oder eine Produktionsinstallation auf einem günstigen VPS (ein 3-4 $ Server ist in Ordnung), da Discourse keinen Hostnamen oder SMTP mehr benötigt.

1 „Gefällt mir“

Hallo @Canapin, vielen Dank für deine kontinuierliche Hilfe.

Wie würde ich das machen? Aktuell steht dort 22 Themen gelesen und 2,6 Mio. Beiträge gelesen