vogler / free-games-claimer

Automatically claims free games on the Epic Games Store, Amazon Prime Gaming and GOG.
GNU Affero General Public License v3.0
2.3k stars 142 forks source link

Epic: use data from JSON API for purchase URL #127

Closed WiLuX-Source closed 1 year ago

WiLuX-Source commented 1 year ago

parse freebies with https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions and put them in a order with a url. example would be like this

It will make code more future proof.

so it is like creating a url with "store.epicgames.com/purchase?offers=1-{namespace}-{id}

With this way we only handle Authentication with Playwright & Claim it with 1 simple button click.

vogler commented 1 year ago

image I assume the error is due to the fact that I already owned 'Never Alone'. So, we'd need to only add those games to the URL which haven't been claimed yet. I already parsed this json to get the current free games in #30, however, checking the order history with cookies alone somehow didn't work. Could try it with Playwright.

WiLuX-Source commented 1 year ago

we can just visit game pages for checking whether if its claimed or not.

vogler commented 1 year ago

Then there's no real advantage since you'd also have to deal with issues like #120 when you check the page for each game.

WiLuX-Source commented 1 year ago

Currently you get links through ui you click buttons. API takes time to change and most of the time not preffered. But game links and even /free-games can change overtime so we have that advantage if we go this route. We can also try claiming 1 by 1 and tell the user we couldn't claim. But to keep details i suggested visiting game page.

vogler commented 1 year ago

We can play around a bit. I just want to avoid adding more code / situations that complicate debugging / lead to more captchas without a clear advantage (like not checking each game page). In #30 there were some comments on alternatives.

vogler commented 1 year ago

Didn't notice any requests to their API whether a game is claimed or not. Seems like it's checked in a local database in the browser that contains all owned games: image

vogler commented 1 year ago

Check the PR. I'm always getting a captcha with it, even with a new IP. Using the purchase URL like in your example seems to be problematic.

WiLuX-Source commented 1 year ago

Strange I dont get any captchas with it.

WiLuX-Source commented 1 year ago

Maybe another person can confirm if they get one?

vogler commented 1 year ago

Did you run the code from the PR? image

WiLuX-Source commented 1 year ago

I didn't test it will let you know when i do it.

vogler commented 1 year ago

Ok, just got no captcha with #130. However, missing the response, seems like it was just a blank page afterwards.

WiLuX-Source commented 1 year ago

Yes, The blank page is the end result but It shows thanks for your order for a little bit of time. I'm sure we can capture that by waiting a text just like we did with Thanks for your order.

WiLuX-Source commented 1 year ago

It might be Thanks for your purchase I don't really remember well.

raulvasquez commented 1 year ago

https://github.com/AuroPick/epic-free-games I noticed this repository, not sure if it would helpful vs the current method.

WiLuX-Source commented 1 year ago

@raulvasquez It can help for listing the game through api and the guy went through the effort and added all of the country codes as well. But still not solving our current problem.

vogler commented 1 year ago

@raulvasquez Thanks, I added an option EG_COUNTRY in 47be85f45cb8f2aa5c17350be152f836cdf3e5ad (via). I assume country should be enough to get the correct free games for the account's country and locale just changes the language of the description texts. Will have to wait until there is some difference (however, that is seldomly the case for DE vs. US).

vogler commented 1 year ago

Using PWDEBUG=1 makes it show a captcha. Without it, you can't easily check what's going on, but looks like there really is just an empty page without any Thanks .... I then used the new RECORD=1 and checked the .har in Chrome. image This request response looks like something to wait for.

