-
-
Save cptmacp/1e9a9f20f69c113a0828fea8d13cb34c to your computer and use it in GitHub Desktop.
| /** Config Starts. **/ | |
| const profiles = [ | |
| { | |
| cred: "xxxxxxxxxxxxxxxxxxxxxx", // Replace with your Endfield cred cookie value ( get from cookie ) | |
| skGameRole: "xxxxxxxxxxxx", // Replace with your Endfield skGameRole cookie value ( get from cookie ) | |
| platform: "3", | |
| vName: "1.0.0", | |
| accountName: "acc_name" // Replace with a name to identify this account( a simple identifier ) | |
| } | |
| // Add more profiles if needed | |
| ]; | |
| const discord_notify = true; | |
| const myDiscordID = "xxxxxxxxxxxxxxxxxxx"; // Replace with your Discord ID (optional, for pinging) | |
| const discordWebhook = "https://xxxx.discord.com/api/webhooks/xxxxxxxxxxx"; // Replace with your Discord webhook URL | |
| /** Config ends. **/ | |
| const attendanceUrl = 'https://zonai.skport.com/web/v1/game/endfield/attendance'; | |
| async function main() { | |
| const results = await Promise.all(profiles.map(autoClaimFunction)); | |
| if (discord_notify && discordWebhook) { | |
| postWebhook(results); | |
| } | |
| } | |
| function autoClaimFunction({ cred, skGameRole, platform, vName, accountName }) { | |
| console.log(`[${accountName}] Checking credentials and performing check-in...`); | |
| const timestamp = Math.floor(Date.now() / 1000).toString(); | |
| // Attempt to refresh token used for signing. If refresh fails, token will be empty. | |
| let token = ""; | |
| try { | |
| token = refreshToken(cred, platform, vName); | |
| console.log(`[${accountName}] Token refreshed successfully.`); | |
| } catch (e) { | |
| console.error(`[${accountName}] Token refresh failed: ${e.message}`); | |
| // proceed with empty token; API may reject if token required | |
| } | |
| const sign = generateSign('/web/v1/game/endfield/attendance', '', timestamp, token, platform, vName); | |
| const header = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0', | |
| 'Accept': '*/*', | |
| 'Accept-Language': 'en-US,en;q=0.9', | |
| 'Accept-Encoding': 'gzip, deflate, br, zstd', | |
| 'Referer': 'https://game.skport.com/', | |
| 'Content-Type': 'application/json', | |
| 'sk-language': 'en', | |
| 'sk-game-role': skGameRole, | |
| 'cred': cred, | |
| 'platform': platform, | |
| 'vName': vName, | |
| 'timestamp': timestamp, | |
| 'sign': sign, | |
| 'Origin': 'https://game.skport.com', | |
| 'Connection': 'keep-alive', | |
| 'Sec-Fetch-Dest': 'empty', | |
| 'Sec-Fetch-Mode': 'cors', | |
| 'Sec-Fetch-Site': 'same-site' | |
| }; | |
| const options = { | |
| method: 'POST', | |
| headers: header, | |
| muteHttpExceptions: true, | |
| }; | |
| let result = { | |
| name: accountName, | |
| success: false, | |
| status: "", | |
| rewards: "" | |
| }; | |
| try { | |
| const endfieldResponse = UrlFetchApp.fetch(attendanceUrl, options); | |
| const responseJson = JSON.parse(endfieldResponse.getContentText()); | |
| console.log(`[${accountName}] API Response Code: ${responseJson.code}`); | |
| if (responseJson.code === 0) { | |
| result.success = true; | |
| result.status = "✅ Check-in Successful"; | |
| if (responseJson.data && responseJson.data.awardIds) { | |
| const awards = responseJson.data.awardIds.map(award => { | |
| const resource = responseJson.data.resourceInfoMap ? responseJson.data.resourceInfoMap[award.id] : null; | |
| return resource ? `${resource.name} x${resource.count}` : (award.id || "Unknown Item"); | |
| }).join('\n'); | |
| result.rewards = awards; | |
| } else { | |
| result.rewards = "No detailed reward info."; | |
| } | |
| } else if (responseJson.code === 10001) { | |
| result.success = true; | |
| result.status = "👌 Already Checked In"; | |
| result.rewards = "Nothing to claim"; | |
| } else { | |
| result.success = false; | |
| result.status = `❌ Error (Code: ${responseJson.code})`; | |
| result.rewards = responseJson.message || "Unknown Error"; | |
| } | |
| } catch (error) { | |
| result.success = false; | |
| result.status = "💥 Exception"; | |
| result.rewards = error.message; | |
| console.error(`[${accountName}] Exception: ${error.message}`); | |
| } | |
| return result; | |
| } | |
| function postWebhook(results) { | |
| console.log('Posting to Discord webhook...'); | |
| const allSuccess = results.every(r => r.success); | |
| const hasError = !allSuccess; | |
| const embedColor = allSuccess ? 5763719 : 15548997; // Green or Red | |
| const fields = results.map(r => { | |
| return { | |
| name: `👤 ${r.name}`, | |
| value: `**Status:** ${r.status}\n**Rewards:**\n${r.rewards ? r.rewards : 'None'}`, | |
| inline: true | |
| }; | |
| }); | |
| const payload = { | |
| username: "Endfield Assistant", | |
| avatar_url: "https://pbs.twimg.com/profile_images/1984225639407529984/2_3-HRTS_400x400.jpg", | |
| embeds: [{ | |
| title: "📡 Endfield Daily Check-in Report", | |
| color: embedColor, | |
| fields: fields, | |
| footer: { | |
| text: `Time: ${new Date().toLocaleString('en-US', { timeZone: 'UTC' })} (UTC)`, | |
| icon_url: "https://assets.skport.com/assets/favicon.ico" | |
| } | |
| }] | |
| }; | |
| if (hasError && myDiscordID) { | |
| payload.content = `<@${myDiscordID}> Script encountered an error, please check logs!`; | |
| } | |
| const options = { | |
| method: 'POST', | |
| contentType: 'application/json', | |
| payload: JSON.stringify(payload), | |
| muteHttpExceptions: true | |
| }; | |
| try { | |
| UrlFetchApp.fetch(discordWebhook, options); | |
| } catch (e) { | |
| console.error("Failed to send Discord webhook: " + e.message); | |
| } | |
| } | |
| /** Helper: Refresh token used for signing **/ | |
| function refreshToken(cred, platform, vName) { | |
| const refreshUrl = 'https://zonai.skport.com/web/v1/auth/refresh'; | |
| const header = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', | |
| 'Accept': 'application/json, text/plain, */*', | |
| 'cred': cred, | |
| 'platform': platform, | |
| 'vName': vName, | |
| 'Origin': 'https://game.skport.com', | |
| 'Referer': 'https://game.skport.com/' | |
| }; | |
| const options = { | |
| method: 'GET', | |
| headers: header, | |
| muteHttpExceptions: true | |
| }; | |
| const response = UrlFetchApp.fetch(refreshUrl, options); | |
| const json = JSON.parse(response.getContentText()); | |
| if (json.code === 0 && json.data && json.data.token) { | |
| return json.data.token; | |
| } else { | |
| throw new Error(`Refresh Failed (Code: ${json.code}, Msg: ${json.message})`); | |
| } | |
| } | |
| /** Signature generation (HMAC-SHA256 then MD5) **/ | |
| function generateSign(path, body, timestamp, token, platform, vName) { | |
| let str = path + body + timestamp; | |
| const headerJson = `{"platform":"${platform}","timestamp":"${timestamp}","dId":"","vName":"${vName}"}`; | |
| str += headerJson; | |
| const hmacBytes = Utilities.computeHmacSha256Signature(str, token || ''); | |
| const hmacHex = bytesToHex(hmacBytes); | |
| const md5Bytes = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, hmacHex); | |
| return bytesToHex(md5Bytes); | |
| } | |
| function bytesToHex(bytes) { | |
| return bytes.map(function(byte) { | |
| return ('0' + (byte & 0xFF).toString(16)).slice(-2); | |
| }).join(''); | |
| } |
* You will see `cred` and `skGameRole`![]()
I can't get skGameRole , in fact I don't even have any cookie that follows the "Platform_UserID_Server" format. That tampersmonkey script also doesn't work for me @cptmacp .
* You will see `cred` and `skGameRole`![]()
I can't get
skGameRole, in fact I don't even have any cookie that follows the "Platform_UserID_Server" format. That tampersmonkey script also doesn't work for me @cptmacp .
did you enable, "Allow userscript"
After installing just open the link "https://game.skport.com/endfield/sign-in?header=0&hg_media=skport&hg_link_campaign=tools"
and you should see the popup on top right side
did you enable, "Allow userscript"
After installing just open the link "https://game.skport.com/endfield/sign-in?header=0&hg_media=skport&hg_link_campaign=tools"
and you should see the popup on top right side
Seems like it fixed itself after reinstalling the script.
@cptmacp thanks for the script. <3 Do you happen to know what to change so the name in the discord message would be a user ping? Before I could just change the variable of username to
"<@" + myDiscordID + ">. But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.
Hey, the ping will only happen in case of
https://gist.github.com/cptmacp/1e9a9f20f69c113a0828fea8d13cb34c#file-endfield_discord-js-L149
hasError is populated, it wont ping in normal scenario.
@cptmacp thanks for the script. <3 Do you happen to know what to change so the name in the discord message would be a user ping? Before I could just change the variable of username to
"<@" + myDiscordID + ">. But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.
I can send what I looked up to change the message back to the old written text instead of the new layout since I preferred the old one.



@cptmacp thanks for the script. <3
Do you happen to know what to change so the name in the discord message would be a user ping?
Before I could just change the variable of username to
"<@" + myDiscordID + ">.But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.