Commenting users scraper and coin updater

This commit is contained in:
EdiFarcas
2025-04-29 23:37:54 +03:00
parent 9a33acbf53
commit 1aa2de4500
7 changed files with 800 additions and 23 deletions
+4
View File
@@ -0,0 +1,4 @@
UPDATE UserCoins
SET coins = coins + @coinsToAdd
WHERE userHandle = @userHandle;
+2
View File
@@ -0,0 +1,2 @@
###
GET https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId=48oDy9Ni1TA&key=AIzaSyB92CRC8QVrUUXBRuW9lt6vGJUbAsSOMts
+691
View File
@@ -0,0 +1,691 @@
{
"kind": "youtube#commentThreadListResponse",
"etag": "Cq5bmzGRCQTU2uNuon4cn8NSna0",
"nextPageToken": "Z2V0X25ld2VzdF9maXJzdC0tQ2dnSWdBUVZGN2ZST0JJRkNJa2dHQUFTQlFpZElCZ0JFZ1VJaHlBWUFCSUZDS2dnR0FBU0JRaUlJQmdBSWc0S0RBalJnYm5BQmhEd2k5aXBBUQ==",
"pageInfo": {
"totalResults": 20,
"resultsPerPage": 20
},
"items": [
{
"kind": "youtube#commentThread",
"etag": "7RHdNyT-pAbo2W1hWfE3voEpkOw",
"id": "UgxoWbZV6m5popnY5a54AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "1fmFY7IyKyrcyRxMhqS12wXucbc",
"id": "UgxoWbZV6m5popnY5a54AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "Your manabox setup is dope!! (goodluck everyone on the giveaway!)",
"textOriginal": "Your manabox setup is dope!! (goodluck everyone on the giveaway!)",
"authorDisplayName": "@citadelgaminginc.4193",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_kJ7-d2r5mLWmoNvOBYpaEIkUiiRZaCFzeB7EV91OHvlCE=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@citadelgaminginc.4193",
"authorChannelId": {
"value": "UCeIOnlexRLnAGRAYTl31RTw"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-29T10:59:07Z",
"updatedAt": "2025-04-29T10:59:07Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "zzP07A9_sYXxiw6wQ_VPyTfTcgQ",
"id": "Ugy48PZAboo3x7DAqd54AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "-0skvSPUOh7aE8oGc-PBlV1JiSo",
"id": "Ugy48PZAboo3x7DAqd54AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "Fun packs",
"textOriginal": "Fun packs",
"authorDisplayName": "@jarbo261",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_nGbdkjmUoP0ohweS9LBUq5huAiKfmiKGFiVZ0jL-AGQg=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@jarbo261",
"authorChannelId": {
"value": "UC24MAkAxc4OauZ2SnJLc4rQ"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-29T08:52:47Z",
"updatedAt": "2025-04-29T08:52:47Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "plMHkiKikQGxFv7ypB7Exh57iKA",
"id": "Ugx6nhAhutbloiwYA9R4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "r7QlJI2t32s55pPO8fCz2B3lJLk",
"id": "Ugx6nhAhutbloiwYA9R4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "Super jealous of whoever wins that marsh flats",
"textOriginal": "Super jealous of whoever wins that marsh flats",
"authorDisplayName": "@josephledesma2637",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_kqKvg1lOnUXwTAKbfMYUabDlB4F4GhRWsktA-w9Ys=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@josephledesma2637",
"authorChannelId": {
"value": "UCM8_NbHRi93IL5eeMtPk23Q"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-29T05:16:53Z",
"updatedAt": "2025-04-29T05:16:53Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "t4Rtgqh_LcI1iIRqbWZtxHPNtgU",
"id": "UgyDmnQd6iqmtoVD2mh4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "eeOzg-tWU3iLHyqWqztjpUe6D8E",
"id": "UgyDmnQd6iqmtoVD2mh4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "I hope I have enough",
"textOriginal": "I hope I have enough",
"authorDisplayName": "@spookys1031",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_kFDQeAoo--lA0mcrnNTlTJg8yiy6U0AMzp16vBjD7VWw=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@spookys1031",
"authorChannelId": {
"value": "UCB_z1FeWziylCUm74gle6ng"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-29T04:25:47Z",
"updatedAt": "2025-04-29T04:25:47Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "W8_NGemQcgXN_mNnCB5_Xai_U-A",
"id": "UgzmA42mI_czg8MmjqV4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "XYjux0O5ShDFJN5Nl0f2TJR2sXc",
"id": "UgzmA42mI_czg8MmjqV4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "W pulls",
"textOriginal": "W pulls",
"authorDisplayName": "@Caden-r9z",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_nr9xE_2vBhbh6K--Fq-aive21XyEQnu2y02BiS_JoIPeuEzrRmJAz6CHewA8Z5_h4Pew=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@Caden-r9z",
"authorChannelId": {
"value": "UCicymeM5AHJ20ko-V7B6WvQ"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-29T01:53:36Z",
"updatedAt": "2025-04-29T01:53:36Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "2Wu3qQfeUnrMVKy1Ab46wtm5Ekw",
"id": "Ugykx7MIesAeGAYNZhZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "jcAWrn_ep8JUKW-M0vM07skciH0",
"id": "Ugykx7MIesAeGAYNZhZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "Yo",
"textOriginal": "Yo",
"authorDisplayName": "@adedoyinjaiyesimi8480",
"authorProfileImageUrl": "https://yt3.ggpht.com/TJY5f8AV2TE3zHliAABSewIQbv8q5lbC76b0RyHv1dfVSKQ6ZCvHQC5UHDpJohpimLE9vpaJxwg=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@adedoyinjaiyesimi8480",
"authorChannelId": {
"value": "UCzLyRnu6oqlow91DHoB5M6w"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T22:15:18Z",
"updatedAt": "2025-04-28T22:15:18Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "FC82taf9lBL8DP6txq40YfU43FA",
"id": "UgwYJ4pD_grOvg1e5tB4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "2ZMleXBFmbNDDp1r_5bmnfaqgLg",
"id": "UgwYJ4pD_grOvg1e5tB4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "I love Tarkir so much!",
"textOriginal": "I love Tarkir so much!",
"authorDisplayName": "@xXMrZentusXx",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_l1zp0gCFA-ZvOAjG4xdXwKwlqq0iVFkxcs3vGqMkb_5w=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@xXMrZentusXx",
"authorChannelId": {
"value": "UCAxqwsMQMW1g8SmOEe-gU1Q"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T20:27:01Z",
"updatedAt": "2025-04-28T20:27:01Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "w8IBXL6f6VY7lxHdjI0LoTmFEyI",
"id": "UgykL8RRnBJ3veLZHKZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "TTcvht3TN087Vvh5Atbwtn38en4",
"id": "UgykL8RRnBJ3veLZHKZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "500",
"textOriginal": "500",
"authorDisplayName": "@pastorchrisstewart6141",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_n5-X_lcPBgLL1ukm-BITDqec_VUiPxhYsQSQOyAyeQvL5l=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@pastorchrisstewart6141",
"authorChannelId": {
"value": "UC4xPfnkdAyJxW-l3LUfyfHA"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T16:58:55Z",
"updatedAt": "2025-04-28T16:58:55Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "zBVhGw9OmeV_UZxnPyjl_wDoqXc",
"id": "UgwNvwmfaDTa3tboTgt4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "r9xyzvcJ7d5SU8qBeDTH3z2_Qqo",
"id": "UgwNvwmfaDTa3tboTgt4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "terror of the peaks is a crazy pull need that card xD",
"textOriginal": "terror of the peaks is a crazy pull need that card xD",
"authorDisplayName": "@jodqjovi3743",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_mXlj4JKDtpIftdMXXwmfdNOvIW6f7NuOCT1zM4v-3Q9zY=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@jodqjovi3743",
"authorChannelId": {
"value": "UCBtU5ZW1n604-Yq9XnaosfA"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T16:28:09Z",
"updatedAt": "2025-04-28T16:28:09Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "6Skc79ENfkvYsZ3XCFPekgwMe1M",
"id": "UgzriqM8O6ZVAsj30tp4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "9ZZ45MBy4ewWEe57uJosautP-l4",
"id": "UgzriqM8O6ZVAsj30tp4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "I love opening packs but I never hit anything good XD",
"textOriginal": "I love opening packs but I never hit anything good XD",
"authorDisplayName": "@Voryum",
"authorProfileImageUrl": "https://yt3.ggpht.com/dJQHyVppgP20fmJ82uKYz8kwlIi-0WdS-sCerbhLAlqhXTonzRJJtHQKzAiKaT8bQzg4lDEXxQ=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@Voryum",
"authorChannelId": {
"value": "UCjw7cdSwqfQCHlskh18MqvQ"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T14:06:22Z",
"updatedAt": "2025-04-28T14:06:22Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "yFpCwSSBLAM5l-q4CSrdbXnw7iM",
"id": "Ugwv-GbpqzSthOQpmYF4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "ptmaoQ601Cy-po-VexiNdfA3p40",
"id": "Ugwv-GbpqzSthOQpmYF4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "comment time",
"textOriginal": "comment time",
"authorDisplayName": "@andros8856",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_n8qSBYJvOtlIzPOluPdpxo6wf5ITPDgiEXfxdiwwan_w=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@andros8856",
"authorChannelId": {
"value": "UCBioCdp0fkimeGmjcyWpuJw"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T13:04:14Z",
"updatedAt": "2025-04-28T13:04:14Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "7BcSC6Dfk8THeT1R-6lRaQ_7zLM",
"id": "UgyIr2K1BLqHr4ryEyV4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "7UyXukVQGu3YY10l7gIUQTCcsFk",
"id": "UgyIr2K1BLqHr4ryEyV4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "How so many",
"textOriginal": "How so many",
"authorDisplayName": "@derpy1015",
"authorProfileImageUrl": "https://yt3.ggpht.com/Sr0kVdVL-8hkmLoTqA-IYEjN1wNFbxBBOXqgcPhFERwIqNpkzz6WD7ZjIoHaT06a03-DYFMF=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@derpy1015",
"authorChannelId": {
"value": "UClGHRyGmEGgCrjNEFJ7zUeA"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T07:14:39Z",
"updatedAt": "2025-04-28T07:14:39Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "JP9tV4RFcygi9tDRyJmhoI5a9IE",
"id": "Ugytf8-2luPQ_3pFszt4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "ICllIHORkDbvgiEFxDEyA-S-T4g",
"id": "Ugytf8-2luPQ_3pFszt4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "300",
"textOriginal": "300",
"authorDisplayName": "@lightningheart594",
"authorProfileImageUrl": "https://yt3.ggpht.com/R0x0k60WNnv__CJR8aLvsRMIzY93AxWfDIXqe-Jdsvvl0Hb9HfWIJzRcmG4-C4LL3IAVoyTfNOM=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@lightningheart594",
"authorChannelId": {
"value": "UCqslhJAjIqkSS4VcZSavGDw"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T04:16:08Z",
"updatedAt": "2025-04-28T04:16:08Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "pHtaCJUEYROXZl_fpc7wUMuyDqY",
"id": "UgxVmE01acpyX9iOI0h4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "BKwlq7No-q7BDGG8rBNlSz36Eeo",
"id": "UgxVmE01acpyX9iOI0h4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "500",
"textOriginal": "500",
"authorDisplayName": "@lightningheart594",
"authorProfileImageUrl": "https://yt3.ggpht.com/R0x0k60WNnv__CJR8aLvsRMIzY93AxWfDIXqe-Jdsvvl0Hb9HfWIJzRcmG4-C4LL3IAVoyTfNOM=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@lightningheart594",
"authorChannelId": {
"value": "UCqslhJAjIqkSS4VcZSavGDw"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-28T04:16:04Z",
"updatedAt": "2025-04-28T04:16:04Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "XqqYhavALrKnK4U4RRmGM__RyRU",
"id": "UgwkifE-Rl15XN4C9bZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "iRpUBwmv7pZ9xmgLQ90w2QHX208",
"id": "UgwkifE-Rl15XN4C9bZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "Nice promos",
"textOriginal": "Nice promos",
"authorDisplayName": "@Nilsferd1323",
"authorProfileImageUrl": "https://yt3.ggpht.com/CUIFJvo1qfRY_nwTuGEbdbSWCzLX5oBwiEAHUd68ZPe-SPn3UUwcRtDycySxwNRBTBQhWd5J=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@Nilsferd1323",
"authorChannelId": {
"value": "UCxOIjqtMCWM0dHn0Mx3wEPQ"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-27T23:46:13Z",
"updatedAt": "2025-04-27T23:46:13Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "CpEXzESgoTSL8SRLeuVXz0Acocc",
"id": "UgzmG0EHTgr4Oouhg_Z4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "5GG7uj4KsDIFa9N_RtriItLrizo",
"id": "UgzmG0EHTgr4Oouhg_Z4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "I just want to be part of the chill community (which i just found!)",
"textOriginal": "I just want to be part of the chill community (which i just found!)",
"authorDisplayName": "@jesseleerader",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_nJFEyraLUI4G2Gw6-pn_cbTfsc6Mf64MiXqheyK1g=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@jesseleerader",
"authorChannelId": {
"value": "UCxwjdDZ7gwewDMDkatJNPBg"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-27T23:44:50Z",
"updatedAt": "2025-04-27T23:44:50Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "lp_AzYqSM1RaXVaGqAjt6jenCaM",
"id": "UgzPPn7kADSJIPA3MUB4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "y_y5GXsT1CKulsizPDW7eVw6wJU",
"id": "UgzPPn7kADSJIPA3MUB4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "500",
"textOriginal": "500",
"authorDisplayName": "@ivan_6788",
"authorProfileImageUrl": "https://yt3.ggpht.com/YzMhDFCgUt4ohhB9O2p4rM_m4hqg7QMsgccnxi_s3zUQiBFtEWrmNm95TRrwaom3IcT5NRCmYA=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@ivan_6788",
"authorChannelId": {
"value": "UCZZw_VkHq-bGYtoQpKTXcdA"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-27T21:36:58Z",
"updatedAt": "2025-04-27T21:36:58Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "NbnrQeVyF8d_xa5-HTEwfelZTu0",
"id": "Ugz-8H3PHC79804GKMl4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "8Km5eVT1wD9mdihEvk020D6iqgM",
"id": "Ugz-8H3PHC79804GKMl4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "300",
"textOriginal": "300",
"authorDisplayName": "@ivan_6788",
"authorProfileImageUrl": "https://yt3.ggpht.com/YzMhDFCgUt4ohhB9O2p4rM_m4hqg7QMsgccnxi_s3zUQiBFtEWrmNm95TRrwaom3IcT5NRCmYA=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@ivan_6788",
"authorChannelId": {
"value": "UCZZw_VkHq-bGYtoQpKTXcdA"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-27T21:36:51Z",
"updatedAt": "2025-04-27T21:36:51Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "BMFv2qscuwc8GDCgt9XAEPNRHUw",
"id": "Ugxaamle3j7uFmyl42x4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "M87q4zOCAopLb6-Dnxrrlua7fEE",
"id": "Ugxaamle3j7uFmyl42x4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "Are promo packs the same as pre release. Videos are excellent",
"textOriginal": "Are promo packs the same as pre release. Videos are excellent",
"authorDisplayName": "@BigJoeEats",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_kO4_YFEfK3ODw3QQTSbFjaG5_M3D8IST7z-VXZmnTEh-Aq3hi_OdWLaUpAEE2hmLQIiQ=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@BigJoeEats",
"authorChannelId": {
"value": "UCGftpKpFaa4YMpNZvC-L-jw"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-27T21:17:08Z",
"updatedAt": "2025-04-27T21:17:08Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
},
{
"kind": "youtube#commentThread",
"etag": "-8V7xmLsFiUjWcvhjQlwicLdDQM",
"id": "UgxlIM2LAJeACGgwTNZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"topLevelComment": {
"kind": "youtube#comment",
"etag": "Qq62cJykzYzIlYLua-nT5qkMaqc",
"id": "UgxlIM2LAJeACGgwTNZ4AaABAg",
"snippet": {
"channelId": "UCwiY7tC4YkLlGiqT9osucZg",
"videoId": "48oDy9Ni1TA",
"textDisplay": "I'm still trying to pull a Terror of the Peaks",
"textOriginal": "I'm still trying to pull a Terror of the Peaks",
"authorDisplayName": "@ErikBlythe",
"authorProfileImageUrl": "https://yt3.ggpht.com/ytc/AIdro_nNUswFd5SWLf5RHtNxLBgHiJOJYWOosZExppWT5EU_KDM=s48-c-k-c0x00ffffff-no-rj",
"authorChannelUrl": "http://www.youtube.com/@ErikBlythe",
"authorChannelId": {
"value": "UC6DSdpRKshuMIJmx8sCv02Q"
},
"canRate": true,
"viewerRating": "none",
"likeCount": 0,
"publishedAt": "2025-04-27T14:36:01Z",
"updatedAt": "2025-04-27T14:36:01Z"
}
},
"canReply": true,
"totalReplyCount": 0,
"isPublic": true
}
}
]
}
+8 -21
View File
@@ -1,6 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import handleUpdateCoins from "./AdminServer";
interface AdminClientProps { interface AdminClientProps {
email: string; email: string;
@@ -8,7 +9,8 @@ interface AdminClientProps {
export default function AdminClient({ email }: AdminClientProps) { export default function AdminClient({ email }: AdminClientProps) {
const [giveaway, setGiveaway] = useState({ title: "", description: "", value: 0, prize: "", duration: 0, endsAt: 0 }); const [giveaway, setGiveaway] = useState({ title: "", description: "", value: 0, prize: "", duration: 0, endsAt: 0 });
const [userCoins, setUserCoins] = useState({ userId: "", coins: 0 }); const [youtube_url, setYoutubeUrl] = useState("https://www.youtube.com/watch?v=48oDy9Ni1TA&ab_channel=TCGLove");
const [coin_value, setCoinValue] = useState(0);
const handleCreateGiveaway = async () => { const handleCreateGiveaway = async () => {
const response = await fetch("/api/admin/create-giveaway", { const response = await fetch("/api/admin/create-giveaway", {
@@ -25,21 +27,6 @@ export default function AdminClient({ email }: AdminClientProps) {
} }
}; };
const handleUpdateCoins = async () => {
const response = await fetch("/api/admin/update-coins", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(userCoins),
});
if (response.ok) {
alert("User coins updated successfully!");
setUserCoins({ userId: "", coins: 0 }); // Reset form
} else {
const error = await response.json();
alert(`Failed to update user coins: ${error.error}`);
}
};
return ( return (
<div className="min-h-screen bg-white text-black py-12 px-4 sm:px-6 lg:px-8"> <div className="min-h-screen bg-white text-black py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto space-y-8"> <div className="max-w-3xl mx-auto space-y-8">
@@ -97,19 +84,19 @@ export default function AdminClient({ email }: AdminClientProps) {
<input <input
type="text" type="text"
placeholder="YouTube Video URL" placeholder="YouTube Video URL"
value={userCoins.userId} value={youtube_url}
onChange={(e) => setUserCoins({ ...userCoins, userId: e.target.value })} onChange={(e) => setYoutubeUrl(e.target.value)}
className="block w-full mt-2 p-2 border rounded bg-gray-700 text-gray-200" className="block w-full mt-2 p-2 border rounded bg-gray-700 text-gray-200"
/> />
<input <input
type="number" type="number"
placeholder="Coins" placeholder="Coins"
value={userCoins.coins} value={coin_value}
onChange={(e) => setUserCoins({ ...userCoins, coins: Number(e.target.value) })} onChange={(e) => setCoinValue(Number(e.target.value))}
className="block w-full mt-2 p-2 border rounded bg-gray-700 text-gray-200" className="block w-full mt-2 p-2 border rounded bg-gray-700 text-gray-200"
/> />
<button <button
onClick={handleUpdateCoins} onClick={() => handleUpdateCoins(youtube_url, coin_value)}
className="mt-4 bg-green-600 text-white px-4 py-2 rounded" className="mt-4 bg-green-600 text-white px-4 py-2 rounded"
> >
Update Coins Update Coins
+93
View File
@@ -0,0 +1,93 @@
"use server";
import { db } from "@/lib/db";
import axios from "axios";
const handleUpdateCoins = async (youtubeUrl: string, coinValue: number) => {
// const response = await fetch("/api/admin/update-coins", {
// method: "POST",
// headers: { "Content-Type": "application/json" },
// body: JSON.stringify(userCoins),
// });
// if (response.ok) {
// alert("User coins updated successfully!");
// setUserCoins({ userId: "", coins: 0 });
// } else {
// const error = await response.json();
// alert(`Failed to update user coins: ${error.error}`);
// }
const apiKey = process.env.GOOGLE_YOUTUBE_API_KEY;
if (!apiKey) {
throw new Error("YouTube API key is not defined in the environment variables.");
}
try {
const videoId = new URL(youtubeUrl).searchParams.get("v");
if (!videoId) {
throw new Error("Invalid YouTube URL. Could not extract video ID.");
}
const params = {
part: "snippet",
videoId,
key: apiKey,
maxResults: 100,
pageToken: "",
};
let nextPageToken;
const allAuthors: string[] = [];
while (true) {
params.pageToken = nextPageToken || "";
const response = await axios.get(
`https://www.googleapis.com/youtube/v3/commentThreads`,
{ params }
);
const pageAuthors = response.data.items.map(
(item: any) => item.snippet.topLevelComment.snippet.authorDisplayName
);
allAuthors.push(...pageAuthors);
nextPageToken = response.data.nextPageToken;
if (!nextPageToken) {
break; // Exit loop if no more pages
}
}
const uniqueAuthors = Array.from(new Set(allAuthors));
// console.log("Unique authors:", uniqueAuthors);
// Use a transaction to ensure all updates are atomic
await db.$transaction(async (prisma) => {
// loop through the unique authors and update their coins
for (const author of uniqueAuthors) {
// console.log(`Updating coins for ${author} with value ${coinValue}`);
try {
await prisma.user.update({
where: { youtubeHandle: author },
data: { coins: { increment: coinValue } },
});
console.log(`Updating coins for ${author} with value ${coinValue}`);
} catch {
// console.log(`User with YouTube handle ${author} not found, skipping`);
// Continue with the next author
}
}
},{timeout: 60000}); // Set a timeout of 60 seconds for the transaction
console.log("Coins updated successfully for all authors.");
return uniqueAuthors;
} catch (error) {
console.error("Error fetching comments from YouTube API:", error);
throw error;
}
};
export default handleUpdateCoins;
+1 -1
View File
@@ -21,7 +21,7 @@ export async function POST(req: Request) {
}, },
}); });
return NextResponse.json(giveaway); return NextResponse.json(giveaway);
} catch (error) { } catch {
return NextResponse.json({ error: "Failed to create giveaway" }, { status: 500 }); return NextResponse.json({ error: "Failed to create giveaway" }, { status: 500 });
} }
} }
+1 -1
View File
@@ -15,7 +15,7 @@ export async function POST(req: Request) {
data: { coins }, data: { coins },
}); });
return NextResponse.json(user); return NextResponse.json(user);
} catch (error) { } catch {
return NextResponse.json({ error: "Failed to update user coins" }, { status: 500 }); return NextResponse.json({ error: "Failed to update user coins" }, { status: 500 });
} }
} }