{
  "cardinalInfo": null,
  "cardinalLookUpResponse": null,
  "confirmation": "F...",
  "message": null,
  "orderPending": null,
  "receiptResponse": {
    "orderId": "F...",
    "totalPrice": 0,
    "formattedTotalPrice": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "formattedCouponDiscount": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "formattedConvenienceFee": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "taxSettings": {},
    "orderStatus": "COMPLETED",
    "type": "PURCHASE",
    "formattedPresentmentAmount": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "totalTax": 0,
    "formattedPromotionDiscount": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "salesChannelId": "epic-store-web-purchase",
    "promotionDiscount": 0,
    "rewardDiscount": 0,
    "totalDiscounted": 0,
    "currency": "EUR",
    "sumPromotions": 0,
    "id": "QUICK_PURCHASE",
    "formattedSumPromotions": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "formattedTotalTax": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "rewardVoucher": null,
    "taxType": "",
    "formattedRewardDiscount": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "purchaseOrderPriceSummary": {
      "orderPrice": { "amount": 0, "currency": "EUR" },
      "purchasePrice": {
        "convenienceFee": { "amount": 0, "currency": "EUR" },
        "discountedPrice": { "amount": 0, "currency": "EUR" },
        "totalPrice": { "amount": 0, "currency": "EUR" }
      },
      "paymentAmount": { "amount": 0, "currency": "EUR" }
    },
    "paymentCurrencyCode": "EUR",
    "paymentCurrencyAmount": 0,
    "lineOffers": [
      {
        "quantity": 1,
        "entitlementSource": "AppEpicgamesCom",
        "formattedVoucherPrice": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
        "voucherDiscount": 0,
        "formattedBasePrice": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
        "offerIdx": 1,
        "sellerId": "o-rlswgtffm6ua68662gd37xv3lmq95q",
        "rewardDiscount": 0,
        "formattedDiscountedPrice": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
        "discountedPrice": 0,
        "price": {
          "convenienceFee": { "amount": 0, "currency": "EUR" },
          "discountedPrice": { "amount": 0, "currency": "EUR" },
          "totalPrice": { "amount": 0, "currency": "EUR" },
          "revenueWithoutTax": { "amount": 0, "currency": "USD" },
          "basePayout": { "amount": 0, "currency": "USD" },
          "basePrice": { "amount": 0, "currency": "EUR" }
        },
        "namespace": "676a89b2e8344c9db39a79724150cba6",
        "offerId": "5b99274688e9465aa9d5ca5cea176cfd",
        "basePrice": 0
      }
    ],
    "merchantGroup": "EGS_MKT",
    "voucherDiscount": 0,
    "convenienceFee": 0,
    "identityId": "...",
    "redeemRewardAmount": 0,
    "formattedTotalDiscounted": { "amount": "0.00", "symbol": "€", "placement": "f", "decimals": 2, "digits": 2 },
    "status": "COMPLETED",
    "morId": "...",
    "xEpicEnv": "PUBLIC"
  },
  "syncToken": null
}
WiLuX-Source commented 1 year ago

Page should say Thank you... then it should dissappear leaving you with blank page

vogler commented 1 year ago

Page should say Thank you... then it should dissappear leaving you with blank page

I'm just getting a blank page: https://github.com/vogler/free-games-claimer/assets/493741/ad0889f0-0bc2-499f-aa3d-c2f9cb57ba7b

