Advertisement
fspkwon

Twitter Profile Scraper

Jan 6th, 2025 (edited)
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.02 KB | None | 0 0
  1. var authorization = "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA"; // replace by authorization value
  2. var ua = navigator.userAgentData.brands.map(brand => `"${brand.brand}";v="${brand.version}"`).join(', ');
  3. var client_tid = "B/ZQbuFgNZtPo89968eOVD3EvUuz6BrmfQz3HAKZe9/GVJM6Hu764jlp8rZjdqY/azgFKgR2rbAhVJOwG25J24PzjqEwBA"; // replace by X-Client-Transaction-Id value
  4. var client_uuid = "***";
  5. var csrf_token = getCookie("ct0");
  6. var random_resource = "uYU5M2i12UhDvDTzN6hZPg";
  7. var random_resource_old_tweets = "H8OOoI-5ZE4NxgRr8lfyWg"
  8. var language_code = navigator.language.split("-")[0]
  9. var tweets_to_delete = []
  10. var user_id = getCookie("twid").substring(4);
  11. var username = "fspnet_fspkwon" // replace with your username
  12. var stop_signal = undefined
  13. var twitter_archive_content = undefined
  14. var twitter_archive_loading_confirmed = false
  15.  
  16. var delete_options = {
  17. /* from_archive: If you downloaded your archive from Twitter, set this to true.
  18. You will be prompt to upload the tweets.js file from it.
  19. Advantage is that this is much more reliable and faster.
  20. You can combine this with options: unretweet, match_any_keywords, tweets_to_ignore, after/before date
  21. others will be ignored
  22. */
  23. "from_archive":false,
  24. /* unretweet: seems obvious, but it unretweet if set to true */
  25. "unretweet":false,
  26. /* do_not_remove_pinned_tweet: THIS CAN FAIL. Twitter has too many different way to format their response that I cannot guarantee this to work 100%
  27. It should work for newer tweets. HOWEVER, use the "tweets_to_ignore" below and put in your pinned tweet ID, this will work 100%.
  28. 'why do you make this option then', this is a safeguard for people that forgot to add their pinned tweet in the ignore list.
  29. */
  30. "do_not_remove_pinned_tweet":true,
  31. /* delete_message_with_url_only: self explanatory, but will delete tweets that contain links */
  32. "delete_message_with_url_only":false,
  33. /* delete_specific_ids_only: Array of tweet IDs that the script will delete. The script will not delete anything else than these IDs. Any other option will be ignored.
  34. a tweet id is the number you see on the right of the url: https://x.com/USERNAME/status/1695001000000000
  35. an example of how the array can look like : ["1695001000000000", "1303001000000000"] don't forget the quotes ""
  36. */
  37. "delete_specific_ids_only":[""],
  38. /*
  39. match_any_keywords : if any of the strings is found, delete the tweet. It's OR not AND. Example : ["hello", "hi", "yo"]
  40. if no words are given, it will match all. Can be combined with delete_message_with_url_only
  41. links shouldn't be used as keywords.
  42. */
  43. "match_any_keywords":[""],
  44. /*
  45. tweets_to_ignore : give all the tweet ids that you want to keep.
  46. To find the id of the tweet, click on it, then copy the number you find in the url
  47. it looks like that : https://x.com/USERNAME/status/1695001000000000, the id here is 1695001000000000
  48. It expects strings, so add the double-quotes around it, like that : ["1695001000000000"], you can give multiple ids ofc it's an array
  49. */
  50. "tweets_to_ignore":[
  51. "00000000000000", // these
  52. "111111111111111", // ids
  53. "222222222222" // are examples, you can safely keep them or replace them by your own ids.
  54. ],
  55. /* old_tweets : IF the script worked without any error but haven't deleted some old tweets, set this to true.*/
  56. "old_tweets":false,
  57. /*
  58. after_date // before_date : allows you to delete tweets that belong in a specific time frame
  59. In the example below, tweets that were made before 2100-01-01 AND after 1900-01-01 will be deleted. (these dates are not included. It's AFTER and BEFORE)
  60. Let's say you want to delete tweets from past 6 months. Today is September 19th 2023.
  61. You would set after_date to 2023-03-18 (effectively 6 months ago) and before_date 2023-09-20 (tomorrow's date. So it deletes tweets from today too)
  62. */
  63. "after_date":new Date('1900-01-01'), // year-month-day
  64. "before_date":new Date('2100-01-01') // year-month-day
  65. }
  66.  
  67. function buildAcceptLanguageString() {
  68. const languages = navigator.languages;
  69.  
  70. // Check if we have any languages
  71. if (!languages || languages.length === 0) {
  72. return "en-US,en;q=0.9"; // Default value if nothing is available
  73. }
  74.  
  75. let q = 1;
  76. const decrement = 0.1;
  77.  
  78. return languages.map(lang => {
  79. if (q < 1) {
  80. const result = `${lang};q=${q.toFixed(1)}`;
  81. q -= decrement;
  82. return result;
  83. }
  84. q -= decrement;
  85. return lang;
  86. }).join(',');
  87. }
  88.  
  89. function getCookie(name) {
  90. const value = `; ${document.cookie}`;
  91. const parts = value.split(`; ${name}=`);
  92. if (parts.length === 2) return parts.pop().split(';').shift();
  93. }
  94.  
  95. async function sleep(ms) {
  96. return new Promise(resolve => setTimeout(resolve, ms));
  97. }
  98.  
  99. async function fetch_tweets(cursor, retry = 0) {
  100. let count = "20";
  101. let final_cursor = cursor ? `%22cursor%22%3A%22${cursor}%22%2C` : "";
  102. let resource = delete_options["old_tweets"] ? random_resource_old_tweets : random_resource
  103. let endpoint = delete_options["old_tweets"] ? "UserTweets" : "UserTweetsAndReplies"
  104. var base_url = `https://x.com/i/api/graphql/${resource}/${endpoint}`;
  105.  
  106. var variable = ""
  107. var feature = ""
  108. if (delete_options["old_tweets"] == false) {
  109. variable = `?variables=%7B%22userId%22%3A%22${user_id}%22%2C%22count%22%3A${count}%2C${final_cursor}%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D`;
  110. feature = `&features=%7B%22rweb_lists_timeline_redesign_enabled%22%3Atrue%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Afalse%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_media_download_video_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
  111. }
  112. else {
  113. variable = `?variables=%7B%22userId%22%3A%22${user_id}%22%2C%22count%22%3A${count}%2C${final_cursor}%22includePromotedContent%22%3Atrue%2C%22withQuickPromoteEligibilityTweetFields%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D`
  114. feature = `&features=%7B%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Afalse%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_media_download_video_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`
  115. }
  116.  
  117. var final_url = `${base_url}${variable}${feature}`;
  118.  
  119. const response = await fetch(final_url, {
  120. "headers": {
  121. "accept": "*/*",
  122. "accept-language": buildAcceptLanguageString(),
  123. "authorization": authorization,
  124. "content-type": "application/json",
  125. "sec-ch-ua": ua,
  126. "sec-ch-ua-mobile": "?0",
  127. "sec-ch-ua-platform": "\"Windows\"",
  128. "sec-fetch-dest": "empty",
  129. "sec-fetch-mode": "cors",
  130. "sec-fetch-site": "same-origin",
  131. "x-client-transaction-id": client_tid,
  132. "x-client-uuid": client_uuid,
  133. "x-csrf-token": csrf_token,
  134. "x-twitter-active-user": "yes",
  135. "x-twitter-auth-type": "OAuth2Session",
  136. "x-twitter-client-language": language_code
  137. },
  138. "referrer": `https://x.com/${username}/with_replies`,
  139. "referrerPolicy": "strict-origin-when-cross-origin",
  140. "body": null,
  141. "method": "GET",
  142. "mode": "cors",
  143. "credentials": "include"
  144. });
  145.  
  146. if (!response.ok) {
  147. if (response.status === 429) {
  148. console.log("Rate limit reached. Waiting 1 minute")
  149. await sleep(1000 * 60);
  150. return fetch_tweets(cursor, retry + 1)
  151. }
  152. if (retry == 5) {
  153. throw new Error("Max retries reached")
  154. }
  155. console.log(`(fetch_tweets) Network response was not ok, retrying in ${10 * (1 + retry)} seconds`);
  156. console.log(response.text())
  157. await sleep(10000 * (1 + retry));
  158. return fetch_tweets(cursor, retry + 1)
  159. }
  160. const data = await response.json();
  161. var entries = data["data"]["user"]["result"]["timeline_v2"]["timeline"]["instructions"]
  162. for (item of entries) {
  163. if (item["type"] == "TimelineAddEntries") {
  164. entries = item["entries"]
  165. }
  166. }
  167. console.log(entries);
  168. return entries;
  169. }
  170.  
  171. async function log_tweets(entries) {
  172. for (let item of entries) {
  173. if (item["entryId"].startsWith("profile-conversation") || item["entryId"].startsWith("tweet-")) {
  174. findTweetIds(item)
  175. }
  176. else if (item["entryId"].startsWith("cursor-bottom") && entries.length > 2) {
  177. let cursor_bottom = item["content"]["value"];
  178.  
  179. return cursor_bottom;
  180. }
  181. }
  182. return "finished"
  183. }
  184.  
  185. function check_keywords(text) {
  186. if (delete_options["match_any_keywords"].length == 0) {
  187. return true
  188. }
  189. for (let word of delete_options["match_any_keywords"]) {
  190. if (text.includes(word))
  191. return true
  192. }
  193. return false
  194. }
  195.  
  196. function check_date(tweet) {
  197. if (tweet['legacy'].hasOwnProperty('created_at')) {
  198. tweet_date = new Date(tweet['legacy']["created_at"])
  199. tweet_date.setHours(0, 0, 0, 0);
  200. if (tweet_date > delete_options["after_date"] && tweet_date < delete_options["before_date"]) {
  201. return true
  202. }
  203. else if (tweet_date < delete_options["after_date"]) {
  204. stop_signal = true
  205. }
  206. return false
  207. }
  208. return true
  209. }
  210.  
  211. function check_date_archive(created_at) {
  212. tweet_date = new Date(created_at)
  213. tweet_date.setHours(0, 0, 0, 0);
  214. if (tweet_date > delete_options["after_date"] && tweet_date < delete_options["before_date"]) {
  215. return true
  216. }
  217. else if (tweet_date < delete_options["after_date"]) {
  218. stop_signal = true
  219. }
  220. return false
  221. }
  222.  
  223. function check_filter(tweet) {
  224. if (tweet['legacy'].hasOwnProperty('id_str')
  225. && ( delete_options["tweets_to_ignore"].includes(tweet['legacy']["id_str"]) || delete_options["tweets_to_ignore"].includes( parseInt(tweet['legacy']["id_str"]) ) )) {
  226. return false
  227. }
  228. if (delete_options["delete_message_with_url_only"] == true)
  229. {
  230. if (tweet['legacy'].hasOwnProperty('entities') && tweet['legacy']["entities"].hasOwnProperty('urls') && tweet['legacy']["entities"]["urls"].length > 0
  231. && check_keywords(tweet['legacy']['full_text']) && check_date(tweet)) {
  232. return true
  233. }
  234. return false
  235. }
  236. if (check_keywords(tweet['legacy']['full_text']) && check_date(tweet))
  237. return true
  238. return false
  239. }
  240.  
  241. function check_filter_archive(tweet_obj) {
  242. let tweet_id = tweet_obj["id"]
  243. let tweet_str = tweet_obj["text"]
  244. let tweet_date = tweet_obj["date"]
  245. if ((delete_options["tweets_to_ignore"].includes(tweet_id) || delete_options["tweets_to_ignore"].includes( parseInt(tweet_id) ) )) {
  246. return false
  247. }
  248. if (check_keywords(tweet_str) && check_date_archive(tweet_date))
  249. return true
  250. return false
  251. }
  252.  
  253. function check_tweet_owner(obj, uid) {
  254. if (obj.hasOwnProperty('legacy') && obj['legacy'].hasOwnProperty('retweeted') && obj['legacy']['retweeted'] === true && delete_options["unretweet"] == false)
  255. return false
  256. if (obj.hasOwnProperty('user_id_str') && obj['user_id_str'] === uid)
  257. return true;
  258. else if (obj.hasOwnProperty('legacy') && obj['legacy'].hasOwnProperty('user_id_str') && obj['legacy']['user_id_str'] === uid)
  259. return true;
  260. return false
  261. }
  262.  
  263. function tweetFound(obj) {
  264. console.log(`found ${obj['legacy']['full_text']}`)
  265. }
  266.  
  267. function parseTweetsFromArchive(data) {
  268. try {
  269. const filteredIds = [];
  270.  
  271. data.forEach(item => {
  272. if (item.tweet && item.tweet.id_str) {
  273. const isInReplyToExcludedUser = item.tweet.in_reply_to_user_id_str === user_id;
  274. const startsWithRT = item.tweet.full_text.startsWith('RT ');
  275.  
  276. let tweet_obj = {}
  277. tweet_obj["id"] = item.tweet.id_str
  278. tweet_obj["text"] = item.tweet.full_text
  279. tweet_obj["date"] = item.tweet.created_at
  280. if (!isInReplyToExcludedUser
  281. && ((delete_options["unretweet"] == true && startsWithRT == true) || (delete_options["unretweet"] == false && startsWithRT == false))
  282. && check_filter_archive(tweet_obj)) {
  283. ;
  284. }
  285. else {
  286. return;
  287. }
  288. console.log("DELETING:",item.tweet.full_text)
  289. filteredIds.push(item.tweet.id_str);
  290. }
  291. });
  292.  
  293. return filteredIds;
  294. } catch (error) {
  295. console.error("Error parsing JSON:", error);
  296. return [];
  297. }
  298. }
  299.  
  300. function findTweetIds(obj) {
  301. function recurse(currentObj) {
  302. if (typeof currentObj !== 'object' || currentObj === null
  303. || (delete_options["do_not_remove_pinned_tweet"] == true && currentObj['__type'] == "TimelinePinEntry")) {
  304. return;
  305. }
  306.  
  307. if (currentObj['__typename'] === 'TweetWithVisibilityResults' && currentObj.hasOwnProperty('tweet')
  308. && check_tweet_owner(currentObj['tweet'], user_id) && check_filter(currentObj['tweet'])) {
  309. tweets_to_delete.push(currentObj['tweet']['id_str'] || currentObj['tweet']['legacy']['id_str']);
  310. tweetFound(currentObj['tweet'])
  311. }
  312.  
  313. else if (currentObj.hasOwnProperty('__typename') && currentObj['__typename'] === 'Tweet'
  314. && check_tweet_owner(currentObj, user_id) && check_filter(currentObj)) {
  315. tweets_to_delete.push(currentObj['id_str'] || currentObj['legacy']['id_str']);
  316. tweetFound(currentObj)
  317. }
  318.  
  319. for (let key in currentObj) {
  320. if (currentObj.hasOwnProperty(key)) {
  321. recurse(currentObj[key]);
  322. }
  323. }
  324. }
  325.  
  326. recurse(obj);
  327. }
  328.  
  329. async function delete_tweets(id_list) {
  330. var delete_tid = "LuSa1GYxAMxWEugf+FtQ/wjCAUkipMAU3jpjkil3ujj7oq6munDCtNaMaFmZ8bcm7CaNvi4GIXj32jp7q32nZU8zc5CyLw"
  331. var id_list_size = id_list.length
  332. var retry = 0
  333.  
  334. for (let i = 0; i < id_list_size; ++i) {
  335. const response = await fetch("https://x.com/i/api/graphql/VaenaVgh5q5ih7kvyVjgtg/DeleteTweet", {
  336. "headers": {
  337. "accept": "*/*",
  338. "accept-language": buildAcceptLanguageString(),
  339. "authorization": authorization,
  340. "content-type": "application/json",
  341. "sec-ch-ua": ua,
  342. "sec-ch-ua-mobile": "?0",
  343. "sec-ch-ua-platform": "\"Windows\"",
  344. "sec-fetch-dest": "empty",
  345. "sec-fetch-mode": "cors",
  346. "sec-fetch-site": "same-origin",
  347. "x-client-transaction-id": delete_tid,
  348. "x-client-uuid": client_uuid,
  349. "x-csrf-token": csrf_token,
  350. "x-twitter-active-user": "yes",
  351. "x-twitter-auth-type": "OAuth2Session",
  352. "x-twitter-client-language": language_code
  353. },
  354. "referrer": `https://x.com/${username}/with_replies`,
  355. "referrerPolicy": "strict-origin-when-cross-origin",
  356. "body": `{\"variables\":{\"tweet_id\":\"${id_list[i]}\",\"dark_request\":false},\"queryId\":\"VaenaVgh5q5ih7kvyVjgtg\"}`,
  357. "method": "POST",
  358. "mode": "cors",
  359. "credentials": "include"
  360. });
  361. if (!response.ok) {
  362. if (response.status === 429) {
  363. console.log("Rate limit reached. Waiting 1 minute")
  364. await sleep(1000 * 60);
  365. i -= 1;
  366. continue
  367. }
  368. if (retry == 8) {
  369. throw new Error("Max retries reached")
  370. }
  371. console.log(response.text())
  372. console.log(`(delete_tweets) Network response was not ok, retrying in ${10 * (1 + retry)} seconds`);
  373. i -= 1;
  374. await sleep(10000 * (1 + retry));
  375. continue
  376. }
  377. retry = 0
  378. console.log(`${i}/${id_list_size}`)
  379. await sleep(100);
  380. }
  381. }
  382.  
  383. var next = null
  384. var entries = undefined
  385.  
  386. if (delete_options["from_archive"] == true) {
  387. console.log("Waiting for user to load his Twitter archive")
  388.  
  389. // Create modal elements
  390. const modal = document.createElement('div');
  391. modal.id = 'myModal';
  392. modal.className = 'modal';
  393.  
  394. const modalContent = document.createElement('div');
  395. modalContent.className = 'modal-content';
  396.  
  397. const closeSpan = document.createElement('span');
  398. closeSpan.className = 'close';
  399. closeSpan.innerHTML = '&times;';
  400.  
  401. const header = document.createElement('h2');
  402. header.innerText = 'Drop Your File Here';
  403.  
  404. const dropArea = document.createElement('div');
  405. dropArea.id = 'drop-area';
  406. dropArea.className = 'drop-area';
  407. dropArea.innerHTML = '<p>Drop your tweets.js from your Twitter Archive here</p>';
  408.  
  409. // Append elements
  410. modalContent.appendChild(closeSpan);
  411. modalContent.appendChild(header);
  412. modalContent.appendChild(dropArea);
  413. modal.appendChild(modalContent);
  414. document.body.appendChild(modal);
  415.  
  416. // Add CSS styles
  417. const styles = `
  418. .modal {
  419. display: none;
  420. position: fixed;
  421. z-index: 1;
  422. left: 0;
  423. top: 0;
  424. width: 100%;
  425. height: 100%;
  426. overflow: auto;
  427. background-color: rgba(0,0,0,0.4);
  428. display: flex;
  429. align-items: center;
  430. justify-content: center;
  431. }
  432. .modal-content {
  433. background-color: #fff;
  434. margin: auto;
  435. padding: 20px;
  436. border-radius: 5px;
  437. box-shadow: 0 4px 8px rgba(0,0,0,0.2);
  438. width: 400px;
  439. text-align: center;
  440. }
  441. .close {
  442. color: #aaa;
  443. position: absolute;
  444. top: 10px;
  445. right: 20px;
  446. font-size: 24px;
  447. font-weight: bold;
  448. cursor: pointer;
  449. }
  450. .close:hover {
  451. color: black;
  452. }
  453. .drop-area {
  454. border: 2px dashed #007bff;
  455. border-radius: 5px;
  456. padding: 60px;
  457. cursor: pointer;
  458. transition: .5s ease-in-out;
  459. }
  460. .drop-area:hover {
  461. border-color: #0056b3;
  462. background-color: #dff3fb;
  463. transition: .5s ease-in-out;
  464. }
  465. .drop-area.active {
  466. background-color: #f3f4f6; /* Lighter background */
  467. border-color: #4caf50; /* Green border */
  468. color: #4caf50; /* Green text */
  469. }
  470.  
  471. .drop-area.active p {
  472. font-weight: bold;
  473. color: #4caf50;
  474. }
  475. h2 {
  476. color: #333;
  477. margin-bottom: 20px;
  478. }
  479. p {
  480. margin: 0;
  481. color: #666;
  482. }
  483. confirm-button {
  484. margin-top: 30px;
  485. background-color: rgb(0, 116, 212);
  486. border: 2px solid rgb(0, 116, 212);
  487. border-radius: 3px;
  488. }
  489. `;
  490.  
  491. const styleSheet = document.createElement("style");
  492. styleSheet.type = "text/css";
  493. styleSheet.innerText = styles;
  494. document.head.appendChild(styleSheet);
  495.  
  496. // Display modal
  497. modal.style.display = 'flex';
  498.  
  499. // Close modal on click
  500. closeSpan.onclick = function() {
  501. modal.style.display = 'none';
  502. };
  503. window.onclick = function(event) {
  504. if (event.target === modal) {
  505. modal.style.display = 'none';
  506. }
  507. };
  508. const confirmButton = document.createElement('button');
  509. confirmButton.innerText = 'Confirm';
  510. confirmButton.className = 'confirm-button';
  511. confirmButton.style.marginTop = "5px"
  512.  
  513. // Append confirm button to modal content
  514. modalContent.appendChild(confirmButton);
  515.  
  516. // Confirm button event listener
  517. confirmButton.addEventListener('click', () => {
  518. if (twitter_archive_content) {
  519. console.log("Confirmation received. File processed.");
  520. twitter_archive_loading_confirmed = true
  521. modal.style.display = 'none';
  522. // Further processing can be done here
  523. } else {
  524. console.error("No file loaded. Please load a file before confirming.");
  525. }
  526. });
  527. // Drag and Drop functionality
  528. dropArea.addEventListener('dragover', (event) => {
  529. event.stopPropagation();
  530. event.preventDefault();
  531. event.dataTransfer.dropEffect = 'copy';
  532. dropArea.style.borderColor = '#0056b3';
  533. });
  534.  
  535. dropArea.addEventListener('dragleave', (event) => {
  536. dropArea.style.borderColor = '#007bff';
  537. });
  538.  
  539. dropArea.addEventListener('drop', (event) => {
  540. event.stopPropagation();
  541. event.preventDefault();
  542. dropArea.style.borderColor = '#007bff';
  543. const files = event.dataTransfer.files;
  544.  
  545. // Process file here
  546. console.log(files[0]);
  547. });
  548.  
  549. // Click to upload functionality
  550. dropArea.onclick = function() {
  551. const fileInput = document.createElement('input');
  552. fileInput.type = 'file';
  553. fileInput.onchange = e => {
  554. // Process file here
  555. console.log(e.target.files[0]);
  556. };
  557. fileInput.click();
  558. };
  559. function readFile(file) {
  560. const reader = new FileReader();
  561. reader.onload = function(event) {
  562. const content = event.target.result;
  563.  
  564. // Split by '=' and remove the first part
  565. const parts = content.split('=');
  566. parts.shift(); // Remove the first element
  567. const jsonPart = parts.join('=').trim(); // Rejoin the rest and trim
  568.  
  569. try {
  570. const data = JSON.parse(jsonPart);
  571. twitter_archive_content = data;
  572. console.log("JSON data loaded into global variable.");
  573. } catch (e) {
  574. console.error("Error parsing JSON:", e);
  575. }
  576. };
  577. reader.onerror = function(error) {
  578. console.error("Error reading file:", error);
  579. };
  580. reader.readAsText(file); // Read the file as text
  581. }
  582.  
  583. // Modify the drop event
  584. dropArea.addEventListener('drop', (event) => {
  585. // ... [existing event handler code] ...
  586. const file = event.dataTransfer.files[0];
  587. readFile(file);
  588. });
  589.  
  590. // Modify the file input change event
  591. dropArea.onclick = function() {
  592. const fileInput = document.createElement('input');
  593. fileInput.type = 'file';
  594. fileInput.onchange = e => {
  595. const file = e.target.files[0];
  596. readFile(file);
  597. };
  598. fileInput.click();
  599. };
  600. dropArea.addEventListener('dragover', (event) => {
  601. event.stopPropagation();
  602. event.preventDefault();
  603. event.dataTransfer.dropEffect = 'copy';
  604. dropArea.classList.add('active'); // Add 'active' class
  605. });
  606.  
  607. dropArea.addEventListener('dragleave', (event) => {
  608. dropArea.classList.remove('active'); // Remove 'active' class
  609. });
  610.  
  611. dropArea.addEventListener('drop', (event) => {
  612. event.stopPropagation();
  613. event.preventDefault();
  614. dropArea.classList.remove('active'); // Remove 'active' class
  615. // Rest of your drop event code...
  616. });
  617. }
  618.  
  619. if (delete_options["from_archive"] == true) {
  620. while (twitter_archive_loading_confirmed == false) {
  621. await sleep(1000)
  622. }
  623. tweets_to_delete = parseTweetsFromArchive(twitter_archive_content)
  624. console.log(tweets_to_delete)
  625. await delete_tweets(tweets_to_delete)
  626. }
  627.  
  628.  
  629. else if (delete_options["delete_specific_ids_only"].length == 1 && delete_options["delete_specific_ids_only"][0].length == 0) {
  630. while (next != "finished" && stop_signal != true) {
  631. entries = await fetch_tweets(next);
  632. next = await log_tweets(entries);
  633. await delete_tweets(tweets_to_delete)
  634. tweets_to_delete = []
  635. await sleep(3000);
  636. }
  637. }
  638. else {
  639. await delete_tweets(delete_options["delete_specific_ids_only"]);
  640. }
  641.  
  642. console.log("DELETION COMPLETE (if error happened before this may be not true)")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement