Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto claim Moments #428

Open
willvisentini opened this issue Feb 22, 2022 · 17 comments
Open

Auto claim Moments #428

willvisentini opened this issue Feb 22, 2022 · 17 comments
Labels
enhancement New feature or request

Comments

@willvisentini
Copy link

I would like to ask for an enhancement to auto-claim moments.

@willvisentini willvisentini added the enhancement New feature or request label Feb 22, 2022
@willvisentini
Copy link
Author

https://help.twitch.tv/s/article/moments

@LeoAlt8
Copy link

LeoAlt8 commented Feb 22, 2022

Great idea! I'm really looking forward to the implementation.

@K31X
Copy link

K31X commented May 8, 2022

Hope this can be done, that would be awesome.

@KillaBoi
Copy link

KillaBoi commented Jun 1, 2022

+1, would be better to autoclaim twitch moments if possible, sometimes you tab out for a few seconds and you lose the ability to claim them

@chowder
Copy link

chowder commented Aug 29, 2022

So I'm extremely keen on implementing this myself, and have started digging into how Moments are received and claimed.

I'm fairly certain that Moments come from the PubSub API by listening to the community-moments-channel-v1 topic.

They are then later claimed through the GQL API using the following mutation:

mutation CommunityMomentCallout_Claim($input: ClaimCommunityMomentInput!) {
  claimCommunityMoment(input: $input) {
    moment {
      id
    }
    error
  }
}

Now I'm missing a few pieces here - (1) the schema for ClaimCommunityMomentInput, and (2) the structure of the messages that come from the community-moments-channel-v1 topic.

Any of the following will be really helpful in helping me implement this:

  1. Give me the names of some channel that frequently create Moments
  2. Example requests/responses from the GQL claim API (this can be retrieved from the Chrome network tab right before hitting the claim button)

Or even better, if anyone here personally owns a channel with Moments - please reach out to me, I just need to capture the data for one generated Moment.

@Rakambda
Copy link
Contributor