However, waiting for the response above (see https://github.com/vogler/free-games-claimer/pull/130/commits/32922571720e400fde592cc61253bce478652333) works.

vogler commented 1 year ago

So far, #130 saves one click() and still needs testing of the open points.

WiLuX-Source commented 1 year ago

I will be busy for a month sorry. I'm currently in another place and can't test it right away.

WiLuX-Source commented 1 year ago

Will keep you updated when i get on this.

vogler commented 1 year ago

https://github.com/vogler/free-games-claimer/pull/130/commits/4e8e8ee884adb254c8fcb63ecfb968f372f33fd7 URL construction somehow not reliable.

vogler commented 1 year ago

Tried #130 for Death Stranding on a sep. account and it failed: image

Current free game: DEATH STRANDING
  Not in library yet! Claim!
Unexpected confirm-order response. Message: We could not confirm your purchase at this time.  Please try again later.
{
  error: true,
  errorCode: null,
  message: 'We could not confirm your purchase at this time.  Please try again later.',
  messageVars: null,
  order: null,
  syncToken: '...'
}
vogler commented 1 year ago

Changed to main branch:

  1. Device not supported -> Continue
  2. EPIC GAMES STORE END USER LICENSE AGREEMENT image

https://github.com/vogler/free-games-claimer/blob/4e8e8ee884adb254c8fcb63ecfb968f372f33fd7/epic-games.js#L169-L174 Does not appear when using #130 which may be another issue.

However, that was not the problem and the issue persists. Worked fine on main branch:

Free games: [ 'https://store.epicgames.com/en-US/p/death-stranding' ]
Current free game: DEATH STRANDING
  Not in library yet! Click GET.
  Claimed successfully!
WiLuX-Source commented 1 year ago

Well then we might only use the parse current free games with api and do the claiming with normally. I'm still busy and didn't try.

vogler commented 1 year ago

130 loads https://store.epicgames.com/purchase?offers=1-d5241c76f178492ea1540fce45616757-b951f31da58449cd83d6cb1f4ca62d3a

Free games: [
  'Fallout: New Vegas - Ultimate Edition - https://store.epicgames.com/p/fallout-new-vegas--ultimate-edition'
]
Signed in as ...
  This game contains mature content recommended only for ages 18+
Current free game: Fallout: New Vegas - Ultimate Edition
  Not in library yet! Claim!
  purchaseURL: https://store.epicgames.com/purchase?offers=1-d5241c76f178492ea1540fce45616757-b951f31da58449cd83d6cb1f4ca62d3a
Unexpected confirm-order response. Message: We could not confirm your purchase at this time.  Please try again later.
{
  error: true,
  errorCode: null,
  message: 'We could not confirm your purchase at this time.  Please try again later.',
  messageVars: null,
  order: null,
  syncToken: '...'
}

image vs. main branch which loads https://store.epicgames.com/purchase?highlightColor=0078f2&offers=1-3428aaab2c674c98b3acb789dcfaa548-08834851d4a54f48b485e97caab98012&orderId&purchaseToken&showNavigation=true: image

However, those namespace/id values don't appear in the loaded https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=en-US&country=DE&allowCountries=DE

vogler commented 1 year ago

Same problem for Midnight Ghost Hunt - https://store.epicgames.com/p/midnight-ghost-hunt: https://store.epicgames.com/purchase?offers=1-d5241c76f178492ea1540fce45616757-9d5d8c66d58e412286a3f98139657ef4 https://store.epicgames.com/purchase?highlightColor=0078f2&offers=1-964f58c4c2074404bf9c359483ab1a48-0613000f1d164fc1b5dd3e5ad1376399&orderId&purchaseToken&showNavigation=true

Unsuprisingly, https://github.com/AuroPick/epic-free-games also doesn't help here:

{
  currentGames: [
    {
      title: 'Midnight Ghost Hunt',
      id: '9d5d8c66d58e412286a3f98139657ef4',
      namespace: 'd5241c76f178492ea1540fce45616757',
      description: 'A chaotic multiplayer hide-and-seek game. Possess seemingly harmless objects as Ghosts or chase them down as Hunters before the clock strikes midnight!',
      effectiveDate: '2099-01-01T00:00:00.000Z',
      offerType: 'OTHERS',
      expiryDate: null,
      viewableDate: '2023-05-25T14:25:00.000Z',
      status: 'ACTIVE',
      isCodeRedemptionOnly: true,
      keyImages: [Array],
      seller: [Object],
      productSlug: 'midnight-ghost-hunt',
      urlSlug: 'mystery-game-5',
      url: null,
      items: [Array],
      customAttributes: [Array],
      categories: [Array],
      tags: [],
      catalogNs: [Object],
      offerMappings: [],
      price: [Object],
      promotions: [Object]
    }
  ],
}

To get the correct namespace/id, one needs apparently to make two extra requests to their GraphQL API:

  1. https://store.epicgames.com/graphql?operationName=getMappingByPageSlug&variables=%7B%22pageSlug%22:%22midnight-ghost-hunt%22,%22locale%22:%22en-US%22%7D&extensions=%7B%22persistedQuery%22:%7B%22version%22:1,%22sha256Hash%22:%22781fd69ec8116125fa8dc245c0838198cdf5283e31647d08dfa27f45ee8b1f30%22%7D%7D only gives sandboxId which is the same as namespace
  2. https://store.epicgames.com/graphql?operationName=getCatalogOffer&variables=%7B%22locale%22:%22en-US%22,%22country%22:%22DE%22,%22offerId%22:%220613000f1d164fc1b5dd3e5ad1376399%22,%22sandboxId%22:%22964f58c4c2074404bf9c359483ab1a48%22%7D&extensions=%7B%22persistedQuery%22:%7B%22version%22:1,%22sha256Hash%22:%226797fe39bfac0e6ea1c5fce0ecbff58684157595fee77e446b4254ec45ee2dcb%22%7D%7D which will also give the correct id: image
WiLuX-Source commented 1 year ago

Hello there still away from my main pc,

What I can say is the safest bet would be parse games with json and do the rest of the things normally it is only a small boost but we'll get what we can get.

vogler commented 1 year ago

See above. You can base a PR on what I made. I think I won't spent time on it since it's too much brittle code for little gain.

vogler commented 1 year ago

@WiLuX-Source Any update? If not, I'll close this.

WiLuX-Source commented 1 year ago

@vogler you can close this issue we can discuss further when i make pr.