This repository has been archived on 2025-03-19. You can view files and clone it, but cannot push or open issues or pull requests.
TwitToMast/ref/classes/tweets.js
Penelope Gomez / Pogmommy ed9d5c68fd 2.0.0
2023-02-14 14:35:57 -07:00

245 lines
9.1 KiB
JavaScript

const webdriver = require('selenium-webdriver');
const By = webdriver.By;
//const { format } = require('fast-csv');
const elements = require('../functions/elements.js'); //link support.js
const XPathObjects = require('../classes/xpaths.js'); //link xpaths.js
const Args = require('../classes/arguments.js');
const args = new Args();
const support = require('../functions/support.js');
const debuglog = support.debuglog;
const funcs = require('../functions/functions.js'); //link functions.js
const mastodon = require('../functions/mastodon.js'); //link mastodon.js
const Formats = require('../classes/formats.js');
const format = new Formats();
//const homeX = new XPathObjects.TweetPaths("home"); //import xpath class object for home timeline
//const threadX = new XPathObjects.TweetPaths("thread"); //import xpath class object for thread timeline
class Tweets {
constructor(orig,i) {
//parameters
this.orig = orig;
this.index = i-1;
this.no = i;
this.processed = false;
//detect to filter out
this.isRT = false;
this.isAR = false;
this.isPin = false;
this.keep = false;
//detect to move into thread
this.isThread = false;
//processed text for posting
this.text = "";
//header
this.name = "";
this.handle = "";
this.url = "";
this.header = "";
//body
this.hasBody = false;
this.body = "";
this.hasLinks = false;
this.links = "";
//footer
this.hasVideo = false;
this.isQT = false;
this.quoteLink = "";
this.footer = "";
//media
this.hasSingleImage = false;
this.hasMultiImage = false;
this.hasImages = false;
this.imgArray = [];
this.imgCount = 0;
this.imgUrl = "";
this.iterateExists = false;
this.iteratePath = "";
//mastodon
this.id = 0;
this.prompt = 0;
this.posted = false;
if (orig == "thread") {
this.threadLength = 0;
this.entryIsOpen = false;
}
//xpaths of tweet & elements
this.x = new XPathObjects.TweetPaths(orig,i);
}
compileText(){
const sectionArray = [this.header, this.body, this.footer];
const nonEmptySections = sectionArray.filter(section => section !== '');
this.text = nonEmptySections.join('\r\n\r\n');
}
appendSection(txt, section) {
switch (section) {
case 'header':
this.header += this.header ? `\r\n${txt}` : txt;
break;
case 'body':
this.body += this.body ? `\r\n${txt}` : txt;
break;
case 'footer':
this.footer += this.footer ? `\r\n${txt}` : txt;
break;
default:
throw new Error(`Invalid section: ${section}`);
}
}
async identifyElements(driver){
await elements.waitFor(driver,this.x.tweet,args.timeOut); //WAIT FOR TWEET URL OF CURRENT ITERATE TWEET
this.isAR = await elements.doesExist(driver,this.x.ageRestricted);//IS TWEET AGE-RESTRICTED?
if (this.isAR){
return;
}
var mTweetURL = await elements.getAttribute(driver,this.x.tweetURL,'href') //GET URL OF TWEET
this.url = await mTweetURL.replace('://mobile.','://'); //SAVE TWEET URL TO TWEET OBJECT WITHOUT MOBILE
this.hasBody = await elements.doesExist(driver,this.x.tweetText);//DOES TWEET HAVE BODY TEST?
this.hasLinks = await elements.doesExist(driver,this.x.urlCard);//DOES TWEET HAVE URL CARDS
this.hasVideo = await elements.doesExist(driver,this.x.video);//DOES TWEET HAVE VIDEO MEDIA?
this.isQT = await elements.doesExist(driver, this.x.quoteTweetContent);//IS TWEET A QUOTE TWEET
this.isThread = await elements.doesExist(driver,this.x.detectThread);//IS TWEET A PART OF THREAD
this.isRT = await elements.doesExist(driver,this.x.detectRT);//CHECK FOR RETWEETS
this.isPin = await elements.doesExist(driver,this.x.pinnedTweet);//IS TWEET PINNED
this.hasSingleImage = await elements.doesExist(driver, this.x.singleImage);//DOES TWEET HAVE SINGLE IMAGE?
this.hasMultiImage = await elements.doesExist(driver,this.x.multiImage);//DOES TWEET HAVE MULTIPLE IMAGES?
this.hasImages = this.hasSingleImage || this.hasMultiImage;//DOES TWEET HAVE ANY MEDIA?
}
async getElementProperties(driver){
if (args.printMeta) { //IF TWEET HEADER IS ENABLED
debuglog("running header stuff",2);
this.handle = await elements.getText(driver,this.x.tweeterHandle);//GET TEXT OF TWEETER HANDLE (@)
this.name = await elements.getText(driver,this.x.tweeterName);//GET TEXT OF TWEETER NAME (DISPLAY NAME)
this.appendSection(`${this.name} (${this.handle})\r\n${this.url}`,'header');//COMBINE HEADER COMPONENTS WITH URL
debuglog(`Tweet Header:\r\n${this.header}`);
}
if (this.hasBody){//IF TWEET HAS BODY TEXT
debuglog("running body text stuff",2);
/*use this later to make emojis work? https://stackoverflow.com/questions/65328118/convert-img-with-alt-attribute-to-text-with-selenium-webdriver
await driver.findElement(webdriver.By.xpath(this.x.timeLine)) // GETS NUMBER OF ELEMENTS IN THREAD, SHOULD NOT ITERATE MORE THAN THIS MANY TIMES. NOT USED ANYMORE
.findElements(webdriver.By.xpath(this.x.emoji))
.then(function(elements){
debuglog("Found emoji!",2);
//this.threadLength = elements.length;
});*/
const bodyText = await elements.getText(driver,this.x.tweetText);//SET TWEET BODY TO TEXT OF TWEET
this.appendSection(bodyText,'body');
debuglog(`Tweet Body:\r\n${this.body}`);
}
if (this.hasLinks){//IF TWEET HAS URL CARD
debuglog("running url card stuff",2);
var tweetCardURL = await elements.getAttribute(driver,this.x.urlCard,"href");//GET URL OF URL CARD
this.links = await funcs.expandUrl(tweetCardURL);
this.appendSection(this.links,'body');
debuglog(`Tweet link: ${this.links}`);
}
if (this.isQT){ //IF THREAD IS A QUOTE TWEET, GET URL AND ADD TO EITHER HEADER OR FOOTER
debuglog("running quote tweet stuff",2);
await driver.findElement(By.xpath(this.x.quoteTweetContent)).sendKeys(webdriver.Key.CONTROL, webdriver.Key.ENTER);//OPEN QUOTE TWEET IN NEW TAB
this.parent = await driver.getWindowHandle();
var windows = await driver.getAllWindowHandles();
await driver.switchTo().window(windows[windows.length-1]).then(() => { //SWITCH TO NEW TAB WITH QUOTED TWEET
driver.getCurrentUrl().then(url => {
this.quoteLink = url.replace('://mobile.','://'); //MAKE MOBILE TWEET NON-MOBILE
const text = args.reQuotes //DETERMINE HOW TO FORMAT QUOTE LINK DEPENDING ON RELAVANT ARGUMENT
? `Re: ${this.quoteLink}`
: `« Quoting ${this.quoteLink} »`;
args.reQuotes ? this.appendSection(text,'header') : this.appendSection(text,'footer'); //PLACE QUOTE LINK AT HEADER OR FOOTER OF TWEET
});
driver.switchTo().window(this.parent);//SWITCH BACK TO ORIGINAL TAB
});
await driver.switchTo().window(windows[windows.length-1]);//SWITCH TO NEW TAB AGAIN BECAUSE THAT'S THE ONLY WAY I COULD MAKE THIS PART WORK
await driver.close();//CLOSE NEW TAB
await driver.switchTo().window(this.parent);//SWITCH BACK TO ORIGINAL TAB... AGAIN
debuglog(`Tweet Header: ${this.header}`)
debuglog(`Tweet Footer: ${this.footer}`);
}
if (this.hasVideo) {//IF TWEET HAS NON-POSTABLE MEDIA, APPEND FOOTER DETAILING SO
debuglog("running video stuff",2);
this.appendSection(`⚠ Original tweet had attachment(s) that couldn't be cross-posted. View it at ${homeTweet.url}`,'footer');
debuglog(`Tweet Footer: ${this.footer}`);
}
}
async downloadImages(driver,imgSavePath) {
if (this.hasSingleImage) {
debuglog(`${this.orig} Tweet #${this.no} contains a single image.`, 2)
this.imgCount = 1;
this.imgUrl = await elements.getAttribute(driver,this.x.singleImage,"src")
const jpgPath = `${imgSavePath}${this.orig == 'home' ? '' : 'r'}${this.no}.${this.imgCount}.jpg`
await funcs.downloadImage(this.imgUrl, jpgPath)
.then(debuglog)
.catch(console.error);
debuglog(`Downloaded ${this.imgCount} image from tweet #${this.no}.`, 2)
} else if (this.hasMultiImage) {
debuglog(`${this.orig} Tweet #${this.no} contains multiple images.`, 2)
this.imgCount = 0;
for (var x = 1; x < 3; x++) {
for (var y = 1; y < 3; y++) {
this.iterateExists = await elements.doesExist(driver,this.x.multiImages(x,y));
if (this.iterateExists) {
debuglog(`${x},${y} Exists!`);
this.imgUrl = await elements.getAttribute(driver,this.x.multiImages(x,y),'src')
debuglog(this.imgUrl,2);
this.imgCount++
const jpgPath = `${imgSavePath}${this.orig == 'home' ? '' : 'r'}${this.no}.${this.imgCount}.jpg`
await funcs.downloadImage(this.imgUrl, jpgPath)
.then(debuglog)
.catch(console.error);
}
}
}
debuglog(`Downloaded ${this.imgCount} images from tweet #${this.no}.`,1)
}
}
async uploadImages(imgSavePath) {
if (this.hasImages) {debuglog("Uploading images to Mastodon...",1);}
for (var f = 1; f < (this.imgCount+1); f++) {
var jpgPath = `${imgSavePath}${this.orig == 'home' ? '' : 'r'}${this.no}.${f}.jpg`
debuglog(`uploading image to mastodon: ${jpgPath}`);
var imgid = await mastodon.postMedia(jpgPath)
debuglog(`mastodon image id: ${imgid}`);
this.imgArray.push(imgid);
}
}
async printPreview(){
const postPreviewMessage = `${format.success('Mastodon Post Preview:')}
${'═'.repeat(process.stdout.columns-2)}
${this.text}
${'═'.repeat(process.stdout.columns-2)}`;
debuglog(postPreviewMessage, 1);
}
}
module.exports = Tweets