For the PubSub topic I came to the same conclusion a month ago. It's probably the right direction. However I wasn't able to capture any packets. As this action is limited to a few per months, it's hard to predict when this happens.
I though of modifying the bot to listen that topic and log whatever arrives but I don't know if it'll be enough. We also need the claiming part (you at least found the mutation, that's a good step I guess) which first has to be done in the browser and so can't really be automated.

@chowder
Copy link

chowder commented Aug 29, 2022

So I was really lucky yesterday and managed to capture the GQL request to redeem a Moment:

[
  {
    "operationName": "CommunityMomentCallout_Claim",
    "variables": {
      "input": {
        "momentID": $MOMENT_ID
      }
    },
    "extensions": {
      "persistedQuery": {
        "version": 1,
        "sha256Hash": "e2d67415aead910f7f9ceb45a77b750a1e1d9622c936d832328a0689e054db62"
      }
    }
  }
]

However, very unfortunately I wasn't able to capture in incoming package on the PubSub websocket - but digging through the frontend JavaScript I found the following:

// ...

{
    CommunityMomentStart: "active",
    CommunityMomentClaim: "claimed",
}

// ...

if (l.type === E.qU.CommunityMomentStart) {
                        var c = {
                            momentID: l.data.moment_id,
                            type: N.S.CommunityMoment,
                            userID: null !== (i = null == t ? void 0 : t.id) && void 0 !== i ? i : null,
                            userLogin: null !== (a = null == t ? void 0 : t.login) && void 0 !== a ? a : null
                        }

Using this I think it would be reasonable to deduce that an example response from the topic might be something like:

{
  "type": "MESSAGE",
  "data": {
    "topic": "community-moments-channel-v1.<channel_id>",
    "message": "{\"type\":\"active\",\"moment_id\":<moment_id>}"
  }
}

@RakSrinaNa What do you think?

@Rakambda
Copy link
Contributor

Rakambda commented Aug 29, 2022

I can't really say much, maybe, maybe not. But this seems to be similar to what twitch do with other endpoints.
Can give a shot at it in a branch and see over time.
(I have my own fork where I'll do the implem following those info, if I find any feedback on it I'll share here obviously)

@Rakambda
Copy link
Contributor

Though the format of the json payload from the GQL is probably different. I don't think there's a message field.

You can see examples of other messages from twitch: https://github.com/RakSrinaNa/ChannelPointsMiner/tree/main/miner/src/test/resources/api/gql

@chowder
Copy link

chowder commented Aug 29, 2022

Yes, you're right. Just to clarify - the JSON payload snippet is what I'm expecting from the PubSub API when listening to the community-moments-channel-v1 topic

This is the response for the GQL CommunityMomentCallout_Claim operation that I was able to capture:

[
  {
    "data": {
      "claimCommunityMoment": {
        "moment": {
          "id": $MOMENT_ID,
          "__typename": "CommunityMoment"
        },
        "error": null,
        "__typename": "ClaimCommunityMomentPayload"
      }
    },
    "extensions": {
      "durationMilliseconds": 9,
      "operationName": "CommunityMomentCallout_Claim",
      "requestID": $REQUEST_ID
    }
  }
]

@Rakambda
Copy link
Contributor

Rakambda commented Aug 29, 2022

My bad for the above link. What Twitch send us is through the WS (PubSub) not GQL.
So it'd be more like those: https://github.com/RakSrinaNa/ChannelPointsMiner/tree/main/miner/src/test/resources/api/ws

So it'd be more like the following I think:

{
  "type": "MESSAGE",
  "data": {
    "topic": "community-moments-channel-v1.<channel_id>",
    "message": "{\"type\":\"active\",\"data\":{\"moment_id\":<moment_id>}}"
  }
}

However the type=active is probably wrong. It should be the value of E.qU.CommunityMomentStart (community-moment-start?) from the JS if you can look it up.

@chowder
Copy link

chowder commented Aug 29, 2022

The value of E.qU.CommunityMomentStart does look to be just "active" if I'm reading it right. (Just doing a string search on the Twitch JS files)

But yes agreed - I made an error, the moment_id key should be in a data object.

Thanks for the help. I'll implement this in my own fork and revert the next time I get Moment (might be a while) :)

@Rakambda
Copy link
Contributor

Rakambda commented Aug 29, 2022

Can you share the URL of the JS page ? I'd be curious to inspect it too.

Seems to be in features.chat.components.chat-command-handlers.component-8c9fbcdf482be806bb8a.js

Other things to note from the JS:

  • There is another type claimed which maybe comes from the community-moments-user-v1 topic
  • Possible errors seems to be
            e.INVALID_MOMENT_ID = "INVALID_MOMENT_ID",
            e.CLAIM_PERIOD_EXPIRED = "CLAIM_PERIOD_EXPIRED",
            e.ALREADY_CLAIMED = "ALREADY_CLAIMED",
            e.INVALID_REQUEST = "INVALID_REQUEST",

@chowder
Copy link

chowder commented Sep 7, 2022

So mining for 15+ channels who frequently create Moments paid off. 😄

Here's the payload from the PubSub API when there's a moment active:

{
  "type": "active",
  "data": {
    "moment_id": "0ad4b5b8-be38-4245-b20d-af357aec18e9",
    "channel_id": "215105998",
    "clip_slug": "SparklySmokyFriesFloof-jwMEwyARRfqhEImG"
  }
}

(Moment link: https://clips.twitch.tv/SparklySmokyFriesFloof-jwMEwyARRfqhEImG)

Everything else about claiming Moments is as we already knew it from the conversations above.

@Rakambda
Copy link
Contributor

Rakambda commented Sep 7, 2022

What a man 👏 You've done quite a lot for this, respect.

I'm curious, can you give a list of streamers that "frequently create Moments" so that it'll be easier to test implementations?

@chowder
Copy link

chowder commented Sep 7, 2022

Here were the list of streamers that I was testing this out with:

https://paste.ee/r/NdGA9/0

Alternatively this Google search query will give you pretty good results as well.

@ImpalaPUA
Copy link

This addon collects moments automatically on open tabs,

https://chrome.google.com/webstore/detail/automatic-twitch-drops-mo/kfhgpagdjjoieckminnmigmpeclkdmjm

Can you see how they auto collect it and implement it in this python script?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

8 participants
@Rakambda @chowder @ImpalaPUA @KillaBoi @K31X @LeoAlt8 @willvisentini and others