-
Notifications
You must be signed in to change notification settings - Fork 1
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
Basic error handling and inclusion of retweet removal with logs #5
Open
hybolic
wants to merge
8
commits into
baruchiro:master
Choose a base branch
from
hybolic:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+262
−17
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
6be48b5
init
hybolic 8866ce7
remove login navigation
hybolic b08eda2
args and likes
hybolic 69895a2
readme update and bugfix
hybolic 853fcce
use commander for command line arguments
baruchiro 8bba9c5
merge with pr-suggestions with minor fixes
hybolic 0cf5f4e
Merge remote-tracking branch 'origin/master' into pr/hybolic/5-3
baruchiro f2b8080
Merge remote-tracking branch 'origin/master' into pr/hybolic/5-4
baruchiro File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,6 @@ node_modules/ | |
.vscode/ | ||
|
||
dist/ | ||
data/ | ||
*_log.txt | ||
test.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,36 @@ | ||
# Delete Your Old Tweets | ||
# Delete Your Old Tweets, Retweets And Likes | ||
|
||
1. this application will require [NodeJS](https://nodejs.org/en/download/current) and [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/) to run | ||
1. [Download your Twitter archive](https://twitter.com/settings/download_your_data), which contains all your tweets. | ||
1. Locate the JSON contains your tweets, which is `data/tweet.js` (or `data/twitter-circle-tweet.js`) in the archive. | ||
2. Locate the JSON contains your tweets, which is `data/tweet.js` (`data/like.js` or `data/twitter-circle-tweet.js`) in the archive. | ||
|
||
3. Choose one of the following | ||
|
||
## To Delete tweets | ||
1. Run this project with `yarn && yarn start data/tweet.js`. | ||
1. It will wait you for login | ||
1. After login, it will delete all your tweets. | ||
2. It will wait you for login | ||
3. After login, it will delete all your tweets. | ||
|
||
## To Delete Twitter circle tweets | ||
1. Run this project with `yarn && yarn start data/twitter-circle-tweet.js`. | ||
2. It will wait you for login | ||
3. After login, it will delete all your circle tweets. | ||
|
||
|
||
## To Unlike previously Liked tweets | ||
1. Run this project with `yarn && yarn start data/like.js`. | ||
2. It will wait you for login | ||
3. After login, it will unlike your likes. | ||
|
||
|
||
## Commandline Arguments | ||
|
||
| argumensts | | | ||
| ------------- |:-------------:| | ||
| -d, --debug | writes debug information to log file | | ||
| -l, --log | writes log information to log file | | ||
| -e, --exlog | writes all information from log and debug to log file | | ||
| -n, --nolog | forces app to run without making a log file, could be helpful if removing large amounts of tweets/retweets/likes | | ||
| -s, --skip <number> | skips up to the index given, good if you had to close the app or it crashed and don't have time to rerun the entire file | | ||
| -w, --wait <number> | the delay used between actions, try not to use below 5000ms as this could cause rate limiting | | ||
| -t, --timeout <number> | the timeout amount used after tweet is loaded (helpful on low bandwidth connections), try not to use below 5000ms as this could cause rate limiting | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,209 @@ | ||
import puppeteer from "puppeteer"; | ||
import { prompt } from "./utils/terminal"; | ||
import { program } from "commander"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
import puppeteer from "puppeteer"; | ||
import { loadData } from "./load-data"; | ||
import { prompt } from "./utils/terminal"; | ||
|
||
|
||
var fileValue; | ||
|
||
|
||
const jsonFileInput = path.resolve(process.cwd(), process.argv[2]); | ||
program | ||
.arguments("<file>") | ||
//this is here because for some reason it doesn't parse the file properly? | ||
.action(function(file) { | ||
fileValue = file; | ||
}) | ||
|
||
.option("-d, --debug", | ||
"writes debug information to log file" | ||
) | ||
|
||
.option("-l, --log", | ||
"writes log information to log file", | ||
false | ||
) | ||
|
||
.option("-e, --exlog", | ||
"writes all information from log and debug to log file", | ||
true | ||
) | ||
|
||
.option("-n, --nolog", | ||
"forces app to run without making a log file, could be helpful if removing large amounts of tweets/retweets/likes" | ||
) | ||
|
||
.option( | ||
"-s, --skip <number>", | ||
"skips up to the index given, good if you had to close the app or it crashed and don't have time to rerun the entire file", | ||
"0" | ||
) | ||
|
||
.option( | ||
"-t, --timeout <number>", | ||
"the timeout amount used after tweet is loaded (helpful on low bandwidth connections), try not to use below 5000ms as this could cause rate limiting", | ||
"5000" | ||
) | ||
|
||
.option("-w, --wait <number>", | ||
"the delay used between actions, try not to use below 5000ms as this could cause rate limiting", | ||
"5000"); | ||
|
||
program.parse(); | ||
|
||
const options = program.opts(); | ||
const log = options.log; | ||
const extended_error = options.exlog; | ||
const skipTo = parseInt(options.skip); | ||
const timeout_amount = parseInt(options.timeout); | ||
const delay_amount = parseInt(options.wait); | ||
const jsonFileInput = path.resolve(process.cwd(), fileValue /*options.file*/);//again not sure if broken or just something wrong with my install | ||
const log_name = Date.now() + "_log.txt"; | ||
|
||
(async () => { | ||
const tweets = await loadData(jsonFileInput); | ||
console.log(`Found ${tweets.length} tweets`); | ||
|
||
|
||
//create new log file | ||
if (log || extended_error){ | ||
fs.writeFileSync(log_name, "Process Started"); | ||
fs.appendFileSync(log_name, "\n" + process.argv); | ||
} | ||
|
||
|
||
var tweets; | ||
var isLikes; | ||
|
||
//checks for .js files | ||
try { | ||
tweets = await loadData(jsonFileInput); | ||
console.log(`Found ${tweets.length} tweets`); | ||
isLikes = !(typeof tweets[0].tweetId === "undefined"); | ||
} catch (e) { | ||
console.log("No tweet.js, twitter-circle-tweet.js or like.js, Exiting Program"); | ||
process.exit(0); | ||
} | ||
|
||
//browser instance | ||
const browser = await puppeteer.launch({ headless: false }); | ||
const page = await browser.newPage(); | ||
await page.goto("https://twitter.com/"); | ||
|
||
//wait for interaction | ||
await prompt("Login and press enter to continue..."); | ||
|
||
for (const tweet of tweets) { | ||
await page.goto(`https://twitter.com/baruchiro/status/${tweet.id}`); | ||
const options = await page.waitForSelector('article[data-testid="tweet"][tabindex="-1"] div[aria-label=More]', { visible: true }); | ||
// click on the first found selector | ||
await options?.click(); | ||
await page.click('div[data-testid="Dropdown"] > div[role="menuitem"]'); | ||
await page.click('div[data-testid="confirmationSheetConfirm"]'); | ||
//check if user is logged in by clicking on the profile button | ||
try { | ||
await page.click('a[data-testid="AppTabBar_Profile_Link"'); | ||
page.waitForNavigation({ timeout: timeout_amount }); | ||
} catch (error) { | ||
//might not always be a not logged in issue but in the case it's not log the error to see if we can fix it | ||
if (extended_error) fs.appendFileSync(log_name, "\n" + error); | ||
|
||
//print to screen and exit log | ||
console.log("Not logged in, Exiting Program"); | ||
console.log(error); | ||
|
||
//close browser and the process | ||
await browser.close(); | ||
process.exit(0); | ||
} | ||
|
||
//only require to see where you are in the list | ||
var tweet_index = 0; | ||
|
||
for (const tweet of tweets) { | ||
tweet_index++; | ||
if (tweet_index < skipTo) continue; | ||
if (isLikes) { | ||
await page.goto(`https://twitter.com/x/status/${tweet.tweetId}`); | ||
try { | ||
//check for options menu, if it times out we log the error and continue to next instance | ||
const options = await page.waitForSelector('article[data-testid="tweet"][tabindex="-1"] div[aria-label=More]', { | ||
visible: true, | ||
timeout: timeout_amount, | ||
}); | ||
await delay(delay_amount); | ||
Comment on lines
+122
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
||
try { | ||
//check if its a liked tweet if it is un-like it | ||
await page.click('div[data-testid="unlike"]'); | ||
await delay(delay_amount * 2); | ||
|
||
//log it | ||
console.log("unliked, " + tweet_index); | ||
if (log) fs.appendFileSync(log_name, "\n" + "un-retweeted: #" + tweet_index + " ID: " + tweet.tweetId); | ||
} catch (error) { | ||
//log error and continue on | ||
console.log("Error: probably already unliked"); | ||
if (log) fs.appendFileSync(log_name, "\n" + "Errored: #" + tweet_index + " ID: " + tweet.tweetId); | ||
if (extended_error) fs.appendFileSync(log_name, "\n" + error); | ||
console.log(error); | ||
} | ||
} catch (error) { | ||
// log error and continue on | ||
console.log("Error: tweet unavalible"); | ||
if (log) fs.appendFileSync(log_name, "\n" + "Errored: #" + tweet_index + " ID: " + tweet.tweetId); | ||
if (extended_error) fs.appendFileSync(log_name, "\n" + error); | ||
console.log(error); | ||
} | ||
} else { | ||
await page.goto(`https://twitter.com/x/status/${tweet.id}`); | ||
try { | ||
//check for options menu, if it times out we log the error and continue to next instance | ||
const options = await page.waitForSelector('article[data-testid="tweet"][tabindex="-1"] div[aria-label=More]', { | ||
visible: true, | ||
timeout: timeout_amount, | ||
}); | ||
await delay(delay_amount); | ||
try { | ||
//check if its a retweet if it is un-retweet it | ||
await page.click('div[data-testid="unretweet"]'); | ||
await delay(delay_amount); | ||
|
||
//confirm un-retweet | ||
await page.click('div[data-testid="unretweetConfirm"]'); | ||
await delay(delay_amount); | ||
|
||
//log it | ||
console.log("Unretweeted, " + tweet_index); | ||
if (log) fs.appendFileSync(log_name, "\n" + "un-retweeted: #" + tweet_index + " ID: " + tweet.id); | ||
await delay(delay_amount); | ||
} catch ( | ||
e //if its not a retweet continue to tweet delete | ||
) { | ||
// click on the first found selector | ||
await options?.click(); | ||
await delay(delay_amount); | ||
|
||
// select delete | ||
await page.click('div[data-testid="Dropdown"] > div[role="menuitem"]'); | ||
await delay(delay_amount); | ||
|
||
// confirm delete | ||
await page.click('div[data-testid="confirmationSheetConfirm"]'); | ||
await delay(delay_amount); | ||
|
||
//log it | ||
console.log("Deleted, " + tweet_index); | ||
if (log) fs.appendFileSync(log_name, "\n" + "Deleted: #" + tweet_index + " ID: " + tweet.id); | ||
} | ||
} catch (error) { | ||
// log error and continue on | ||
console.log("Error: probably already deleted"); | ||
if (log) fs.appendFileSync(log_name, "\n" + "Errored: #" + tweet_index + " ID: " + tweet.id); | ||
if (extended_error) fs.appendFileSync(log_name, "\n" + error); | ||
console.log(error); | ||
} | ||
} | ||
} | ||
// close browser | ||
await browser.close(); | ||
})(); | ||
|
||
// delay function to help avoid any rate limiting or slow connection issues | ||
function delay(ms: number) { | ||
//only here just to do a quick skip | ||
if (ms == 0) return; | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The better option in my opinion is to chain all the
.option
first, and the.action
will be the last, with all the rest of the code inside it, so you don't need to decalre a globalvar fileValue
.