diff --git a/social.py b/social.py
index c982d0f..7e0795a 100644
--- a/social.py
+++ b/social.py
@@ -1,2434 +1,4896 @@
-""" Script to download google maps reviews (that you create) and store them
-and then on a cron'd basis post them to social media connectors """
-import time
-import os
-from pathlib import Path
-import pathlib
-import re
-from datetime import datetime
-import ast
-import base64
-import datetime as dt
-from urllib.request import urlretrieve
-import inspect
-import requests
-#import json
-import jsonpickle
-import urllib3
-import pandas as pd
-from dateutil.relativedelta import relativedelta
-from openpyxl import load_workbook
-import instagrapi
-from moviepy.editor import VideoFileClip, concatenate_videoclips
-from selenium import webdriver
-from selenium.webdriver.common.by import By
-from selenium.common.exceptions import NoSuchElementException
-import tweepy
-#import asyncio
-#import aiohttp
-import sqlalchemy
-from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy import null, update
-import googlemaps
-import env
-from review_workflow_utils import (
- build_google_chrome_options,
- build_review_media_path,
- count_google_review_pages,
- normalize_google_media_url,
- sanitize_review_name,
- scroll_google_reviews,
- set_stealth_driver,
-)
-#import inspect
-Base = declarative_base()
-
-##################################################################################################
-
-class Users(Base):
- """Class representing a user config"""
- __tablename__ = 'userConfig'
- id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
- user = sqlalchemy.Column(sqlalchemy.String(length=11, collation="utf8"))
- instagram = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- web = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- facebook = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- tiktok = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- xtwitter = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- threads = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- yelp = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- google = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- data = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- postsperrun = sqlalchemy.Column(sqlalchemy.String(length=11, collation="utf8"))
- needreversed = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- wpAPI = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
- platform = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
- LinuxDriverLocation = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
- WindowsDriverLocation = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
- xls = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
- googleurl = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
- instagramuser = sqlalchemy.Column(sqlalchemy.String(length=32, collation="utf8"))
- instagrampass = sqlalchemy.Column(sqlalchemy.String(length=32, collation="utf8"))
- #active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
-
-##################################################################################################
-
-class Posts(Base):
- """Class representing the attributes of a post"""
- __tablename__ = 'posts'
- id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
- name = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
- comment = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
- rating = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
- picsURL = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
- picsLocalpath = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
- source = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
- date = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
- address = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
- dictPostComplete = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
- #googleurl = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
- wpurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
- businessurl = sqlalchemy.Column(sqlalchemy.String(length=2048, collation="utf8"))
- longitude = sqlalchemy.Column(sqlalchemy.Float())
- latitude = sqlalchemy.Column(sqlalchemy.Float())
- google = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- facebook = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- instagram = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- xtwitter = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- threads = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- yelp = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- web = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- tiktok = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
- #active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
- place_id = sqlalchemy.Column(sqlalchemy.String(length=126, collation="utf8"))
- review_id = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
- googledetails = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
- #businessurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
- pluscode = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
- googleurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
- visitdate = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
-
-
-##################################################################################################
-
-def preload():
- """
- Removes a specific file if it exists.
-
- Returns:
- None
- """
-
- file=pathlib.Path("./config/joeteststeele_uuid_and_cookie.json")
- if pathlib.Path.exists(file):
- pathlib.Path.unlink(file)
-# today = datetime.today().strftime('%Y-%m-%d')
- return
-
-##################################################################################################
-
-def clearlist(my_list):
- """
- Clears all elements in a list.
-
- Args:
- my_list (list): The list to be cleared.
-
- Returns:
- list: The input list with all elements cleared.
- """
-
- for listelement in my_list:
- listelement.clear
- return my_list
-
-##################################################################################################
-
-def get_auth_connect():
- """Make all connections to socials and DB, etec.."""
- connections = {}
- if env.mariadb:
- print('Connecting to MariaDB for configuration and storage')
- #from sqlalchemy import create_engine
- engine = sqlalchemy.create_engine("mysql+mysqldb://"+env.mariadbuser+":"+env.mariadbpass+
- "@"+env.mariadbserver+"/"+env.mariadbdb+"?charset=utf8mb4", echo=False)
- Session = sqlalchemy.orm.sessionmaker()
- Session.configure(bind=engine)
- session = Session()
- dbuser = session.query(Users).filter(Users.user=='joesteele').first()
- if dbuser is None:
- raise ValueError("Missing userConfig row for joesteele")
- #for userloop in usersession:
- print("- " + dbuser.user + ' ' + dbuser.googleurl)
- connections['user'] =dbuser
- posts = session.query(Posts).all()
- connections['posts'] = posts
- connections['postssession'] = session
- if env.data:
- print(' loading XLS content data source ...')
- if os.path.exists(env.xls):
- wb = load_workbook(filename = env.xls)
- xls_wb_df = pd.read_excel(env.xls)
- elif os.path.exists('./GoogleScrape/'+ env.xls):
- wb = load_workbook(filename = './GoogleScrape/'+ env.xls)
- xls_wb_df = pd.read_excel('./GoogleScrape/'+ env.xls)
- else:
- raise FileNotFoundError(f"Unable to find xls file: {env.xls}")
- ws = wb['Sheet1']
- #xls_wb_df = pd.read_excel(xls)
- connections |= {'xlsdf':xls_wb_df,'data':ws,'datawb':wb}
-# connections.update({'data':ws})
-# connections.update({'datawb':wb})
-
- sheet = wb.active
- c_row = sheet.max_row
- c_column = sheet.max_column
- #out_data=[]
- #import inspect
- #local_dict=Posts
- column_list = []
- my_list = []
- my_list_data = []
- #my_post = Posts
- #my_dict = {}
- for x in inspect.getmembers(Posts):
- if not (x[0].startswith('_') or 'metadata' in x[0]):
- column_list.append(x[0])
- # solumn_list2[0][0]
- #solumn_list2 = tuple(x for x in solumn_list2 if ('metadata' not in solumn_list2[0][0])\
- # or(not solumn_list2[0][0].startswith('_')))
-# for a in range(1, c_row + 1):
- for a in range(1, c_row + 1):
- for b in range(2, c_column+1):
- ob = sheet.cell(row=a, column=b)
- my_list.append(ob.value)
-# my_post.getattr(Posts, column_list[b]) == ob.value #my_post.(eval(b,column_list))
- #my_dict[b] = ob.value
- my_list_data.append(str(my_list))
- print (my_list)
- my_list = []
- #out_data.append(str(my_dict))
- connections['xls_list'] = my_list_data
-# connections['xls_list'] = out_data
- if env.instagram:
- print(' Connecting to Instagram ...')
- instasessionclient = instagrapi.Client()
- instasessionclient.login(env.instagramuser, env.instagrampass)
- connections['instagram'] = instasessionclient
- if env.facebook:
- print(' Connecting to facebook ...')
- # page_id_1 = facebookpageID
- # facebook_access_token = 'paste-your-page-access-token-here'
- # image_url = 'https://graph.facebook.com/{}/photos'.formatting(page_id_1)
- # image_location = 'http://image.careers-portal.co.za/f_output.jpg'
- # img_payload = {
- # 'message': msg,
- # 'url': image_location,
- # 'access_token': facebook_access_token
- # }
- # #Send the POST request
- # r = requests.post(image_url, data=img_payload)
- # print(r.text)
- connections['facebook'] = posts
- if env.yelp:
- print(' Connecting to yelp ...')
- if env.xtwitter:
- print(' Connecting to xtwitter ...')
- if env.threads:
- print(' Connecting to threads ...')
- threadssessionclient = instagrapi.Client()
- threadssessionclient.login(env.instagramuser, env.instagrampass)
- connections |= {'threads':threadssessionclient}
- if env.web:
- print(' Connecting to joeeatswhat.com ...')
- data_string = f"{env.user}:{env.password}"
- token = base64.b64encode(data_string.encode()).decode("utf-8")
- connections['web'] = {"Authorization": f"Basic {token}"}
- else:
- connections['web'] = ""
- if env.tiktok :
- print(' Connecting to Instagram ...')
- return connections
-
-##################################################################################################
-
-def get_twitter_conn_v1(api_key, api_secret, access_token, access_token_secret) -> tweepy.API:
- """Get twitter conn 1.1"""
- auth = tweepy.OAuth1UserHandler(api_key, api_secret)
- auth.set_access_token(
- access_token,
- access_token_secret,
- )
- return tweepy.API(auth)
-
-##################################################################################################
-
-def get_twitter_conn_v2(api_key, api_secret, access_token, access_token_secret) -> tweepy.Client:
- """Get twitter conn 2.0"""
- return tweepy.Client(
- consumer_key=api_key,
- consumer_secret=api_secret,
- access_token=access_token,
- access_token_secret=access_token_secret,
- )
-
-##################################################################################################
-
-def get_hastags(address, name, hashtype):
- """
- Generates hashtags based on the address, name, and type provided.
-
- Args:
- address (str): The address related to the content.
- name (str): The name associated with the content.
- hashtype (str): The type of hashtags to generate.
-
- Returns:
- str: The generated hashtags based on the input parameters.
- """
-
- name_no_spaces = re.sub( r'[^a-zA-Z]','',name)
- addressdict = address.rsplit(r' ',3)
- try:
- zip_code = addressdict[3]
- except:
- zip_code = '34787'
- try:
- state = addressdict[2]
- except:
- state = 'Florida'
- try:
- city = re.sub( r'[^a-zA-Z]','',addressdict[1])
- except:
- city = 'WinterGarden'
- if 'short' in hashtype:
- defaulttags = '#'+name_no_spaces+' #foodie #food #joeeatswhat @timberjoe'
- else:
- defaulttags = "\n\n\n#"+name_no_spaces+\
- " #foodie #music #food #travel #drinks #instagood #feedme #joeeatswhat @timberjoe"
- citytag = "#"+city
- statetag = "#"+state
- ziptag = "#"+zip_code
- if statetag in ['FL', 'fl','Fl']:
- statetag += '#Florida'
- if statetag == 'OR':
- statetag += '#Oregon'
- if statetag == 'MA':
- statetag += '#Massachusetts'
- return defaulttags+" "+citytag+" "+statetag+" "+ziptag+" "
-
-##################################################################################################
-
-# Grab a count of how far we need to scroll
-def counter_google(driver):
- """
- Counts the number of Google search results pages.
-
- Args:
- driver: The Selenium WebDriver instance.
-
- Returns:
- int: The total number of search result pages.
- """
- return count_google_review_pages(driver)
-
-##################################################################################################
-
-def make_montage_video_from_google(inphotos,cleanname):
- """
- Creates a montage video from a list of input photos.
-
- Args:
- inphotos (list): List of paths to input photo files.
-
- Returns:
- tuple: A tuple containing the path to the output video file and a boolean indicating succe
- """
-
-# Load the photos from the folder
-# Set the duration of each photo to 2 seconds
- if not inphotos:
- return False, False
- directory = inphotos[0].rsplit(r'/', 1)
- folder = directory[0]
- output = folder+"/"+cleanname+"-montage.mp4"
- if not os.path.exists(output) and len(inphotos) >0:
- video = VideoFileClip(inphotos[0])
- for photo in inphotos :
- #clip = VideoFileClip("myHolidays.mp4").subclip(50,60)
- clip = VideoFileClip(photo)
- # Concatenate the photos into a clip
- if ".jpg" in photo:
- clip.duration = 2
- try:
- video = concatenate_videoclips([video, clip], method="compose")
- except AttributeError as error:
- print(" An error occurred :", type(error).__name__) # An error occurred:
- # Load the audio file
- # audio = AudioFileClip("audio.mp3")
- # Set the audio as the soundtrack of the montage
- # montage = montage.set_audio(audio)
- # Write the final montage to a file
- outputvideo = video.write_videofile(output, fps=24)
- else:
- outputvideo = False
- return outputvideo, output
-
-##################################################################################################
-
-def is_docker():
- """
- Checks if the code is running in a Docker container.
-
- Returns:
- bool: True if running in a Docker container, False otherwise.
- """
- cgroup = Path('/proc/self/cgroup')
- #print (cgroup.read_text())
- return Path('/.dockerenv').is_file() or cgroup.is_file() and 'docker' in \
- cgroup.read_text(encoding="utf-8")
-
-##################################################################################################
-
-def post_facebook_video(group_id, video_path, auth_token, title, content, date, rating, address):
- """
- Posts a video to a Facebook group with specified details.
-
- Args:
- group_id (str): The ID of the Facebook group.
- video_path (list): List of paths to the video files to be uploaded.
- auth_token (str): The authentication token for posting to Facebook.
- title (str): The title of the video.
- content (str): Additional content to be included in the post.
- date (str): The date of the post.
- rating (str): The rating associated with the post.
- address (str): The address related to the post.
-
- Returns:
- dict or bool: The response JSON if successful, False if an error occurs.
- """
-
- url = f"https://graph-video.facebook.com/{group_id}/videos?access_token=" + auth_token
- addresshtml = re.sub(" ", ".",address)
- files = {eachfile: open(eachfile, 'rb') for eachfile in video_path}
- data = { "title":title,"description" : title + "\n"+ address+"\nGoogle map to destination: "
- r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n"+ content +
- "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title, 'long')+
- "\n\nhttps://www.joeeatswhat.com"+"\n\n","published" : True,
- "alt_text" : title
- }
- try:
- r = requests.post(url, files=files, data=data,timeout=env.request_timeout).json()
- except AttributeError as error:
- print(" An error getting date occurred:", error) # An error occurred:
- r = False
- time.sleep(env.facebooksleep)
- return r
-
-##################################################################################################
-
-##################################################################################################
-
-def post_threads_video(group_id, video_path, auth_token, title, content, date, rating, address):
- """
- Posts a video to a Facebook group with specified details.
-
- Args:
- group_id (str): The ID of the Facebook group.
- video_path (list): List of paths to the video files to be uploaded.
- auth_token (str): The authentication token for posting to Facebook.
- title (str): The title of the video.
- content (str): Additional content to be included in the post.
- date (str): The date of the post.
- rating (str): The rating associated with the post.
- address (str): The address related to the post.
-
- Returns:
- dict or bool: The response JSON if successful, False if an error occurs.
- """
- # Get url from wordpress - right now threads can only get video and pics from and external URL
-
- connect_url = f"https://graph.threads.net/v1.0/{env.threads_page_id}/threads?media_type=\
- VIDEO&video_url=https://www.example.com/images/bronz-fonz.jpg&text=#BronzFonz&\
- access_token=" + auth_token
- addresshtml = re.sub(" ", ".",address)
- files = {eachfile: open(eachfile, 'rb') for eachfile in video_path}
- data = { "title":title,"description" : title + "\n"+ address+"\nGoogle map to destination: "
- r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n"+ content +
- "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title, 'long')+
- "\n\nhttps://www.joeeatswhat.com"+"\n\n","published" : True,
- "alt_text" : title
- }
- try:
- r = requests.post(connect_url, files=files, data=data,timeout=env.request_timeout).json()
- except AttributeError as error:
- print(" An error getting date occurred:", error) # An error occurred:
- r = False
- time.sleep(env.facebooksleep)
- return r
-
-##################################################################################################
-
-def get_google_data(driver, local_outputs):
- """
- Retrieves data from Google Maps including name, address, and review details.
-
- Args:
- driver: The Selenium WebDriver instance.
- local_outputs: Output information.
-
- Returns:
- list: A list of data extracted from Google Maps.
- """
- print(' get google data...', end ="")
- # Click on more botton on each text reviews
- more_elemets = driver.find_elements(By.CSS_SELECTOR, '.w8nwRe.kyuRq')
- for list_more_element in more_elemets:
- print (".", end ="")
- list_more_element.click()
- print ("")
- # Find Pictures that have the expansion indicator to see the rest of the pictures under
- # them and click it to expose them all
- more_pics = driver.find_elements(By.CLASS_NAME, 'Tya61d')
- print(' Found extra pics',end = "")
- for list_more_pics in more_pics:
- if 'showMorePhotos' in list_more_pics.get_attribute("jsaction") :
- print('.', end = '')
- list_more_pics.click()
- print ('.')
- elements = driver.find_elements(By.CLASS_NAME, 'jftiEf')
- lst_data = []
- for data in elements:
- name = data.find_element(By.CSS_SELECTOR, 'div.d4r55.YJxk2d').text
- try:
- address = data.find_element(By.CSS_SELECTOR, 'div.RfnDt.xJVozb').text
- except NoSuchElementException :
- address = 'Unknonwn'
- print ('Name of location: ',name, ' Address:',address)
- try:
- visitdate = data.find_element(By.CSS_SELECTOR, 'span.rsqaWe').text
- except NoSuchElementException :
- visitdate = "Unknown"
- print(' Visited: ',visitdate)
- if re.match('^[a-zA-Z]+', visitdate) is None and re.match('^[a-zA-Z]+', visitdate) is\
- not None:
- #if visitdate[:1].isalpha:
- newdate,newdate2,visitdate = get_wordpress_post_date_string(visitdate, \
- str(datetime.now()))
- print(' Visited altered to : ',visitdate)
- try:
- text = data.find_element(By.CSS_SELECTOR, 'div.MyEned').text
- except NoSuchElementException :
- text = ''
- try:
- score = data.find_element(By.CSS_SELECTOR, 'span.kvMYJc').get_attribute("aria-label")
- #find_element(By.CSS_SELECTOR,'aria-label').text #) ##QA0Szd > div > div > div.w6VYqd >
- # div:nth-child(2) > div > div.e07Vkf.kA9KIf > div > div > div.m6QErb.DxyBCb.kA9KIf.dS8AEf
- # > div.m6QErb > div:nth-child(3) > div:nth-child(2) > div > div:nth-child(4) > div.DU9Pgb
- # > span.kvMYJc
- except NoSuchElementException as error:
- score = "Unknown"
- print ('Error: ',error)
- # Grab more info from google maps entry on this particular review
- needs_google_details = local_outputs['postssession'].query(Posts).filter(
- Posts.name == name,
- Posts.google.is_not(True)
- ).first() is not None
- if needs_google_details or env.forcegoogleupdate or env.block_google_maps is not True:
- gmaps = googlemaps.Client(env.googleapipass)
- place_ids = gmaps.find_place(name+address, input_type = 'textquery', fields='')
- if len(place_ids['candidates']) == 1 :
- place_id = place_ids['candidates'][0]['place_id']
- details = gmaps.place(place_id)
- # Get place details
- try:
- businessurl = details['result']['website']
- latitude = details['result']['geometry']['location']['lat']
- longitude = details['result']['geometry']['location']['lng']
- pluscode = details['result']['plus_code']['compound_code']
- googleurl = details['result']['url']
- database_update_row(name,"businessurl",businessurl,"onlyempty",local_outputs)
- database_update_row(name,"latitude",latitude,"onlyempty",local_outputs)
- database_update_row(name,"longitude",longitude,"onlyempty",local_outputs)
- database_update_row(name,"pluscode",pluscode,"onlyempty",local_outputs)
- database_update_row(name,"googleurl",googleurl,"onlyempty",local_outputs)
- database_update_row(name,"place_id",place_id,"onlyempty",local_outputs)
- database_update_row(name,"googledetails",details,"onlyempty",local_outputs)
- database_update_row(name,"google",True,"onlyempty",local_outputs)
- except KeyError as error:
- print('Error writing business details from google maps : ',error)
- else:
- print (' Post was already in database, skipping update unless you activate override')
- if env.forcegoogleupdate:
- database_update_row(name,"google",True,"forceall",local_outputs)
- pics= []
- pics2 = []
- more_specific_pics = []
- more_specific_pics = data.find_elements(By.CLASS_NAME, 'Tya61d')
- if len(more_specific_pics) > 0:
- # check to see if folder for pictures and videos already exists, if not, create it
- cleanname = sanitize_review_name(name)
- if not os.path.exists('./Output/Pics/'+cleanname):
- os.makedirs('./Output/Pics/'+cleanname)
- # Walk through all the pictures and videos for a given review
- lmpics = ''
- for lmpics in more_specific_pics:
- # Grab URL from style definiton (long multivalue string), and remove the -p-k so that
- # it is full size
- urlmedia = normalize_google_media_url(lmpics.get_attribute("style"))
- print (' Pic URL : ',urlmedia)
- pics.append(urlmedia)
- # Grab the name of the file and remove all spaces and special charecters to name the
- # folder
- filename = re.sub( r'[^a-zA-Z0-9]','', str(lmpics.get_attribute("aria-label")))
- if lmpics == more_specific_pics[0]:
- lmpics.click()
- time.sleep(2)
- #iframe = driver.find_element(By.TAG_NAME, "iframe")
- tempdate = str((driver.find_element(By.CLASS_NAME,'mqX5ad')).text).rsplit("-",1)
- visitdate = re.sub( r'[^a-zA-Z0-9]','',tempdate[1])
- #print (' Visited: ',visitdate)
- # Check to see if it has a sub div, which represents the label with the video length
- # displayed, this will be done
- # because videos are represented by pictures in the main dialogue, so we need to click
- # through and grab the video URL
- if lmpics.find_elements(By.CSS_SELECTOR,'div.fontLabelMedium.e5A3N') :
- ext='.mp4'
- lmpics.click()
- time.sleep(2)
- # After we click the right side is rendered in an inframe,
- # Store iframe web element
- iframe = driver.find_element(By.TAG_NAME, "iframe")
- # switch to selected iframe
- driver.switch_to.frame(iframe)
- # Now find button and click on button
- video_elements = driver.find_elements(By.XPATH ,'//video')
- urlmedia = str((video_elements[0]).get_attribute("src"))
- current_url = video_elements[0]._parent.current_url
- # return back away from iframe
- driver.switch_to.default_content()
- else:
- # The default path if it is not a video link
- ext='.jpg'
- filename = filename+ext
- # Test to see if file already exists, and if it does not grab the media and store
- # in location folder
- pics_local_path = build_review_media_path(name, visitdate, filename)
- if not os.path.isfile(pics_local_path):
- urlretrieve(urlmedia, pics_local_path)
- # Store the local path to be used in the excel document
- pics2.append(pics_local_path)
- if env.forcegoogleupdate:
- database_update_row(name,"review_id",current_url,"forceall",local_outputs)
- if len(pics2) > 0 and not os.path.isfile("./Output/Pics/"+cleanname+"/"+visitdate+\
- '/'+cleanname+'-montage.mp4'):
- make_montage_video_from_google(pics2,cleanname)
- for loop in pics2:
- if "montage.mp4" in loop:
- outputmontage = loop
- break
- #sif pathlib.Path.exists(outputmontage):
- pics2.append("./Output/Pics/"+cleanname+"/"+visitdate+'/'+cleanname+'-montage.mp4')
- dict_post_complete= {'google':1,'web':0,'yelp':0,'facebook':0,'xtwitter':0,
- 'instagram':0,'tiktok':0}
- lst_data.append([name , text, score,pics,pics2,"GoogleMaps",visitdate,address,
- dict_post_complete])
- if env.force_web_create:
- database_update_row(name,"visitdate",visitdate,"forceall",local_outputs)
- return lst_data
-
-##################################################################################################
-
-# Do the google_scroll
-def google_scroll(counter_google_scroll,driver):
- """
- Scrolls down a Google search results page a specified number of times.
-
- Args:
- counter_google_scroll (int): The number of times to scroll down the page.
- driver: The Selenium WebDriver instance.
-
- Returns:
- int: The result of the last scroll operation.
-
- Raises:
- AttributeError: If an error occurs during scrolling.
- """
- return scroll_google_reviews(driver, counter_google_scroll, label='google_scroll...')
-
-##################################################################################################
-
-def write_to_xlsx2(data, local_outputs):
- """
- Writes data to an Excel file and updates the database with new entries.
-
- Args:
- data: Data to be written to the Excel file.
- local_outputs: Output information.
-
- Returns:
- Data: The data that was written to the Excel file.
- """
-
- print('write to excel...')
- sqlalchemy.null()
- cols = ["name", "comment", 'rating','picsURL','picsLocalpath','source','date','address',
- 'dictPostComplete']
- cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
- 'address','dictPostComplete']
- df = pd.DataFrame(data, columns=cols)
- df2 = pd.DataFrame(local_outputs['xlsdf'].values, columns=cols2)
- #df2 = df1.where((pd.notnull(df)), None) # take out NAN problems
- #df3.astype(object).where(pd.notnull(df2), None)
- print ('Dropped items not included in sync to database: ',df2.dropna(inplace=True))
- rows = list(data)
- if env.needreversed:
- rows = reversed(rows)
- #jsonposts = json.dumps(local_outputs['posts'], default=Posts)
- print("Encode Object into JSON formatted Data using jsonpickle")
- jsonposts = jsonpickle.encode(local_outputs['posts'], unpicklable=False)
- for processrow in df2.values:
- if processrow[1] in df.values:
- print (' Row ',processrow.id,' ', processrow.name ,' already in XLS sheet')
- d2_row = Posts(name=processrow.name ,comment=processrow.comment,rating=\
- processrow.rating,picsURL=processrow.picsURL,pics_local_path=processrow.\
- picsLocalpath,source=processrow.source,date=processrow.date,address=processrow.\
- address,dict_post_complete=processrow.dictPostComplete)
- elif processrow.name is not None:
-# Create a Python dictionary object with all the column values
-# d_row = {'name':processrow.name ,'comment':processrow.comment,'rating':processrow.rating,
-# 'picsURL':processrow.picsURL,'pics_local_path':processrow.picsLocalpath, 'source':\
-# processrow.source,'date':processrow.date,'address':processrow.address,'dict_post_complete'\
-# :processrow.dictPostComplete}
- d2_row = Posts(name=processrow.name ,comment=processrow.comment,rating=processrow.\
- rating,picsURL=processrow.picsURL,pics_local_path=processrow.picsLocalpath,\
- source=processrow.source,date=processrow.date,address=processrow.address,\
- dict_post_complete=processrow.dictPostComplete)
- print (' Row ',processrow[0],' ', processrow.name ,' added to XLS sheet')
- # Append the above Python dictionary object as a row to the existing pandas DataFrame
- # Using the DataFrame.append() function
- try:
- if processrow.name in jsonposts : #local_outputs['posts']):
- print (' Row ',processrow[0],' ', processrow.name ,' already in Database')
- else:
- local_outputs['postssession'].add(d2_row)
- local_outputs['postssession'].commit()
- print (' Row ',processrow[0],' ', processrow.name ,' added to Database')
- except AttributeError as error:
- print(' Not able to write to post data table: ' , type(error))
- local_outputs['postssession'].rollback()
- raise
- df.to_excel(env.xls)
- return data
-
-##################################################################################################
-
-def write_to_database(data, local_outputs):
- """
- Writes data to the database and updates the database with new entries.
-
- Args:
- data: Data to be written to the database.
- local_outputs: Local output information.
-
- Returns:
- Data: The data that was written to the database.
- """
- column_list=[]
- print('write to database ...')
- for x in inspect.getmembers(Posts):
-# if not (x[0].startswith('_') or 'metadata' in x[0] or 'registry' in x[0] or 'id' in x[0]):
- if not (x[0].startswith('_') or 'metadata' in x[0] or 'registry' in x[0]):
- column_list.append(x[0])
- #cols = ["name", "comment", 'rating','picsURL','picsLocalpath','source','date','address',
- # 'dictPostComplete','visitdate']
- #cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
- # 'address','dictPostComplete','visitdate']
- #df = pd.DataFrame(local_outputs["xls"], columns=cols)
-# df = pd.DataFrame(local_outputs['xlsdf'])
- df = pd.DataFrame(local_outputs['xlsdf'].values, columns=column_list)
- #df2 = pd.DataFrame(local_outputs['posts'], columns=column_list)
- df2 = pd.DataFrame(local_outputs['posts'])
- # print ('Dropped items not included in sync to database: ',df2.dropna(inplace=True))
-# rows = list(data)
- # if env.needreversed:
- # rows = reversed(rows)
- #jsonposts = json.dumps(local_outputs['posts'], default=Posts)
- df.to_excel(env.xls)
- print("Encode Object into JSON formatted Data using jsonpickle")
- jsonposts = jsonpickle.encode(local_outputs['posts'], unpicklable=False)
- for processrow in data:
-# getdata = local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0])
- #if processrow[0] in local_outputs['posts']:
-# if getdata.count() >0:
- # if len(result) > 0:
-# print (' Row ',processrow[0],' already in database')
-# d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
-# ,picsURL=processrow[3],picsLocalpath=processrow[4],\
-# source=processrow[5],date=processrow[6],address=processrow[7],\
-# dictPostComplete=processrow[8])
-# d2_dict = {'name':processrow[0] ,'comment':processrow[1],'rating':processrow[2]\
-# ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
-# 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
-# 'dictPostComplete':str(processrow[8])}
-# if env.forcegoogleupdate:
-# print (' Row ',processrow[0],' updated in database due to forcegoogleupdate')
-# local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0]).\
-# update\
-# (d2_dict)
-# local_outputs['postssession'].commit()
-# elif processrow[0] is not None:
-# # Create a Python dictionary object with all the column values
-# # d_row = {'name':processrow.name ,'comment':processrow.comment,'rating':processrow.rating,
-# # 'picsURL':processrow.picsURL,'pics_local_path':processrow.picsLocalpath, 'source':
-# # processrow.source,'date':processrow.date,'address':processrow.address,'dict_post_complete'
-# # :processrow.dictPostComplete}
-# d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
-# ,picsURL=str(processrow[3]),picsLocalpath=str(processrow[4]),\
-# source=processrow[5],date=processrow[6],address=processrow[7],\
-# dictPostComplete=str(processrow[8]))
-# print (' Row ',processrow[0],' added to Database')
-# # Append the above Python dictionary object as a row to the existing pandas DataFrame
-# # Using the DataFrame.append() function
- try:
- getdata2 = local_outputs['postssession'].query(Posts).filter(Posts.name ==\
- processrow[0])
- if getdata2.count() >0:
- print (' Row ',processrow[0],' already in Database')
- if env.forcegoogleupdate:
- print (' Row ',processrow[0],' updated in database due to forcegoogleupdate')
- d2_dict = {'name':processrow[0] ,'comment':processrow[1],'rating':\
- processrow[2]\
- ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
- 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
- 'dictPostComplete':str(processrow[8])}
- local_outputs['postssession'].query(Posts).filter(Posts.name == \
- processrow[0]).update(d2_dict)
- local_outputs['postssession'].commit()
- else:
- # d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
- # ,picsURL=processrow[3],picsLocalpath=processrow[4],\
- # source=processrow[5],date=processrow[6],address=processrow[7],\
- # dictPostComplete=processrow[8])
- d2_row = {'name':processrow[0] ,'comment':processrow[1],'rating':\
- processrow[2]\
- ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
- 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
- 'dictPostComplete':str(processrow[8])}
- local_outputs['postssession'].add(d2_row)
- local_outputs['postssession'].commit()
- print (' Row ',processrow[0],' added to Database')
- except AttributeError as error:
- print(' Not able to write to post data table: ' , type(error))
- local_outputs['postssession'].rollback()
- raise
- processrow = []
- df.to_excel(env.xls)
- return data
-
-##################################################################################################
-
-def database_update_row(review_name, column_name, column_value, update_style, local_outputs):
- """
- Updates a row in the database based on the specified review name, column name, value,
- and update style.
-
- Args:
- review_name (str): The name of the review to update.
- column_name (str): The name of the column to update.
- column_value: The value to update the column with.
- update_style (str): The style of update to perform.
- local_outputs: Local output information.
-
- Returns:
- bool: True if the row was successfully updated, False otherwise.
- """
-
- try:
- if update_style == "forceall" and column_value is not False:
- local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).update\
- ({column_name : column_value})
- print (' Force Updated ',column_name, ' to: ',column_value)
- elif update_style == "onlyempty" and column_value is not False:
- postval = local_outputs['postssession'].query(Posts).filter(Posts.name == review_name,\
- getattr(Posts,column_name).is_not(null())).all()
- if len(postval) == 0 :
- local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).\
- update({column_name : column_value})
- print (' Updated blank ',postval ,' on value',column_name, ' to: ',\
- column_value)
- elif update_style == "toggletrue":
- postval = local_outputs['postssession'].query(Posts).filter(Posts.name == review_name\
- ,getattr(Posts,column_name).is_not(1)).all()
- local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).update\
- ({column_name : "1"})
- print (' Updated ',column_name, ' on value: ',postval[0].column_value, ' to: ',\
- column_value)
- except AttributeError as error:
- print(" Not able to write to post data table to update ",review_name," ",column_name,"\
- to: ",column_value , type(error), error)
- local_outputs['postssession'].rollback()
- raise
-# else:
- local_outputs['postssession'].commit()
- #time.sleep(env.facebooksleep)
- return True
-
-##################################################################################################
-
-def check_wordpress_media(filename, headers):
- """
- Checks if a media file exists in the WordPress media folder.
-
- Args:
- filename (str): The name of the media file to check.
- headers: Additional headers for the request.
-
- Returns:
- tuple: A tuple containing the ID and link of the media file if found, otherwise
- (False, False).
- """
-
- file_name_minus_extension = filename
- response = requests.get(env.wpAPI + "/media?search="+file_name_minus_extension,\
- headers=headers,timeout=env.request_timeout)
- try:
- if result := response.json():
- file_id = int(result[0]['id'])
- link = result[0]['guid']['rendered']
- return file_id, link
- else:
- return False,False
- except AttributeError:
- print(' No existing media with same name in Wordpress media folder: '+filename)
- return (False, False)
-
-##################################################################################################
-
-def check_is_port_open(host):
- """
- Checks if a port on a host is open.
-
- Args:
- host (str): The host to check for an open port.
- port (int): The port number to check.
-
- Returns:
- bool: True if the port is open, False otherwise.
- """
-
- try:
- is_web_up = urllib3.request("GET", host, timeout=env.request_timeout)
- if is_web_up.status == 200:
- return True
- except AttributeError as error:
- print ('Could not open port to website: ', host, type(error))
- return False
-
-##################################################################################################
-
-def get_wordpress_post_id_and_link(postname, headers2):
- """
- Retrieves the ID and link of a WordPress post based on the post name.
-
- Args:
- postname (str): The name of the WordPress post to retrieve.
- headers2: Additional headers for the request.
-
- Returns:
- tuple: A tuple containing the ID and link of the WordPress post.
- """
-
- response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,timeout=\
- env.request_timeout)
- result = response.json()
- if len(result) > 0:
- return int(result[0]['id']), result[0]['link']
- print(' No existing post with same name: ' + postname)
- return False, False
-
-##################################################################################################
-
-def check_wordpress_post(postname, postdate, headers2,local_outputs):
- """
- Checks if a WordPress post with the given name and date exists.
-
- Args:
- postname (str): The name of the WordPress post to check.
- postdate: The date of the WordPress post to check.
- headers2: Additional headers for the request.
-
- Returns:
- tuple: A tuple containing the ID and link of the existing post if found,
- otherwise (False, False).
- """
-
- try:
- response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,\
- timeout=env.request_timeout)
- result = response.json()
- except AttributeError as error:
- print ('Could not query for post on wordpress: ', postname,postdate, type(error))
- return False, False
- # try:
- # newdate,newdate2,visitdate = get_wordpress_post_date_string(result[0]['date'],\
- # result[0]['date'])
- # newdate3,newdate4,visitdate2 = get_wordpress_post_date_string(postdate,str(datetime.now()))
- # if visitdate and visitdate2:
- # print ('Post exists, checking visit date')
- # except KeyError as error:
- # print (' Post exists but does not have post date in visitdate field:',error)
- if len(result) > 0:
- d1list = result[0]['date'].split("-")
- d2list = postdate.split("-")
- if d1list[0] == d2list[0] and d1list[1] == d2list[1]:
- return int(result[0]['id']), result[0]['link']
- else:
- print(' -No existing post with same name: ' + postname)
- return False, False
-
-##################################################################################################
-def check_wordpress_post2(postname, postdate, post_id, headers2,local_outputs):
- """
- Checks if a WordPress post with the given name and date exists.
-
- Args:
- postname (str): The name of the WordPress post to check.
- postdate: The date of the WordPress post to check.
- headers2: Additional headers for the request.
-
- Returns:
- tuple: A tuple containing the ID and link of the existing post if found,
- otherwise (False, False).
- """
-
- try:
- response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,\
- timeout=env.request_timeout)
- result = response.json()
- except AttributeError as error:
- print ('Could not query for post on wordpress: ', postname,postdate, type(error))
- return False, False
- # try:
- # newdate,newdate2,visitdate = get_wordpress_post_date_string(result[0]['date'],
- # result[0]['date'])
- # newdate3,newdate4,visitdate2 = get_wordpress_post_date_string(postdate,str(datetime.now()))
- # if visitdate and visitdate2:
- # print ('Post exists, checking visit date')
- # except KeyError as error:
- # print (' Post exists but does not have post date in visitdate field:',error)
- if len(result) > 0:
- d1list = result[0]['date'].split("-")
- d2list = postdate.split("-")
- if d1list[0] == d2list[0] and d1list[1] == d2list[1]:
- return int(result[0]['id']), result[0]['link']
- print(' -No existing post with same name: ' + postname)
- return False, False
-
-##################################################################################################
-
-# Function to get the featured photo ID of a WordPress post
-def get_wordpress_featured_photo_id(post_id):
- """ Get photoid from featured photo
-
- Args:
- post_id (_type_): _description_
-
- Returns:
- _type_: _description_
- """
- # Make a GET request to the WordPress REST API to retrieve media details
- response = requests.get(f"{env.wpAPOurl}/{post_id}",timeout=env.request_timeout)
- # Check if the request was successful
- if response.status_code == 200:
- # Parse the JSON response
- media_items = response.json()
-
- # Loop through the media items associated with the post
- # for item in media_items:
- # # Check if the media item is the featured image
- # if item.get('post', None) == int(post_id):
- # # Return the ID of the featured image
- return media_items['featured_media']
- # If the request failed or the featured image was not found, return None
- return None
-# # Example usage
-# featured_photo_id = get_featured_photo_id(POST_ID)
-# print(f"The featured photo ID for post {POST_ID} is: {featured_photo_id}")
-
-##################################################################################################
-
-def post_to_x2(title, content, headers,date, rating, address, picslist,local_outputs):
- """
- Post to x2.
-
- This function posts content to a social media platform using the provided data.
-
- Args:
- title (str): The title of the post.
- content (str): The content of the post.
- date (str): The date of the post.
- rating (int): The rating of the post.
- address (str): The address associated with the post.
- picslist (list): A list of pictures for the post.
- instasession: The Instagram session for posting.
-
- Returns:
- str: The media ID of the posted content.
- """
- pics = ((picslist[1:-1]).replace("'","")).split(",")
- # Replace the following strings with your own keys and secrets
- CONSUMER_KEY = env.x_consumer_key
- CONSUMER_SECRET = env.x_consumer_secret
- ACCESS_TOKEN = env.x_access_token
- ACCESS_TOKEN_SECRET = env.x_access_token_secret
- # Authenticate to Twitter
- auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
- auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
- # Create an API object to use the Twitter API
- #api = tweepy.API(auth)
- img_list = pics
- imgs_vid = []
- imgs_pic = []
- client_v1 = get_twitter_conn_v1(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
- client_v2 = get_twitter_conn_v2(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
- for img in img_list:
- if 'montage.mp4' in img:
- imgs_vid.append(img.strip())
- else:
- imgs_pic.append(img.strip())
- if imgs_vid:
- try:
- video_path = imgs_vid[0]
- # Message to post along with the video
- attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
- .all()
- business_url = attrib_list[0].businessurl
- wpurl = attrib_list[0].wpurl
- if wpurl: # Don't post of website URL does not exist yet
- if business_url: #Sometimes Business URL does not exist, so account for it
- status_message=str(title)+': My Review - '+wpurl+'\n Business website: '+\
- business_url + '\n'
- else:
- status_message = str(title) + ': My Review - '+ wpurl + '\n'
- status_message2 = status_message +' '+str(get_hastags(address, title, 'short'))\
- +' '
- status_message_short = status_message2[:279]
- # Upload video
- media = client_v1.media_upload(filename=video_path)
- # Post tweet with video
- # tweetlat = (local_outputs['postssession'].query(Posts).filter(Posts.name == \
- # title).all())[0].latitude
- # tweetlong = (local_outputs['postssession'].query(Posts).filter(Posts.name == \
- # title).all())[0].longitude
- if media.processing_info['state'] != 'failed':
- client_v2.create_tweet(text=status_message_short,media_ids=[media.media_id])
-# client_v2.create_tweet(text=status_message_short, lat=tweetlat , \
-# long=tweetlong ,media_ids=[media.media_id])
- else:
- print ('Problem uploading video to twitter: ',media.processing_info['error'])
- return False
- else:
- print (' Skipping xtwitter post because wordpress URL is missing')
- except AttributeError as error:
- print("AttributeError An error occurred:",error) # An error occurred:
- else:
- print (' xtwitter: No video available, skipping twitter post for : ',title)
- return False
- time.sleep(env.facebooksleep)
- return True
-
-##################################################################################################
-
-def post_to_threads(title, content,headers, date, rating, address, picslist, local_outputs):
- img_list = ((picslist[1:-1]).replace("'","")).split(",")
- attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
- business_url = attrib_list[0].businessurl
- wpurl = attrib_list[0].wpurl
- auth_token = env.threads_access_token
- group_id = env.threads_page_id
- imgs_id = []
- imgs_vid = []
- imgs_pic = []
- if wpurl and (attrib_list[0].picsLocalpath != '[]'):
- if business_url:
- status_message = (
- f'{str(title)}: My Review - {wpurl} \n Business website: {business_url}'\
- + ' \n\n') + content
- else:
- status_message = f'{str(title)}: My Review - ' + wpurl + ' \n\n' + content
- for img in img_list:
- if 'montage.mp4' in img:
- imgs_vid.append(img.strip())
- else:
- imgs_pic.append(img.strip())
- if imgs_vid:
- try:
- post_id = post_threads_video(group_id, imgs_vid,auth_token,title, status_message,
- date, rating, address)
- imgs_id.append(post_id['id'])
- except AttributeError as error:
- print(" An error occurred:",error)
- return False
- time.sleep(env.facebooksleep)
- print(' threads response: ',post_id)
- else:
- print (' threads: Wordpress URL or no pictures so skipping threads posting')
- return True
-
-##################################################################################################
-
-def post_facebook3(title, content,headers, date, rating, address, picslist, local_outputs):
- """
- Post to Facebook3.
-
- This function posts content to Facebook using the provided data.
-
- Args:
- title (str): The title of the post.
- content (str): The content of the post.
- date (str): The date of the post.
- rating (int): The rating of the post.
- address (str): The address associated with the post.
- picslist (list): A list of pictures for the post.
- instasession: The Instagram session for posting.
-
- Returns:
- bool: Indicates if the post was successfully made.
- """
- pics = ((picslist[1:-1]).replace("'","")).split(",")
- group_id = env.facebookpageID
- auth_token = env.facebookpass
- imgs_id = []
- imgs_vid = []
- imgs_pic = []
- img_list = pics
- attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
- business_url = attrib_list[0].businessurl
- wpurl = attrib_list[0].wpurl
- if wpurl and (attrib_list[0].picsLocalpath != '[]'):
- if business_url:
- status_message = (
- f'{str(title)}: My Review - {wpurl} \n Business website: {business_url}'\
- + ' \n\n') + content
- else:
- status_message = f'{str(title)}: My Review - ' + wpurl + ' \n\n' + content
- for img in img_list:
- if 'montage.mp4' in img:
- imgs_vid.append(img.strip())
- else:
- imgs_pic.append(img.strip())
- if imgs_vid:
- try:
- post_id = post_facebook_video(group_id, imgs_vid,auth_token,title, status_message,
- date, rating, address)
- imgs_id.append(post_id['id'])
- except AttributeError as error:
- print(" An error occurred:",error)
- return False
- time.sleep(env.facebooksleep)
- print(' Facebook response: ',post_id)
- else:
- print (' facebook: Wordpress URL or no pictures so skipping Facebook posting')
- return True
-
-##################################################################################################
-
-def post_to_threads2(title, content, headers, date, rating, address, picslist, local_outputs):
- """
- Posts content to threads if picslist is not empty and contains 'montage.mp4'.
-
- Args:
- title (str): The title of the post.
- content (str): The content of the post.
- headers: Headers information.
- date: Date information.
- rating: Rating information.
- address: Address information.
- picslist: List of pictures.
- local_outputs: Local output information.
-
- Returns:
- bool: True if the post was successfully uploaded to Instagram, False otherwise.
- """
- pics = ((picslist[1:-1]).replace("'","")).split(",")
- if pics != '[]' and "montage.mp4" in pics:
- outputmontage = ''
- addresshtml = re.sub(" ", ".",address)
- #content = content + get_hastags(address, title)
- pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
- #video, outputmontage = make_montage_video_from_google(pics)
- for loop in pics:
- if "montage.mp4" in loop:
- outputmontage = loop
- break
- if pathlib.Path.exists(outputmontage):
- try:
- data = title + "\n"+ address+"\nGoogle map to destination: " \
- r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n" \
- + content + "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title,'long')+ \
- "\n\nhttps://www.joeeatswhat.com "+"\n\n"
- local_outputs['instasession'].video_upload(outputmontage, data)
- except AttributeError as error:
- print(" An error occurred uploading video to Threads:", type(error).__name__)
- return False
- return True
- else:
- return False
-
-###################################################################################################
-
-# def tiktok_upload_video(session_id, file_path, title, tags, schedule_time=None):
-# url = 'https://www.tiktok.com/api/upload/video/'
-# headers = {
-# 'Cookie': f'sessionid={session_id}'
-# }
-# data = {
-# 'title': title,
-# 'tags': ','.join(tags),
-# 'schedule_time': schedule_time
-# }
-# files = {
-# 'video': open(file_path, 'rb')
-# }
-# response = requests.post(url, headers=headers, data=data, files=files)
-# return response.json()
-
-def post_to_tiktok(title, content, headers2, date, rating, address, picslist, local_outputs):
- """
- Posts content to TikTok with specified session ID, video file, title, hashtags, and optional
- scheduling.
-
- Args:
- title (str): The title of the video.
- content (str): The content of the video.
- headers: Headers information.
- date: Date information.
- rating: Rating information.
- address: Address information.
- picslist: List of pictures.
- local_outputs: Local output information.
-
- Returns:
- None
- """
- # Replace 'your_sessionid_cookie' with your actual TikTok sessionid cookie.
- #session_id = env.tiktok_client_secret
-
- # Replace 'path_to_video.mp4' with the path to your video file.
- #file_path = 'path_to_video.mp4'
-
- # Replace 'Your video title' with the title of your video.
- #title = 'Your video title'
-
- # Replace the following list with the hashtags you want to add to your post.
- tags = get_hastags(address, title,'long')
-
- # If you want to schedule your video, replace 'schedule_timestamp' with the Unix timestamp.
- # Leave it as None if you want to upload immediately.
- schedule_time = None # or Unix timestamp (e.g., 1672592400)
- pics = ((picslist[1:-1]).replace("'","").replace(" ","")).split(",")
- if any(element.endswith("montage.mp4") for element in pics):
- for pic in pics:
- if 'montage.mp4' in pic:
- file_path = pic
- else:
- return False
- #content = content + get_hastags(address, title)
- #pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
-# video, outputmontage = make_montage_video_from_google(pics)
- # try:
- # instasession.video_upload(outputmontage, data)
- # except AttributeError as error:
- # print(" An error occurred uploading video to Instagram:", type(error).__name__)
- # return False
- # return True
- # """
- # client_key string The unique identification key
- # provisioned to the partner.
- # client_secret string The unique identification secret provisioned
- # to the partner.
- # code string The authorization code from the web, iOS, Android or desktop
- # authorization callback. The value should be URL decoded.
- # grant_type string Its value should always be set as
- # authorization_code.
- # redirect_uri string Its value must be the same as the redirect_uri used
- # for requesting code.
- # curl --location --request POST 'https://open.tiktokapis.com/v2/oauth/token/' \
- # --header 'Content-Type: application/x-www-form-urlencoded' \
- # --header 'Cache-Control: no-cache' \
- # --data-urlencode 'client_key=CLIENT_KEY' \
- # --data-urlencode 'client_secret=CLIENT_SECRET' \
- # --data-urlencode 'code=CODE' \
- # --data-urlencode 'grant_type=authorization_code' \
- # --data-urlencode 'redirect_uri=REDIRECT_URI'
- # """
-
-# curl --location 'https://open.tiktokapis.com/v2/post/publish/inbox/video/init/' \
-# --header 'Authorization: Bearer act.example12345Example12345Example' \
-# --header 'Content-Type: application/json; charset=UTF-8'
-# --data '{
-# "source_info": {
-# "source": "FILE_UPLOAD",
-# "video_size": exampleVideoSize,
-# "chunk_size" : exampleChunkSize,
-# "total_chunk_count": exampleTotalChunkCount
-# }
-# }'
-
-
-# curl --location 'https://open.tiktokapis.com/v2/post/publish/video/init/' \
-# --header 'Authorization: Bearer act.example12345Example12345Example' \
-# --header 'Content-Type: application/json; charset=UTF-8' \
-# --data-raw '{
-# "post_info": {
-# "title": "this will be a funny #cat video on your @tiktok #fyp",
-# "privacy_level": "MUTUAL_FOLLOW_FRIENDS",
-# "disable_duet": false,
-# "disable_comment": true,
-# "disable_stitch": false,
-# "video_cover_timestamp_ms": 1000
-# },
-# "source_info": {
-# "source": "FILE_UPLOAD",
-# "video_size": 50000123,
-# "chunk_size": 10000000,
-# "total_chunk_count": 5
-# }
-# }'
-
-
-
-
-# https://api.tiktok.com/open-api/v2/aweme/post/?aweme-type=video
-# You will need to include the following headers:
-
-# Content-Type: application/json
-# X-SS-TOKEN: [Your App ID]
-# X-TikTok-Signature: [Your App Secret]
-# And the following JSON body:
-
-# {
-# "device_platform": "android",
-# "device_version": "11",
-# "app_name": "musical.ly",
-# "app_version": "7.0.3",
-# "resolution": "1080*1920",
-# "os_version": "11",
-# "model": "vivo 1906",
-# "manufacturer": "vivo",
-# "language": "en",
-# "country": "US"
-# }
-
- connect_json_body = {
- "device_platform": "android",
- "device_version": "11",
- "app_name": "musical.ly",
- "app_version": "7.0.3",
- "resolution": "1080*1920",
- "os_version": "11",
- "model": "vivo 1906",
- "manufacturer": "vivo",
- "language": "en",
- "country": "US"
- }
- connect_json_header = {
- 'Content-Type': 'application/json',
- 'X-SS-TOKEN': env.tiktok_app_id, #[Your App ID],
- 'X-TikTok-Signature': env.tiktok_client_secret, #[Your App Secret]
- }
- connect_response = requests.post('https://open.tiktokapis.com/v2/post/publish/video/init/',headers=connect_json_header,\
- data=connect_json_body,timeout=env.request_timeout)
-
-#request https://api.tiktok.com/open-api/v2/aweme/post/?aweme-type=video
-# https://api.tiktok.com/open-api/v2/aweme/post/
-# You will need to include the following headers:
-
-# Content-Type: multipart/form-data
-# X-SS-TOKEN: [Your App ID]
-# X-TikTok-Signature: [Your App Secret]
-# Authorization: Bearer [Your Access Token]
-# And the following form data:
-
-# video: [Your Video File]
-# desc: [Your Video Description]
-# Once you have made this request, your video will be uploaded to TikTok.
- post_json_header = {
- 'X-SS-TOKEN': env.tiktok_app_id,#[Your App ID],
- 'X-TikTok-Signature': env.tiktok_client_secret,#[Your App Secret]
- 'Authorization': 'ww'#Bearer [Your Access Token]
- }
- post_json_body = {
- 'video': file_path,
- 'desc': content+tags
- }
-
- post_response = requests.post('https://api.tiktok.com/open-api/v2/aweme/post/',headers=post_json_header,\
- data=post_json_body,timeout=env.request_timeout)
-
-
-
- # headers = ['Content-Type: application/x-www-form-urlencoded','Cache-Control: no-cache']
- # data = ['client_key='+env.tiktok_client_key,'client_secret='+env.tiktok_client_secret,\
- # 'code='+env.tiktok_app_id,'grant_type=authorization_code','redirect_uri=http://www.joeeatswhat.com']
- # allheaders = headers + data
-
- # try:
- # data2 = {'source_info':{'source':"FILE_UPLOAD",file_path}}
- # response = requests.post('https://open.tiktokapis.com/v2/oauth/token/,headers:',allheaders,\
- # 'data:',data2,'timeout:',env.request_timeout)
- # except BaseException as error:
- # print(" An error occurred uploading video to TikTok:", type(error).__name__)
- # return False
- # Call the function to upload the video
- # response = tiktok_upload_video(session_id, file_path, title, tags, schedule_time)
- print(' tikTok response: ',post_response)
- return True
-###################################################################################################
-
-def post_to_instagram2(title, content, headers, date, rating, address, picslist, local_outputs):
- """
- Posts content to Instagram with relevant information and media.
-
- Args:
- title (str): The title of the post.
- content (str): The content of the post.
- headers: Headers for the post.
- date: Date of the post.
- rating: Rating of the post.
- address: Address related to the post.
- picslist: List of pictures for the post.
- local_outputs: Local outputs for the post.
-
- Returns:
- bool: True if the post was successfully uploaded, False otherwise.
- """
-
- outputmontage = ''
- addresshtml = re.sub(" ", ".",address)
- attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
- if wpurl := attrib_list[0].wpurl:
- if business_url := attrib_list[0].businessurl:
- data = title + "\n"+ address+"\n"+business_url+"\n"+"Review: "+wpurl+\
- "\nGoogle map to destination: " \
- r"https://www.google.com/maps/dir/?api=1&destination="\
- +addresshtml +"\n"+"Review: "+wpurl+"\n\n"+ content + "\n"+rating+"\n"+date+\
- "\n\n"+get_hastags(address, title,'long')+"\n\nhttps://www.joeeatswhat.com"+"\n\n"
- else:
- print (" Missing business url for : "+title+" not using it in intagram post")
- data = title + "\n"+ address+"\n"+"Review: "+wpurl+"\nGoogle map to destination: " \
- r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\nReview: "\
- +wpurl+"\n\n"+ content + "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title\
- ,'long')+"\n\nhttps://www.joeeatswhat.com"+"\n\n"
- instasession = local_outputs['instagram']
- if picslist != '[]' and "montage.mp4" in picslist:
- #content = content + get_hastags(address, title)
- pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
- #video, outputmontage = make_montage_video_from_google(pics)
- for loop in pics:
- if "montage.mp4" in loop:
- outputmontage = loop
- break
- pathoutputmontage = outputmontage[1:-1]
- if pathlib.Path.exists(pathoutputmontage):
- try:
- duration, fps, (width, height)=with_moviepy(outputmontage)
- if duration < 60:
- instasession.video_upload(outputmontage, data)
- else:
- if not os.path.isfile(outputmontage+".trim.mp4"):
- video = VideoFileClip(outputmontage)
- video = video.subclip(0, 60)
- print (' IG video duration too long 60 : ',duration, fps, (width,height))
- video.write_videofile(outputmontage+".trim.mp4")
- instasession.video_upload(outputmontage+".trim.mp4", data)
- except BaseException as error:
- print(" An error occurred uploading video to Instagram:", type(error).__name__)
- return False
- return True
- else:
- print (' Missing wordpress post for instagram : ',title)
- return False
-
-##################################################################################################
-
-def with_moviepy(filename):
- from moviepy.editor import VideoFileClip
- clip = VideoFileClip(filename)
- duration = clip.duration
- fps = clip.fps
- width, height = clip.size
- return duration, fps, (width, height)
-
-##################################################################################################
-
-def post_to_wordpress(title,content,headers,date,rating,address,picslist,local_outputs):
- """
- Post to WordPress.
-
- This function posts content to a WordPress site using the provided data.
-
- Args:
- title (str): The title of the post.
- content (str): The content of the post.
- headers: Headers for the request.
- date (str): The date of the post.
- rating (str): The rating of the post.
- address (str): The address associated with the post.
- picslist (list): A list of pictures for the post.
- local_outputs: Outputs for the post.
-
- Returns:
- None
-"""
- # post
- #new_post = False
- #countreview = False
- addresshtml = re.sub(" ", ".",address)
- googleadress = r""+str(address)+r""
- contentpics = ''
- picchop = ''
- linkslist=[]
- # picl = picslist[1:-1]
- # pic2 = picl.replace(",","")
- # # #re.sub(r',','',picl) #re.sub( r'[^a-zA-Z0-9]','',tempdate[1])
- # pic3= pic2.replace("'","")
- # picchop = pic3.split(" ")
- # line = re.sub('[!@#$]', '', line)
- #picchop = re.sub(',\'','',picslist[1:-1])
- picchop = picslist[1:-1].replace(",","").replace("'","").split(" ")
- print (' Figuring out date of Post : ',title)
- #specifify the formatting of the date_string.
- # formatting = '%b/%Y/%d'
- date_string = date
- if "a day" in date_string:
- date = dt.timedelta(days=-1)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() - date
- visitdate = newdate.strftime("%b%Y")
- else:
- if "day" in date:
- tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
- print ('Stuff - > ',tempdate)
-# date = dt.timedelta(days=tempdate)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() + relativedelta(days=tempdate)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "a week" in date:
-# date = dt.timedelta(weeks= -1)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() - relativedelta(weeks= 1)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "week" in date:
- tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
- print ('Stuff - > ',tempdate)
-# date = dt.timedelta(weeks= tempdate)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() + relativedelta(weeks= tempdate)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "a month" in date:
-# date = dt.timedelta(months= -1)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() - relativedelta(months = 1)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "month" in date:
- tempdate = -int(re.sub( r'[^0-9]','',date_string))
- print ('Stuff - > ',tempdate)
-# date = dt.timedelta(months= tempdate)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() + relativedelta(months = tempdate)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "a year" in date:
-# date = dt.timedelta(years= -1)
-# newdate = dt.datetime.strptime(date_string, formatting).date()
- newdate = datetime.today() - relativedelta(years= 1)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "year" in date:
- try:
- tempdate = -int(re.sub( r'[^0-9]','',date_string))
- print ('Stuff - > ',tempdate)
-# date = dt.timedelta( years= tempdate)
-# newdate = dt.datetime.strptime(date_string).date()
- newdate = datetime.today() + relativedelta(years= tempdate)
- visitdate = newdate.strftime("%b%Y")
- except AttributeError as error:
- print(" An error getting date occurred:",error)
- else:
- #specifify the formatting of the date_string.
- formatting = '%Y-%b-%d'
- month = date[:3]
- year = date[3:]
- day = '01'
- date_string = year+'-'+ month+'-'+day
- try:
- newdate = dt.datetime.strptime(date_string, formatting)\
- .date()
- except AttributeError as error:
- print(" An error getting date occurred:",error)
-# try:
-# newdate = dt.datetime.strptime(date_string, formatting)\
-# .date()
-# except AttributeError as error:
-# print(" An error getting date occurred:", error)
- visitdate = newdate.strftime("%b%Y")
- newdate = str(newdate)
- #formatting = '%b/%Y/%d' #specifify the formatting of the date_string.
- #newdate2 = dt.datetime.strptime(str(newdate), formatting).date()
- dateparts = (str(newdate)).split("-")
- dateparts2 = dateparts[2].split(" ")
- visitdate2 = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
- .all()[0].visitdate
- if visitdate != visitdate2:
- database_update_row(title,"visitdate",visitdate,"forceall",local_outputs)
- print (f'UPDATED: {visitdate2} to {visitdate} for {title}')
- #dateparts = dateparts2[0]
-# print ('dateparts',dateparts)
- newdate2 = dateparts[0]+'-'+dateparts[1]+'-'+dateparts2[0]+'T22:00:00'
- #newdate2 = str(re.sub(r'-','/',str(newdate.date())))+'T22:00:00'
- print (' Got Date: ', newdate2, newdate)
- post_id, post_link = check_wordpress_post(title,newdate2,headers,local_outputs)
- featured_photo_id = get_wordpress_featured_photo_id(post_id)
- print(f" Featured photo ID: for {title} post {post_id} is: {featured_photo_id}")
- if env.block_google_maps is not True:
- try:
- database_update_row(title,"wpurl",post_link,"forceall",local_outputs)
- except AttributeError as error :
- print ('Could not check to see post already exists',error)
- if not post_id:
- googleadress = r""+address+r""
- post_data = {
- "title": title,
- # "content": address+'\n\n'+content+'\n'+rating+'\n\n' ,
- "content": googleadress+'\n\n'+content+'\n'+rating ,
- "status": "publish", # Set to 'draft' if you want to save as a draft
- "date": newdate2,
- "meta": {'visitdate':visitdate}
- # "date": str(newdate)+'T22:00:00',
- # "author":"joesteele"
- }
- try:
- headers2 = headers
- response = requests.post(env.wpAPOurl, json = post_data, headers=headers2,timeout=\
- env.request_timeout)
- if response.status_code != 201:
- print ('Error: ',response, response.text)
- else:
- #new_post = True
- post_id_json = response.json()
- post_id = post_id_json.get('id')
- print (' New post is has post_id = ',post_id)
- except AttributeError as error:
- print("An error occurred:", type(error).__name__) # An error occurred:
- #postneedsupdate = True
- else:
- print (' Post already existed: Post ID : ',post_id)
- if not env.force_web_create:
- return True
- for pic in picchop:
- if pic != '':
- picslice2 = pic.split("/")[-1]
- picslice = picslice2.split(".")
- picname = picslice[0]
- caption =title
- description = title+"\n"+address
- print (' Found Picture: ',picname)
- file_id, link = check_wordpress_media(picname, headers)
- # link = linknew['rendered']
- if file_id is False:
- print (' '+str(picname)+' was not already found in library, adding it')
- # countreview = True
- image = {
- "file": open(pic, "rb"),
- "post": post_id,
- "caption": caption,
- "description": description
- }
- try:
- image_response = requests.post(env.wpAPI + "/media", headers=headers, \
- files=image,timeout=env.request_timeout)
- except AttributeError as error:
- print(" An error uploading picture ' + picname+ ' occurred:", \
- type(error).__name__)
- if image_response.status_code != 201 :
- print (' Error:Image ',picname,' wasnot successfully uploaded.response:'\
- ,image_response)
- else:
- pic_dic=image_response.json()
- file_id= pic_dic.get('id')
- link = pic_dic.get('guid').get("rendered")
- print (' ',picname,' was successfully uploaded to website with ID: ',\
- file_id, link)
- try:
- links_dict = {'file_id' : file_id , 'link' : link}
- linkslist.append(links_dict)
- except AttributeError as error:
- print(" An error adding to dictionary " , file_id , link , " occurred:",\
- type(error).__name__) # An error occurred:
- else:
- print (' Photo ',picname,' was already in library and added to post with ID:',\
- file_id,' : ',link)
- try:
- image_response = requests.post(env.wpAPI + "/media/" + str(file_id),\
- headers=headers, data={"post" : post_id},timeout=env.request_timeout)
- except AttributeError as error:
- print (' Error- Image ',picname,' was not attached to post. response: ',\
- image_response+' '+type(error).__name__)
- try:
- post_response = requests.post(env.wpAPI + "/posts/" + str(post_id),\
- headers=headers,timeout=env.request_timeout)
- if link in post_response.text:
- print (' Image link for ', picname, 'already in content of post: '\
- ,post_id, post_response.text, link)
- else:
- linkslist.append({'file_id' : file_id , 'link' : link})
- # countreview = True
- except AttributeError as error:
- print(" An error loading the metadata from the post "+post_response.title+\
- ' occurred: '+type(error).__name__)
- #ratinghtml = post_response.text
- first_mp4 = True
- first_pic = True
- fmedia = {}
- contentpics = ""
- for piclink in linkslist:
- if piclink != '':
- #for loop in linkslist:
- print (' Adding ', piclink['link'], ' to posting')
- try:
- ext = piclink['link'].split( '.')[-1]
- if ext == 'mp4':
- if first_mp4:
- contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
- r'" autoplay="true"]'
- first_mp4 = False
- else:
- contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
- #[evp_embed_video url="http://example.com/wp-content/uploads/videos/vid1.mp4" autoplay="true"]
- else:
- contentpics+='\n '+r'
![]()
'
- if first_pic:
- fmedia = piclink['file_id']
- first_pic = False
- # fmedia.append = piclink{'file_id' }
- # contentpics += '\n '+r'
' +'\n\n'
- except AttributeError as error:
- print("An error occurred:", type(error).__name__) # An error occurred:
- return False
- try:
-# print ('featured_media = ',linkslist[0]['file_id'])
- # if linkslist[0]['file_id']:
- # print ('featuredmedia2 = ',linkslist[0]['file_id'])
- if fmedia:
- print ('Featured Media: ',fmedia)
- else:
- if linkslist:
- fmedia = linkslist[0]['file_id']
-# print ('featured_media2 = ',file_id)
- business_url_list = local_outputs['postssession'].query(Posts).filter(Posts.name == \
- title).all()
- business_url = ""+\
- title+""
- # wpurllist = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
- # wpurl = wpurllist[0].wpurl
-# if business_url or business_url is False:
- status_message = str(title) + ':\nBusiness website: '+ business_url
- response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
- data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+'\n'+\
- rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":title},\
- headers=headers,timeout=env.request_timeout)
- print (' response_piclinks: ',response_piclinks)
- if fmedia and fmedia != 0 and featured_photo_id and featured_photo_id !=0:
- print (" Featured Media: "+str(featured_photo_id)+" "+str(fmedia)+" looks OK")
- else:
- print (" fmedia is still empty and need to populate")
- if fmedia:
- response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
- data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+
- '\n'+rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":\
- title},headers=headers,timeout=env.request_timeout)
- print (' Results of new results ID value : '+str(\
- get_wordpress_featured_photo_id(post_id)))
- else:
- response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
- data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress\
- +'\n'+rating+contentpics,"rank_math_focus_keyword":title},\
- headers=headers,timeout=env.request_timeout)
- print ('Results of new results ID with no picture value : '+str\
- (get_wordpress_featured_photo_id(post_id)))
- except AttributeError as error:
- print(" An error writing images to the post " + post_response.title + ' occurred:',\
- type(error).__name__) # An error occurred')
- return False
- return True
-
-##################################################################################################
-
-def build_picslist(picchop, piclink, file_id):
- """
- Builds a list of pictures for posting based on the provided picture links.
-
- Args:
- picchop (list): List of picture links to process.
- piclink (str): The picture link to be added to the list.
-
- Returns:
- str: A string containing the formatted list of pictures for posting.
- Raises:
- AttributeError: If an error occurs during picture processing.
- """
-
- for piclink in picchop:
- if piclink != '':
- print (' Adding ', piclink['link'], ' to posting')
- try:
- ext = piclink['link'].split( '.')[-1]
- if ext == 'mp4':
- if first_mp4:
- contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
- r'" autoplay="true"]'
- first_mp4 = False
- else:
- contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
- else:
- contentpics+='\n '+r''
- if first_pic:
- fmedia = piclink['file_id']
- first_pic = False
- except AttributeError as error:
- print("An error occurred:", type(error).__name__) # An error occurred:
- return False
- return contentpics
-
-##################################################################################################
-
-def get_wordpress_post_date_string(date_string, date):
- """
- Parses a date string and returns two formatted date strings.
-
- Args:
- date_string (str): The input date string to be parsed.
- date (str): The keyword indicating the date offset.
-
- Returns:
- tuple: A tuple containing two formatted date strings.
- Raises:
- AttributeError: If an error occurs during date parsing.
- """
-
-
- if "a day" in date_string:
- date = dt.timedelta(days=-1)
- newdate = datetime.today() - date
- visitdate = newdate.strftime("%b%Y")
- else:
- if "day" in date_string:
- tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
- print ('Stuff - > ',tempdate)
- newdate = datetime.today() + relativedelta(days=tempdate)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "a week" in date_string:
- newdate = datetime.today() - relativedelta(weeks= 1)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "week" in date_string:
- tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
- print ('Stuff - > ',tempdate)
- newdate = datetime.today() + relativedelta(weeks= tempdate)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "a month" in date_string:
- newdate = datetime.today() - relativedelta(months = 1)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "month" in date_string:
- tempdate = -int(re.sub( r'[^0-9]','',date_string))
- print ('Stuff - > ',tempdate)
- newdate = datetime.today() + relativedelta(months = tempdate)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "a year" in date_string:
- newdate = datetime.today() - relativedelta(years= 1)
- visitdate = newdate.strftime("%b%Y")
- else:
- if "year" in date_string:
- try:
- tempdate = -int(re.sub( r'[^0-9]','',date_string))
- print ('Stuff - > ',tempdate)
- newdate = datetime.today() + relativedelta(years= tempdate)
- visitdate = newdate.strftime("%b%Y")
- except AttributeError as error:
- print(" An error getting date occurred:",error)
- else:
- #specifify the formatting of the date_string.
- formatting = '%Y-%b-%d'
- month = date[:3]
- year = date[3:]
- day = '01'
- date_string = year+'-'+ month+'-'+day
- try:
- newdate = dt.datetime.strptime(date_string, formatting)\
- .date()
- except AttributeError as error:
- print(" An error getting date occurred:",error)
- newdate = str(newdate)
- #formatting = '%b/%Y/%d' #specifify the formatting of the date_string.
- #newdate2 = dt.datetime.strptime(str(newdate), formatting).date()
- dateparts = (str(newdate)).split("-")
- dateparts2 = dateparts[2].split(" ")
- newdate2 = dateparts[0]+'-'+dateparts[1]+'-'+dateparts2[0]+'T22:00:00'
- print (' Got Date: ', newdate2, newdate)
- return (newdate,newdate2,visitdate)
-
-##################################################################################################
-
-def create_wordpress_post(newdate2, picchop, title, address, headers, post_id, linkslist,\
- local_outputs, content, googleadress, rating, featured_photo_id):
- """
- Creates a WordPress post with pictures and content.
-
- Args:
- newdate2: The date of the post.
- picchop (list): List of picture links to process.
- title: The title of the post.
- address: The address associated with the post.
- headers: The headers for the HTTP request.
- post_id: The ID of the post.
- linkslist: List of links to pictures.
- local_outputs: Local outputs for the post.
- content: The content of the post.
- googleadress: The Google address for the post.
- rating: The rating of the post.
- featured_photo_id: The ID of the featured photo.
-
- Returns:
- bool: True if the post creation is successful, False otherwise.
- Raises:
- AttributeError: If an error occurs during post creation or processing.
- """
-
- if not post_id:
- addresshtml = re.sub(" ", ".",address)
- googleadress = r""+address+r""
- post_data = {
- "title": title,
- "content": googleadress+'\n\n'+content+'\n'+rating ,
- "status": "publish", # Set to 'draft' if you want to save as a draft
- "date": newdate2
- }
- try:
- headers2 = headers
- response = requests.post(env.wpAPOurl, json = post_data, headers=headers2,timeout=\
- env.request_timeout)
- if response.status_code != 201:
- print ('Error: ',response, response.text)
- else:
- post_id_json = response.json()
- post_id = post_id_json.get('id')
- print (' New post has post_id = ',post_id)
- except AttributeError as error:
- print("An error occurred:", type(error).__name__) # An error occurred:
- else:
- print (' Post already existed: Post ID : ',post_id)
- for pic in picchop:
- if pic != '':
- picslice2 = pic.split("/")[-1]
- picslice = picslice2.split(".")
- picname = picslice[0]
- caption =title
- description = title+"\n"+address
- print (' Found Picture: ',picname)
- file_id, link = check_wordpress_media(picname, headers)
- if file_id is False:
- print(f' {str(picname)} was not already found in library, adding it')
- image = {
- "file": open(pic, "rb"),
- "post": post_id,
- "caption": caption,
- "description": description
- }
- try:
- image_response = requests.post(env.wpAPI + "/media", headers=headers, \
- files=image,timeout=env.request_timeout)
- except AttributeError as error:
- print(f" An error uploading picture {picname} occurred:", \
- type(error).__name__)
- if image_response.status_code != 201 :
- print (f' Error:Image {picname} wasnot successfully uploaded. response:'\
- ,image_response)
- else:
- pic_dic=image_response.json()
- file_id= pic_dic.get('id')
- link = pic_dic.get('guid').get("rendered")
- print (f' {picname} was successfully uploaded to website with ID: ',\
- file_id, link)
- try:
- links_dict = {'file_id' : file_id , 'link' : link}
- linkslist.append(links_dict)
- except AttributeError as error:
- print(f" An error adding to dictionary {file_id} {link} occurred:",\
- type(error).__name__) # An error occurred:
- else:
- print (f' Photo {picname} was already in library and added to post with ID: \
- {file_id} : {link}')
- try:
- image_response = requests.post(env.wpAPI + "/media/" + str(file_id),\
- headers=headers, data={"post" : post_id},timeout=env.request_timeout)
- except AttributeError as error:
- print (' Error- Image ',picname,' was not attached to post. response: ',\
- image_response+' '+type(error).__name__)
- try:
- post_response = requests.post(env.wpAPI + "/posts/" + str(post_id),\
- headers=headers,timeout=env.request_timeout)
- if link in post_response.text:
- print (' Image link for ', picname, 'already in content of post: '\
- ,post_id, post_response.text, link)
- else:
- linkslist.append({'file_id' : file_id , 'link' : link})
- except AttributeError as error:
- print(" An error loading the metadata from the post "+post_response.title+\
- ' occurred: '+type(error).__name__)
- first_mp4 = True
- first_pic = True
- fmedia = {}
- contentpics = ""
- for piclink in linkslist:
- if piclink != '':
- print (' Adding ', piclink['link'], ' to posting')
- try:
- ext = piclink['link'].split( '.')[-1]
- if ext == 'mp4':
- if first_mp4:
- contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
- r'" autoplay="true"]'
- first_mp4 = False
- else:
- contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
- else:
- contentpics+='\n '+r''
- if first_pic:
- fmedia = piclink['file_id']
- first_pic = False
- except AttributeError as error:
- print("An error occurred:", type(error).__name__) # An error occurred:
- return False
- try:
- if fmedia:
- print ('Featured Media: ',fmedia)
- else:
- if linkslist:
- fmedia = linkslist[0]['file_id']
- business_url_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
- .all()
- business_url = f"{title}"
- status_message = f'{str(title)}: Business website: {business_url}'
- response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
- data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+'\n'+\
- rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":title},\
- headers=headers,timeout=env.request_timeout)
- print (' ',response_piclinks)
- if fmedia and fmedia != 0 and featured_photo_id and featured_photo_id !=0:
- print (" Featured Media: "+str(featured_photo_id)+" "+str(fmedia)+" looks OK")
- else:
- print (" fmedia is still empty and need to populate")
- if fmedia:
- response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
- data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress\
- +'\n'+rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":\
- title},headers=headers,timeout=env.request_timeout)
- print (' Results of new results ID value : '+\
- str(get_wordpress_featured_photo_id(post_id)))
- else:
- response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
- data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+\
- googleadress+'\n'+rating+contentpics,"rank_math_focus_keyword":title},\
- headers=headers,timeout=env.request_timeout)
- print ('Results of new results ID with no picture value : '+\
- str(get_wordpress_featured_photo_id(post_id)))
- except AttributeError as error:
- print(" An error writing images to the post " + post_response.title + ' occurred:',\
- type(error).__name__) # An error occurred')
- return False
- return True
-
-##################################################################################################
-
-def post_to_wordpress2(title,content,headers,date,rating,address,picslist,local_outputs):
- """
- Post to WordPress.
-
- This function posts content to a WordPress site using the provided data.
-
- Args:
- title (str): The title of the post.
- content (str): The content of the post.
- headers: Headers for the request.
- date (str): The date of the post.
- rating (str): The rating of the post.
- address (str): The address associated with the post.
- picslist (list): A list of pictures for the post.
- local_outputs: Outputs for the post.
-
- Returns:
- None
-"""
- linkslist = ()
- addresshtml = re.sub(" ", ".",address)
- googleadress = r""+str(address)+r""
- picchop = picslist[1:-1].replace(",","").replace("'","").split(" ")
- print (' Figuring out date of Post : ',title)
- #specifify the formatting of the date_string.
- # formatting = '%b/%Y/%d'
- date_string = date
- newdate,newdate2,visitdate = get_wordpress_post_date_string(date_string,date)
- post_id, post_link = check_wordpress_post(title,newdate2,headers,local_outputs)
- if picslist and picslist != '':
- content_pics = build_picslist(picchop,picslist,post_id) #file_id
- featured_photo_id = get_wordpress_featured_photo_id(post_id)
- print(f" Featured photo ID: for {title} post {post_id} is: {featured_photo_id}")
- if env.block_google_maps is not True or env.forcegoogleupdate is True:
- try:
- database_update_row(title,"wpurl",post_link,"forceall",local_outputs)
- except AttributeError as error :
- print (f' Error: {error}')
- else:
-
- if post_id:
- print (' Post already existed: Post ID : ',post_id)
- print (' Found post for : '+title)
- if env.force_web_create:
- create_wordpress_post(newdate2,picchop,title,address,headers,post_id,linkslist,\
- local_outputs,content,googleadress,rating,featured_photo_id)
- #update_wordpress()
- else:
- print (' Found existing post but skipping updating post')
- else:
- create_wordpress_post(newdate2,picchop,title,address,headers,post_id,linkslist,\
- local_outputs,content,googleadress,rating,featured_photo_id)
- print (' Creating wordpress post from scratch for: '+title)
- return True
-
-##################################################################################################
-
-def process_reviews2(outputs):
- """
- Processes reviews data, updates social media platforms, and writes data to files.
-
- Args:
- outputs: Data outputs containing reviews and social media information.
-
- Returns:
- None
- """
-
- # Process
- webcount = xtwittercount = instagramcount = facebookcount = tiktokcount = 0
-# webcount=xtwittercount=instagramcount=yelpcount=threadscount=facebookcount=tiktokcount = 0
- if env.datasource == 'db':
- cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
- 'address','dictPostComplete']
- rows_orig = list(outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
- ttt = list(outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
- ows_orig = list(outputs['data'])
- rows_orig2 = list(outputs['xlsdf'].values)
- rows3 = outputs['data'].iter_rows(min_row=1, max_row=outputs['data'])
- rows4 = pd.DataFrame(outputs['xlsdf'])
- rows5 = pd.DataFrame(outputs['posts'])
- rows6 = pd.DataFrame(outputs['data'])
-# df2 = pd.DataFrame(outputs['xlsdf'].values, columns=cols2).iter_rows(min_row=1, max_row=outputs\
-# ['data'].max_row)
-# df3 = pd.DataFrame(outputs['xlsdf'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
-# rows = [({0:p.id},{1:p.name}, { 2:p.comment}, {3: p.rating}, {4:p.picsURL},\
-# {5:p.picsLocalpath},{6:p.source},{7:p.date},{8:p.address},{9:p.dictPostComplete})\
-# for p in rows_orig]
- # rows = list((outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row)))
- rows = outputs['posts']
- else:
- rows_orig = outputs['posts']
- rows = rows_orig
- if env.google:
- print('Configuration says to update google Reviews prior to processing them')
- options = build_google_chrome_options(
- headless=not env.showchrome,
- log_level=3,
- ignore_certificate_errors_spki_list=True,
- remote_debugging_pipe=True,
- )
- # Setting the driver path and requesting a page
- caps = webdriver.DesiredCapabilities.CHROME.copy()
- caps['acceptInsecureCerts'] = True
- caps['acceptSslCerts'] = True
- options.set_capability('cloud:options', caps)
- #driver = webdriver.Chrome(desired_capabilities=caps)
- if is_docker():
- driver = webdriver.Remote("http://192.168.10.9:4444/wd/hub", options=options)
- print ("IN A DOCKER CONTAINER, USING REMOTE CHROME")
- else:
- driver = webdriver.Chrome(options=options) # Firefox(options=options)
- # Changing the property of the navigator value for webdriver to undefined
- set_stealth_driver(driver)
- driver.get(env.URL)
- time.sleep(5)
- google_scroll(counter_google(driver), driver)
- webdata = get_google_data(driver,outputs)
- if env.datasource == 'db':
- write_to_database(webdata, outputs)
- else:
- write_to_xlsx2(webdata, outputs)
- driver.close()
- # outputs['data'].save(xls)
- print('Done getting google reviews and writing them to xls file !')
- else:
- print ('Configuration says to skip creation of new reviews from google for this run')
- print('Processing Reviews')
- for processrow in rows:
- if processrow.name != "name": # Skip header line of xls sheet
- outputs['postssession'].query(Posts).filter(Posts.name == processrow.name).\
- update({"google" : 1})
- print ("Processing : ",processrow.name)
- writtento = ast.literal_eval(processrow.dictPostComplete)
- # Check to see if the website has already been written to according to the xls sheet,\
- # if it has not... then process
- if (writtento["web"] == 0 or writtento["instagram"]==0 or writtento["facebook"]==0 or\
- writtento["xtwitter"]==0 or writtento["yelp"]==0 or writtento["tiktok"]==0 or \
- writtento["threads"]==0 ) and (check_is_port_open(env.wpAPI)) and (env.web \
- or env.instagram or env.yelp or env.xtwitter or env.tiktok or env.facebook or \
- env.threads or env.google)and (processrow.comment is not None) :
- if (env.web and processrow.web is False) or env.force_web_create is True:
- #if writtento["web"] == 0 :
- try:
- #date_string = date
- #newdate,newdate2,visitdate = get_wordpress_post_date_string(date_string,date)
- post_id, post_link = get_wordpress_post_id_and_link(processrow.name,\
- outputs['web'] )
-# post_id, post_link = check_wordpress_post(processrow.name,processrow.date,outputs['web'],outputs)
- if env.forcegoogleupdate is True and env.block_google_maps is not True:
- if post_link:
- database_update_row(processrow.name,"wpurl",post_link,"forceall"\
- ,outputs)
- else:
- print (' Error getting wordpress links to update databse')
- except AttributeError as error :
- print ('Could not check to see post already exists',error)
- webcount=process_socials("web",processrow,outputs['web'],"post_to_wordpress",\
- webcount, outputs)
- if env.instagram and processrow.instagram is False:
- instagramcount = process_socials("instagram",processrow,outputs['web'],\
- "post_to_instagram2",instagramcount, outputs)
- if env.facebook and processrow.facebook is False :
- facebookcount = process_socials("facebook",processrow,outputs['web'],\
- "post_facebook3",facebookcount, outputs)
- if env.xtwitter and processrow.xtwitter is False:
- xtwittercount = process_socials("xtwitter",processrow,outputs['web'],\
- "post_to_x2",xtwittercount, outputs)
- if env.tiktok and processrow.tiktok is False:
- tiktokcount = process_socials("tiktok",processrow,outputs['web'],\
- "post_to_tiktok",tiktokcount, outputs)
- return
-
-##################################################################################################
-
-def process_socials(social_name,social_post,headers,sub_process,social_count, local_outputs):
- """Summary:
- Function to process social media posts.
-
- Explanation:
- This function processes social media posts based on the provided parameters.
-
- Args:
- - social_name: The name of the social media platform.
- - social_post: The post content for the social media platform.
- - sub_process: The sub-process for posting.
- - social_count: The count of social media posts.
- - local_outputs: Dictionary containing outputs from the process.
-
- Returns:
- Count of the social that was selected
- """
- post_handler_map = {
- "web": post_to_wordpress,
- "instagram": post_to_instagram2,
- "facebook": post_facebook3,
- "xtwitter": post_to_x2,
- "tiktok": post_to_tiktok,
- }
- writtento = ast.literal_eval(social_post.dictPostComplete)
- post_record = local_outputs['postssession'].query(Posts).filter(
- Posts.name == social_post.name
- ).first()
- social_column = getattr(Posts, social_name)
- social_already_written = local_outputs['postssession'].query(Posts).filter(
- Posts.name == social_post.name,
- social_column.is_(True)
- ).first()
- if social_already_written is None and ((post_record is not None and post_record.wpurl is not
- None)or social_name == 'web'):
- if social_count < env.postsperrun or (social_name == 'web' and env.force_web_create is \
- True):
- try:
- print(' Starting to generate ',social_name,' post')
- new_social_post = post_handler_map[sub_process](social_post.name, social_post.comment,\
- headers, social_post.date, social_post.rating, social_post.address,\
- social_post.picsLocalpath,local_outputs )
- try:
- print (' Start generating content to post to : ',social_post.name)
- writtento[social_name] = 1
- social_post.dictPostComplete = str(writtento)
- except AttributeError as error:
- print(" An error occurred setting value to go into Excel file:", type(error)\
- .__name__)
- print (' Success Posting to xtwitter: '+social_post.name)
- if new_social_post:
- social_count +=1
- try:
- print(' write to xls for :',social_name)
- local_outputs['datawb'].save(env.xls)
- print(' Successfully wrote to xls for social - ',social_name)
- except AttributeError as error:
- print(" An error occurred writing Excel file:", type(error).__name__)
- try:
- print(' write to DB for Social - ',social_name)
- local_outputs['postssession'].query(Posts).filter(Posts.name == \
- social_post.name).update({social_name : True})
- local_outputs['postssession'].commit()
- print(' Successfully wrote to database')
- except AttributeError as error:
- print(" An error occurred writing database", type(error).__name__)
- except AttributeError as error:
- print(' Error writing social - ',social_name,' post : ',error,social_post.name,\
- social_post.comment, local_outputs,social_post.date, social_post.rating,\
- social_post.address, social_post.picsLocalpath, writtento[social_name],\
- type(error).__name__ )
- else:
- print (' Exceeded the number of social - ',social_name,' posts per run, skipping',\
- social_post.name)
- else:
- print (' ',social_name,': Skipping posting for ',social_post.name,' previously written')
- return social_count
-
-##################################################################################################
-
-if __name__ == "__main__":
- print('starting ...')
- preload()
- print('making connections ...')
- outputs = get_auth_connect()
- process_reviews2(outputs)
- print('Done!')
-
-##################################################################################################
+""" Script to download google maps reviews (that you create) and store them
+and then on a cron'd basis post them to social media connectors """
+import time
+import os
+from pathlib import Path
+import pathlib
+import re
+from datetime import datetime
+import ast
+import base64
+import datetime as dt
+from urllib.request import urlretrieve
+import inspect
+import requests
+#import json
+import jsonpickle
+import urllib3
+import pandas as pd
+from dateutil.relativedelta import relativedelta
+""" Script to download google maps reviews (that you create) and store them
+and then on a cron'd basis post them to social media connectors """
+import time
+import os
+from pathlib import Path
+import pathlib
+import re
+from datetime import datetime
+import ast
+import base64
+import datetime as dt
+from urllib.request import urlretrieve
+import inspect
+import requests
+#import json
+import jsonpickle
+import urllib3
+import pandas as pd
+from dateutil.relativedelta import relativedelta
+from openpyxl import load_workbook
+import instagrapi
+from moviepy.editor import VideoFileClip, concatenate_videoclips
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.common.exceptions import NoSuchElementException
+import tweepy
+#import asyncio
+#import aiohttp
+import sqlalchemy
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import null, update
+import googlemaps
+import env
+from review_workflow_utils import (
+ build_google_chrome_options,
+ build_review_media_path,
+ count_google_review_pages,
+ normalize_google_media_url,
+ sanitize_review_name,
+ scroll_google_reviews,
+ set_stealth_driver,
+)
+#import inspect
+Base = declarative_base()
+
+##################################################################################################
+
+class Users(Base):
+ """Class representing a user config"""
+ __tablename__ = 'userConfig'
+ id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
+ user = sqlalchemy.Column(sqlalchemy.String(length=11, collation="utf8"))
+ instagram = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ web = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ facebook = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ tiktok = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ xtwitter = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ threads = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ yelp = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ google = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ data = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ postsperrun = sqlalchemy.Column(sqlalchemy.String(length=11, collation="utf8"))
+ needreversed = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ wpAPI = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ platform = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ LinuxDriverLocation = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ WindowsDriverLocation = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ xls = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ googleurl = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ instagramuser = sqlalchemy.Column(sqlalchemy.String(length=32, collation="utf8"))
+ instagrampass = sqlalchemy.Column(sqlalchemy.String(length=32, collation="utf8"))
+ #active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+
+##################################################################################################
+
+class Posts(Base):
+ """Class representing the attributes of a post"""
+ __tablename__ = 'posts'
+ id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
+ name = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ comment = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ rating = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ picsURL = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ picsLocalpath = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ source = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+ date = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+ address = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ dictPostComplete = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ #googleurl = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ wpurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ businessurl = sqlalchemy.Column(sqlalchemy.String(length=2048, collation="utf8"))
+ longitude = sqlalchemy.Column(sqlalchemy.Float())
+ latitude = sqlalchemy.Column(sqlalchemy.Float())
+ google = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ facebook = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ instagram = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ xtwitter = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ threads = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ yelp = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ web = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ tiktok = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ #active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ place_id = sqlalchemy.Column(sqlalchemy.String(length=126, collation="utf8"))
+ review_id = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ googledetails = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ #businessurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ pluscode = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+ googleurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ visitdate = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+
+
+##################################################################################################
+
+def preload():
+ """
+ Removes a specific file if it exists.
+
+ Returns:
+ None
+ """
+
+ file=pathlib.Path("./config/joeteststeele_uuid_and_cookie.json")
+ if pathlib.Path.exists(file):
+ pathlib.Path.unlink(file)
+# today = datetime.today().strftime('%Y-%m-%d')
+ return
+
+##################################################################################################
+
+def clearlist(my_list):
+ """
+ Clears all elements in a list.
+
+ Args:
+ my_list (list): The list to be cleared.
+
+ Returns:
+ list: The input list with all elements cleared.
+ """
+
+ for listelement in my_list:
+ listelement.clear
+ return my_list
+
+##################################################################################################
+
+def get_auth_connect():
+ """Make all connections to socials and DB, etec.."""
+ connections = {}
+ if env.mariadb:
+ print('Connecting to MariaDB for configuration and storage')
+ #from sqlalchemy import create_engine
+ engine = sqlalchemy.create_engine("mysql+mysqldb://"+env.mariadbuser+":"+env.mariadbpass+
+ "@"+env.mariadbserver+"/"+env.mariadbdb+"?charset=utf8mb4", echo=False)
+ Session = sqlalchemy.orm.sessionmaker()
+ Session.configure(bind=engine)
+ session = Session()
+ dbuser = session.query(Users).filter(Users.user=='joesteele').first()
+ if dbuser is None:
+ raise ValueError("Missing userConfig row for joesteele")
+ #for userloop in usersession:
+ print("- " + dbuser.user + ' ' + dbuser.googleurl)
+ connections['user'] =dbuser
+ posts = session.query(Posts).all()
+ connections['posts'] = posts
+ connections['postssession'] = session
+ if env.data:
+ print(' loading XLS content data source ...')
+ if os.path.exists(env.xls):
+ wb = load_workbook(filename = env.xls)
+ xls_wb_df = pd.read_excel(env.xls)
+ elif os.path.exists('./GoogleScrape/'+ env.xls):
+ wb = load_workbook(filename = './GoogleScrape/'+ env.xls)
+ xls_wb_df = pd.read_excel('./GoogleScrape/'+ env.xls)
+ else:
+ raise FileNotFoundError(f"Unable to find xls file: {env.xls}")
+ ws = wb['Sheet1']
+ #xls_wb_df = pd.read_excel(xls)
+ connections |= {'xlsdf':xls_wb_df,'data':ws,'datawb':wb}
+# connections.update({'data':ws})
+# connections.update({'datawb':wb})
+
+ sheet = wb.active
+ c_row = sheet.max_row
+ c_column = sheet.max_column
+ #out_data=[]
+ #import inspect
+ #local_dict=Posts
+ column_list = []
+ my_list = []
+ my_list_data = []
+ #my_post = Posts
+ #my_dict = {}
+ for x in inspect.getmembers(Posts):
+ if not (x[0].startswith('_') or 'metadata' in x[0]):
+ column_list.append(x[0])
+ # solumn_list2[0][0]
+ #solumn_list2 = tuple(x for x in solumn_list2 if ('metadata' not in solumn_list2[0][0])\
+ # or(not solumn_list2[0][0].startswith('_')))
+# for a in range(1, c_row + 1):
+ for a in range(1, c_row + 1):
+ for b in range(2, c_column+1):
+ ob = sheet.cell(row=a, column=b)
+ my_list.append(ob.value)
+# my_post.getattr(Posts, column_list[b]) == ob.value #my_post.(eval(b,column_list))
+ #my_dict[b] = ob.value
+ my_list_data.append(str(my_list))
+ print (my_list)
+ my_list = []
+ #out_data.append(str(my_dict))
+ connections['xls_list'] = my_list_data
+# connections['xls_list'] = out_data
+ if env.instagram:
+ print(' Connecting to Instagram ...')
+ instasessionclient = instagrapi.Client()
+ instasessionclient.login(env.instagramuser, env.instagrampass)
+ connections['instagram'] = instasessionclient
+ if env.facebook:
+ print(' Connecting to facebook ...')
+ # page_id_1 = facebookpageID
+ # facebook_access_token = 'paste-your-page-access-token-here'
+ # image_url = 'https://graph.facebook.com/{}/photos'.formatting(page_id_1)
+ # image_location = 'http://image.careers-portal.co.za/f_output.jpg'
+ # img_payload = {
+ # 'message': msg,
+ # 'url': image_location,
+ # 'access_token': facebook_access_token
+ # }
+ # #Send the POST request
+ # r = requests.post(image_url, data=img_payload)
+ # print(r.text)
+ connections['facebook'] = posts
+ if env.yelp:
+ print(' Connecting to yelp ...')
+ if env.xtwitter:
+ print(' Connecting to xtwitter ...')
+ if env.threads:
+ print(' Connecting to threads ...')
+ threadssessionclient = instagrapi.Client()
+ threadssessionclient.login(env.instagramuser, env.instagrampass)
+ connections |= {'threads':threadssessionclient}
+ if env.web:
+ print(' Connecting to joeeatswhat.com ...')
+ data_string = f"{env.user}:{env.password}"
+ token = base64.b64encode(data_string.encode()).decode("utf-8")
+ connections['web'] = {"Authorization": f"Basic {token}"}
+ else:
+ connections['web'] = ""
+ if env.tiktok :
+ print(' Connecting to Instagram ...')
+ return connections
+
+##################################################################################################
+
+def get_twitter_conn_v1(api_key, api_secret, access_token, access_token_secret) -> tweepy.API:
+ """Get twitter conn 1.1"""
+ auth = tweepy.OAuth1UserHandler(api_key, api_secret)
+ auth.set_access_token(
+ access_token,
+ access_token_secret,
+ )
+ return tweepy.API(auth)
+
+##################################################################################################
+
+def get_twitter_conn_v2(api_key, api_secret, access_token, access_token_secret) -> tweepy.Client:
+ """Get twitter conn 2.0"""
+ return tweepy.Client(
+ consumer_key=api_key,
+ consumer_secret=api_secret,
+ access_token=access_token,
+ access_token_secret=access_token_secret,
+ )
+
+##################################################################################################
+
+def get_hastags(address, name, hashtype):
+ """
+ Generates hashtags based on the address, name, and type provided.
+
+ Args:
+ address (str): The address related to the content.
+ name (str): The name associated with the content.
+ hashtype (str): The type of hashtags to generate.
+
+ Returns:
+ str: The generated hashtags based on the input parameters.
+ """
+
+ name_no_spaces = re.sub( r'[^a-zA-Z]','',name)
+ addressdict = address.rsplit(r' ',3)
+ try:
+ zip_code = addressdict[3]
+ except:
+ zip_code = '34787'
+ try:
+ state = addressdict[2]
+ except:
+ state = 'Florida'
+ try:
+ city = re.sub( r'[^a-zA-Z]','',addressdict[1])
+ except:
+ city = 'WinterGarden'
+ if 'short' in hashtype:
+ defaulttags = '#'+name_no_spaces+' #foodie #food #joeeatswhat @timberjoe'
+ else:
+ defaulttags = "\n\n\n#"+name_no_spaces+\
+ " #foodie #music #food #travel #drinks #instagood #feedme #joeeatswhat @timberjoe"
+ citytag = "#"+city
+ statetag = "#"+state
+ ziptag = "#"+zip_code
+ if statetag in ['FL', 'fl','Fl']:
+ statetag += '#Florida'
+ if statetag == 'OR':
+ statetag += '#Oregon'
+ if statetag == 'MA':
+ statetag += '#Massachusetts'
+ return defaulttags+" "+citytag+" "+statetag+" "+ziptag+" "
+
+##################################################################################################
+
+# Grab a count of how far we need to scroll
+def counter_google(driver):
+ """
+ Counts the number of Google search results pages.
+
+ Args:
+ driver: The Selenium WebDriver instance.
+
+ Returns:
+ int: The total number of search result pages.
+ """
+ return count_google_review_pages(driver)
+
+##################################################################################################
+
+def make_montage_video_from_google(inphotos,cleanname):
+ """
+ Creates a montage video from a list of input photos.
+
+ Args:
+ inphotos (list): List of paths to input photo files.
+
+ Returns:
+ tuple: A tuple containing the path to the output video file and a boolean indicating succe
+ """
+
+# Load the photos from the folder
+# Set the duration of each photo to 2 seconds
+ if not inphotos:
+ return False, False
+ directory = inphotos[0].rsplit(r'/', 1)
+ folder = directory[0]
+ output = folder+"/"+cleanname+"-montage.mp4"
+ if not os.path.exists(output) and len(inphotos) >0:
+ video = VideoFileClip(inphotos[0])
+ for photo in inphotos :
+ #clip = VideoFileClip("myHolidays.mp4").subclip(50,60)
+ clip = VideoFileClip(photo)
+ # Concatenate the photos into a clip
+ if ".jpg" in photo:
+ clip.duration = 2
+ try:
+ video = concatenate_videoclips([video, clip], method="compose")
+ except AttributeError as error:
+ print(" An error occurred :", type(error).__name__) # An error occurred:
+ # Load the audio file
+ # audio = AudioFileClip("audio.mp3")
+ # Set the audio as the soundtrack of the montage
+ # montage = montage.set_audio(audio)
+ # Write the final montage to a file
+ outputvideo = video.write_videofile(output, fps=24)
+ else:
+ outputvideo = False
+ return outputvideo, output
+
+##################################################################################################
+
+def is_docker():
+ """
+ Checks if the code is running in a Docker container.
+
+ Returns:
+ bool: True if running in a Docker container, False otherwise.
+ """
+ cgroup = Path('/proc/self/cgroup')
+ #print (cgroup.read_text())
+ return Path('/.dockerenv').is_file() or cgroup.is_file() and 'docker' in \
+ cgroup.read_text(encoding="utf-8")
+
+##################################################################################################
+
+def post_facebook_video(group_id, video_path, auth_token, title, content, date, rating, address):
+ """
+ Posts a video to a Facebook group with specified details.
+
+ Args:
+ group_id (str): The ID of the Facebook group.
+ video_path (list): List of paths to the video files to be uploaded.
+ auth_token (str): The authentication token for posting to Facebook.
+ title (str): The title of the video.
+ content (str): Additional content to be included in the post.
+ date (str): The date of the post.
+ rating (str): The rating associated with the post.
+ address (str): The address related to the post.
+
+ Returns:
+ dict or bool: The response JSON if successful, False if an error occurs.
+ """
+
+ url = f"https://graph-video.facebook.com/{group_id}/videos?access_token=" + auth_token
+ addresshtml = re.sub(" ", ".",address)
+ files = {eachfile: open(eachfile, 'rb') for eachfile in video_path}
+ data = { "title":title,"description" : title + "\n"+ address+"\nGoogle map to destination: "
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n"+ content +
+ "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title, 'long')+
+ "\n\nhttps://www.joeeatswhat.com"+"\n\n","published" : True,
+ "alt_text" : title
+ }
+ try:
+ r = requests.post(url, files=files, data=data,timeout=env.request_timeout).json()
+ except AttributeError as error:
+ print(" An error getting date occurred:", error) # An error occurred:
+ r = False
+ time.sleep(env.facebooksleep)
+ return r
+
+##################################################################################################
+
+##################################################################################################
+
+def post_threads_video(group_id, video_path, auth_token, title, content, date, rating, address):
+ """
+ Posts a video to a Facebook group with specified details.
+
+ Args:
+ group_id (str): The ID of the Facebook group.
+ video_path (list): List of paths to the video files to be uploaded.
+ auth_token (str): The authentication token for posting to Facebook.
+ title (str): The title of the video.
+ content (str): Additional content to be included in the post.
+ date (str): The date of the post.
+ rating (str): The rating associated with the post.
+ address (str): The address related to the post.
+
+ Returns:
+ dict or bool: The response JSON if successful, False if an error occurs.
+ """
+ # Get url from wordpress - right now threads can only get video and pics from and external URL
+
+ connect_url = f"https://graph.threads.net/v1.0/{env.threads_page_id}/threads?media_type=\
+ VIDEO&video_url=https://www.example.com/images/bronz-fonz.jpg&text=#BronzFonz&\
+ access_token=" + auth_token
+ addresshtml = re.sub(" ", ".",address)
+ files = {eachfile: open(eachfile, 'rb') for eachfile in video_path}
+ data = { "title":title,"description" : title + "\n"+ address+"\nGoogle map to destination: "
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n"+ content +
+ "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title, 'long')+
+ "\n\nhttps://www.joeeatswhat.com"+"\n\n","published" : True,
+ "alt_text" : title
+ }
+ try:
+ r = requests.post(connect_url, files=files, data=data,timeout=env.request_timeout).json()
+ except AttributeError as error:
+ print(" An error getting date occurred:", error) # An error occurred:
+ r = False
+ time.sleep(env.facebooksleep)
+ return r
+
+##################################################################################################
+
+def get_google_data(driver, local_outputs):
+ """
+ Retrieves data from Google Maps including name, address, and review details.
+
+ Args:
+ driver: The Selenium WebDriver instance.
+ local_outputs: Output information.
+
+ Returns:
+ list: A list of data extracted from Google Maps.
+ """
+ print(' get google data...', end ="")
+ # Click on more botton on each text reviews
+ more_elemets = driver.find_elements(By.CSS_SELECTOR, '.w8nwRe.kyuRq')
+ for list_more_element in more_elemets:
+ print (".", end ="")
+ list_more_element.click()
+ print ("")
+ # Find Pictures that have the expansion indicator to see the rest of the pictures under
+ # them and click it to expose them all
+ more_pics = driver.find_elements(By.CLASS_NAME, 'Tya61d')
+ print(' Found extra pics',end = "")
+ for list_more_pics in more_pics:
+ if 'showMorePhotos' in list_more_pics.get_attribute("jsaction") :
+ print('.', end = '')
+ list_more_pics.click()
+ print ('.')
+ elements = driver.find_elements(By.CLASS_NAME, 'jftiEf')
+ lst_data = []
+ for data in elements:
+ name = data.find_element(By.CSS_SELECTOR, 'div.d4r55.YJxk2d').text
+ try:
+ address = data.find_element(By.CSS_SELECTOR, 'div.RfnDt.xJVozb').text
+ except NoSuchElementException :
+ address = 'Unknonwn'
+ print ('Name of location: ',name, ' Address:',address)
+ try:
+ visitdate = data.find_element(By.CSS_SELECTOR, 'span.rsqaWe').text
+ except NoSuchElementException :
+ visitdate = "Unknown"
+ print(' Visited: ',visitdate)
+ if re.match('^[a-zA-Z]+', visitdate) is None and re.match('^[a-zA-Z]+', visitdate) is\
+ not None:
+ #if visitdate[:1].isalpha:
+ newdate,newdate2,visitdate = get_wordpress_post_date_string(visitdate, \
+ str(datetime.now()))
+ print(' Visited altered to : ',visitdate)
+ try:
+ text = data.find_element(By.CSS_SELECTOR, 'div.MyEned').text
+ except NoSuchElementException :
+ text = ''
+ try:
+ score = data.find_element(By.CSS_SELECTOR, 'span.kvMYJc').get_attribute("aria-label")
+ #find_element(By.CSS_SELECTOR,'aria-label').text #) ##QA0Szd > div > div > div.w6VYqd >
+ # div:nth-child(2) > div > div.e07Vkf.kA9KIf > div > div > div.m6QErb.DxyBCb.kA9KIf.dS8AEf
+ # > div.m6QErb > div:nth-child(3) > div:nth-child(2) > div > div:nth-child(4) > div.DU9Pgb
+ # > span.kvMYJc
+ except NoSuchElementException as error:
+ score = "Unknown"
+ print ('Error: ',error)
+ # Grab more info from google maps entry on this particular review
+ needs_google_details = local_outputs['postssession'].query(Posts).filter(
+ Posts.name == name,
+ Posts.google.is_not(True)
+ ).first() is not None
+ if needs_google_details or env.forcegoogleupdate or env.block_google_maps is not True:
+ gmaps = googlemaps.Client(env.googleapipass)
+ place_ids = gmaps.find_place(name+address, input_type = 'textquery', fields='')
+ if len(place_ids['candidates']) == 1 :
+ place_id = place_ids['candidates'][0]['place_id']
+ details = gmaps.place(place_id)
+ # Get place details
+ try:
+ businessurl = details['result']['website']
+ latitude = details['result']['geometry']['location']['lat']
+ longitude = details['result']['geometry']['location']['lng']
+ pluscode = details['result']['plus_code']['compound_code']
+ googleurl = details['result']['url']
+ database_update_row(name,"businessurl",businessurl,"onlyempty",local_outputs)
+ database_update_row(name,"latitude",latitude,"onlyempty",local_outputs)
+ database_update_row(name,"longitude",longitude,"onlyempty",local_outputs)
+ database_update_row(name,"pluscode",pluscode,"onlyempty",local_outputs)
+ database_update_row(name,"googleurl",googleurl,"onlyempty",local_outputs)
+ database_update_row(name,"place_id",place_id,"onlyempty",local_outputs)
+ database_update_row(name,"googledetails",details,"onlyempty",local_outputs)
+ database_update_row(name,"google",True,"onlyempty",local_outputs)
+ except KeyError as error:
+ print('Error writing business details from google maps : ',error)
+ else:
+ print (' Post was already in database, skipping update unless you activate override')
+ if env.forcegoogleupdate:
+ database_update_row(name,"google",True,"forceall",local_outputs)
+ pics= []
+ pics2 = []
+ more_specific_pics = []
+ more_specific_pics = data.find_elements(By.CLASS_NAME, 'Tya61d')
+ if len(more_specific_pics) > 0:
+ # check to see if folder for pictures and videos already exists, if not, create it
+ cleanname = sanitize_review_name(name)
+ if not os.path.exists('./Output/Pics/'+cleanname):
+ os.makedirs('./Output/Pics/'+cleanname)
+ # Walk through all the pictures and videos for a given review
+ lmpics = ''
+ for lmpics in more_specific_pics:
+ # Grab URL from style definiton (long multivalue string), and remove the -p-k so that
+ # it is full size
+ urlmedia = normalize_google_media_url(lmpics.get_attribute("style"))
+ print (' Pic URL : ',urlmedia)
+ pics.append(urlmedia)
+ # Grab the name of the file and remove all spaces and special charecters to name the
+ # folder
+ filename = re.sub( r'[^a-zA-Z0-9]','', str(lmpics.get_attribute("aria-label")))
+ if lmpics == more_specific_pics[0]:
+ lmpics.click()
+ time.sleep(2)
+ #iframe = driver.find_element(By.TAG_NAME, "iframe")
+ tempdate = str((driver.find_element(By.CLASS_NAME,'mqX5ad')).text).rsplit("-",1)
+ visitdate = re.sub( r'[^a-zA-Z0-9]','',tempdate[1])
+ #print (' Visited: ',visitdate)
+ # Check to see if it has a sub div, which represents the label with the video length
+ # displayed, this will be done
+ # because videos are represented by pictures in the main dialogue, so we need to click
+ # through and grab the video URL
+ if lmpics.find_elements(By.CSS_SELECTOR,'div.fontLabelMedium.e5A3N') :
+ ext='.mp4'
+ lmpics.click()
+ time.sleep(2)
+ # After we click the right side is rendered in an inframe,
+ # Store iframe web element
+ iframe = driver.find_element(By.TAG_NAME, "iframe")
+ # switch to selected iframe
+ driver.switch_to.frame(iframe)
+ # Now find button and click on button
+ video_elements = driver.find_elements(By.XPATH ,'//video')
+ urlmedia = str((video_elements[0]).get_attribute("src"))
+ current_url = video_elements[0]._parent.current_url
+ # return back away from iframe
+ driver.switch_to.default_content()
+ else:
+ # The default path if it is not a video link
+ ext='.jpg'
+ filename = filename+ext
+ # Test to see if file already exists, and if it does not grab the media and store
+ # in location folder
+ pics_local_path = build_review_media_path(name, visitdate, filename)
+ if not os.path.isfile(pics_local_path):
+ urlretrieve(urlmedia, pics_local_path)
+ # Store the local path to be used in the excel document
+ pics2.append(pics_local_path)
+ if env.forcegoogleupdate:
+ database_update_row(name,"review_id",current_url,"forceall",local_outputs)
+ if len(pics2) > 0 and not os.path.isfile("./Output/Pics/"+cleanname+"/"+visitdate+\
+ '/'+cleanname+'-montage.mp4'):
+ make_montage_video_from_google(pics2,cleanname)
+ for loop in pics2:
+ if "montage.mp4" in loop:
+ outputmontage = loop
+ break
+ #sif pathlib.Path.exists(outputmontage):
+ pics2.append("./Output/Pics/"+cleanname+"/"+visitdate+'/'+cleanname+'-montage.mp4')
+ dict_post_complete= {'google':1,'web':0,'yelp':0,'facebook':0,'xtwitter':0,
+ 'instagram':0,'tiktok':0}
+ lst_data.append([name , text, score,pics,pics2,"GoogleMaps",visitdate,address,
+ dict_post_complete])
+ if env.force_web_create:
+ database_update_row(name,"visitdate",visitdate,"forceall",local_outputs)
+ return lst_data
+
+##################################################################################################
+
+# Do the google_scroll
+def google_scroll(counter_google_scroll,driver):
+ """
+ Scrolls down a Google search results page a specified number of times.
+
+ Args:
+ counter_google_scroll (int): The number of times to scroll down the page.
+ driver: The Selenium WebDriver instance.
+
+ Returns:
+ int: The result of the last scroll operation.
+
+ Raises:
+ AttributeError: If an error occurs during scrolling.
+ """
+ return scroll_google_reviews(driver, counter_google_scroll, label='google_scroll...')
+
+##################################################################################################
+
+def write_to_xlsx2(data, local_outputs):
+ """
+ Writes data to an Excel file and updates the database with new entries.
+
+ Args:
+ data: Data to be written to the Excel file.
+ local_outputs: Output information.
+
+ Returns:
+ Data: The data that was written to the Excel file.
+ """
+
+ print('write to excel...')
+ sqlalchemy.null()
+ cols = ["name", "comment", 'rating','picsURL','picsLocalpath','source','date','address',
+ 'dictPostComplete']
+ cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
+ 'address','dictPostComplete']
+ df = pd.DataFrame(data, columns=cols)
+ df2 = pd.DataFrame(local_outputs['xlsdf'].values, columns=cols2)
+ #df2 = df1.where((pd.notnull(df)), None) # take out NAN problems
+ #df3.astype(object).where(pd.notnull(df2), None)
+ print ('Dropped items not included in sync to database: ',df2.dropna(inplace=True))
+ rows = list(data)
+ if env.needreversed:
+ rows = reversed(rows)
+ #jsonposts = json.dumps(local_outputs['posts'], default=Posts)
+ print("Encode Object into JSON formatted Data using jsonpickle")
+ jsonposts = jsonpickle.encode(local_outputs['posts'], unpicklable=False)
+ for processrow in df2.values:
+ if processrow[1] in df.values:
+ print (' Row ',processrow.id,' ', processrow.name ,' already in XLS sheet')
+ d2_row = Posts(name=processrow.name ,comment=processrow.comment,rating=\
+ processrow.rating,picsURL=processrow.picsURL,pics_local_path=processrow.\
+ picsLocalpath,source=processrow.source,date=processrow.date,address=processrow.\
+ address,dict_post_complete=processrow.dictPostComplete)
+ elif processrow.name is not None:
+# Create a Python dictionary object with all the column values
+# d_row = {'name':processrow.name ,'comment':processrow.comment,'rating':processrow.rating,
+# 'picsURL':processrow.picsURL,'pics_local_path':processrow.picsLocalpath, 'source':\
+# processrow.source,'date':processrow.date,'address':processrow.address,'dict_post_complete'\
+# :processrow.dictPostComplete}
+ d2_row = Posts(name=processrow.name ,comment=processrow.comment,rating=processrow.\
+ rating,picsURL=processrow.picsURL,pics_local_path=processrow.picsLocalpath,\
+ source=processrow.source,date=processrow.date,address=processrow.address,\
+ dict_post_complete=processrow.dictPostComplete)
+ print (' Row ',processrow[0],' ', processrow.name ,' added to XLS sheet')
+ # Append the above Python dictionary object as a row to the existing pandas DataFrame
+ # Using the DataFrame.append() function
+ try:
+ if processrow.name in jsonposts : #local_outputs['posts']):
+ print (' Row ',processrow[0],' ', processrow.name ,' already in Database')
+ else:
+ local_outputs['postssession'].add(d2_row)
+ local_outputs['postssession'].commit()
+ print (' Row ',processrow[0],' ', processrow.name ,' added to Database')
+ except AttributeError as error:
+ print(' Not able to write to post data table: ' , type(error))
+ local_outputs['postssession'].rollback()
+ raise
+ df.to_excel(env.xls)
+ return data
+
+##################################################################################################
+
+def write_to_database(data, local_outputs):
+ """
+ Writes data to the database and updates the database with new entries.
+
+ Args:
+ data: Data to be written to the database.
+ local_outputs: Local output information.
+
+ Returns:
+ Data: The data that was written to the database.
+ """
+ column_list=[]
+ print('write to database ...')
+ for x in inspect.getmembers(Posts):
+# if not (x[0].startswith('_') or 'metadata' in x[0] or 'registry' in x[0] or 'id' in x[0]):
+ if not (x[0].startswith('_') or 'metadata' in x[0] or 'registry' in x[0]):
+ column_list.append(x[0])
+ #cols = ["name", "comment", 'rating','picsURL','picsLocalpath','source','date','address',
+ # 'dictPostComplete','visitdate']
+ #cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
+ # 'address','dictPostComplete','visitdate']
+ #df = pd.DataFrame(local_outputs["xls"], columns=cols)
+# df = pd.DataFrame(local_outputs['xlsdf'])
+ df = pd.DataFrame(local_outputs['xlsdf'].values, columns=column_list)
+ #df2 = pd.DataFrame(local_outputs['posts'], columns=column_list)
+ df2 = pd.DataFrame(local_outputs['posts'])
+ # print ('Dropped items not included in sync to database: ',df2.dropna(inplace=True))
+# rows = list(data)
+ # if env.needreversed:
+ # rows = reversed(rows)
+ #jsonposts = json.dumps(local_outputs['posts'], default=Posts)
+ df.to_excel(env.xls)
+ print("Encode Object into JSON formatted Data using jsonpickle")
+ jsonposts = jsonpickle.encode(local_outputs['posts'], unpicklable=False)
+ for processrow in data:
+# getdata = local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0])
+ #if processrow[0] in local_outputs['posts']:
+# if getdata.count() >0:
+ # if len(result) > 0:
+# print (' Row ',processrow[0],' already in database')
+# d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
+# ,picsURL=processrow[3],picsLocalpath=processrow[4],\
+# source=processrow[5],date=processrow[6],address=processrow[7],\
+# dictPostComplete=processrow[8])
+# d2_dict = {'name':processrow[0] ,'comment':processrow[1],'rating':processrow[2]\
+# ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
+# 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
+# 'dictPostComplete':str(processrow[8])}
+# if env.forcegoogleupdate:
+# print (' Row ',processrow[0],' updated in database due to forcegoogleupdate')
+# local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0]).\
+# update\
+# (d2_dict)
+# local_outputs['postssession'].commit()
+# elif processrow[0] is not None:
+# # Create a Python dictionary object with all the column values
+# # d_row = {'name':processrow.name ,'comment':processrow.comment,'rating':processrow.rating,
+# # 'picsURL':processrow.picsURL,'pics_local_path':processrow.picsLocalpath, 'source':
+# # processrow.source,'date':processrow.date,'address':processrow.address,'dict_post_complete'
+# # :processrow.dictPostComplete}
+# d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
+# ,picsURL=str(processrow[3]),picsLocalpath=str(processrow[4]),\
+# source=processrow[5],date=processrow[6],address=processrow[7],\
+# dictPostComplete=str(processrow[8]))
+# print (' Row ',processrow[0],' added to Database')
+# # Append the above Python dictionary object as a row to the existing pandas DataFrame
+# # Using the DataFrame.append() function
+ try:
+ getdata2 = local_outputs['postssession'].query(Posts).filter(Posts.name ==\
+ processrow[0])
+ if getdata2.count() >0:
+ print (' Row ',processrow[0],' already in Database')
+ if env.forcegoogleupdate:
+ print (' Row ',processrow[0],' updated in database due to forcegoogleupdate')
+ d2_dict = {'name':processrow[0] ,'comment':processrow[1],'rating':\
+ processrow[2]\
+ ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
+ 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
+ 'dictPostComplete':str(processrow[8])}
+ local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ processrow[0]).update(d2_dict)
+ local_outputs['postssession'].commit()
+ else:
+ # d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
+ # ,picsURL=processrow[3],picsLocalpath=processrow[4],\
+ # source=processrow[5],date=processrow[6],address=processrow[7],\
+ # dictPostComplete=processrow[8])
+ d2_row = {'name':processrow[0] ,'comment':processrow[1],'rating':\
+ processrow[2]\
+ ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
+ 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
+ 'dictPostComplete':str(processrow[8])}
+ local_outputs['postssession'].add(d2_row)
+ local_outputs['postssession'].commit()
+ print (' Row ',processrow[0],' added to Database')
+ except AttributeError as error:
+ print(' Not able to write to post data table: ' , type(error))
+ local_outputs['postssession'].rollback()
+ raise
+ processrow = []
+ df.to_excel(env.xls)
+ return data
+
+##################################################################################################
+
+def database_update_row(review_name, column_name, column_value, update_style, local_outputs):
+ """
+ Updates a row in the database based on the specified review name, column name, value,
+ and update style.
+
+ Args:
+ review_name (str): The name of the review to update.
+ column_name (str): The name of the column to update.
+ column_value: The value to update the column with.
+ update_style (str): The style of update to perform.
+ local_outputs: Local output information.
+
+ Returns:
+ bool: True if the row was successfully updated, False otherwise.
+ """
+
+ try:
+ if update_style == "forceall" and column_value is not False:
+ local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).update\
+ ({column_name : column_value})
+ print (' Force Updated ',column_name, ' to: ',column_value)
+ elif update_style == "onlyempty" and column_value is not False:
+ postval = local_outputs['postssession'].query(Posts).filter(Posts.name == review_name,\
+ getattr(Posts,column_name).is_not(null())).all()
+ if len(postval) == 0 :
+ local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).\
+ update({column_name : column_value})
+ print (' Updated blank ',postval ,' on value',column_name, ' to: ',\
+ column_value)
+ elif update_style == "toggletrue":
+ postval = local_outputs['postssession'].query(Posts).filter(Posts.name == review_name\
+ ,getattr(Posts,column_name).is_not(1)).all()
+ local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).update\
+ ({column_name : "1"})
+ print (' Updated ',column_name, ' on value: ',postval[0].column_value, ' to: ',\
+ column_value)
+ except AttributeError as error:
+ print(" Not able to write to post data table to update ",review_name," ",column_name,"\
+ to: ",column_value , type(error), error)
+ local_outputs['postssession'].rollback()
+ raise
+# else:
+ local_outputs['postssession'].commit()
+ #time.sleep(env.facebooksleep)
+ return True
+
+##################################################################################################
+
+def check_wordpress_media(filename, headers):
+ """
+ Checks if a media file exists in the WordPress media folder.
+
+ Args:
+ filename (str): The name of the media file to check.
+ headers: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the media file if found, otherwise
+ (False, False).
+ """
+
+ file_name_minus_extension = filename
+ response = requests.get(env.wpAPI + "/media?search="+file_name_minus_extension,\
+ headers=headers,timeout=env.request_timeout)
+ try:
+ if result := response.json():
+ file_id = int(result[0]['id'])
+ link = result[0]['guid']['rendered']
+ return file_id, link
+ else:
+ return False,False
+ except AttributeError:
+ print(' No existing media with same name in Wordpress media folder: '+filename)
+ return (False, False)
+
+##################################################################################################
+
+def check_is_port_open(host):
+ """
+ Checks if a port on a host is open.
+
+ Args:
+ host (str): The host to check for an open port.
+ port (int): The port number to check.
+
+ Returns:
+ bool: True if the port is open, False otherwise.
+ """
+
+ try:
+ is_web_up = urllib3.request("GET", host, timeout=env.request_timeout)
+ if is_web_up.status == 200:
+ return True
+ except AttributeError as error:
+ print ('Could not open port to website: ', host, type(error))
+ return False
+
+##################################################################################################
+
+def get_wordpress_post_id_and_link(postname, headers2):
+ """
+ Retrieves the ID and link of a WordPress post based on the post name.
+
+ Args:
+ postname (str): The name of the WordPress post to retrieve.
+ headers2: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the WordPress post.
+ """
+
+ response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,timeout=\
+ env.request_timeout)
+ result = response.json()
+ if len(result) > 0:
+ return int(result[0]['id']), result[0]['link']
+ print(' No existing post with same name: ' + postname)
+ return False, False
+
+##################################################################################################
+
+def check_wordpress_post(postname, postdate, headers2,local_outputs):
+ """
+ Checks if a WordPress post with the given name and date exists.
+
+ Args:
+ postname (str): The name of the WordPress post to check.
+ postdate: The date of the WordPress post to check.
+ headers2: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the existing post if found,
+ otherwise (False, False).
+ """
+
+ try:
+ response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,\
+ timeout=env.request_timeout)
+ result = response.json()
+ except AttributeError as error:
+ print ('Could not query for post on wordpress: ', postname,postdate, type(error))
+ return False, False
+ # try:
+ # newdate,newdate2,visitdate = get_wordpress_post_date_string(result[0]['date'],\
+ # result[0]['date'])
+ # newdate3,newdate4,visitdate2 = get_wordpress_post_date_string(postdate,str(datetime.now()))
+ # if visitdate and visitdate2:
+ # print ('Post exists, checking visit date')
+ # except KeyError as error:
+ # print (' Post exists but does not have post date in visitdate field:',error)
+ if len(result) > 0:
+ d1list = result[0]['date'].split("-")
+ d2list = postdate.split("-")
+ if d1list[0] == d2list[0] and d1list[1] == d2list[1]:
+ return int(result[0]['id']), result[0]['link']
+ else:
+ print(' -No existing post with same name: ' + postname)
+ return False, False
+
+##################################################################################################
+def check_wordpress_post2(postname, postdate, post_id, headers2,local_outputs):
+ """
+ Checks if a WordPress post with the given name and date exists.
+
+ Args:
+ postname (str): The name of the WordPress post to check.
+ postdate: The date of the WordPress post to check.
+ headers2: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the existing post if found,
+ otherwise (False, False).
+ """
+
+ try:
+ response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,\
+ timeout=env.request_timeout)
+ result = response.json()
+ except AttributeError as error:
+ print ('Could not query for post on wordpress: ', postname,postdate, type(error))
+ return False, False
+ # try:
+ # newdate,newdate2,visitdate = get_wordpress_post_date_string(result[0]['date'],
+ # result[0]['date'])
+ # newdate3,newdate4,visitdate2 = get_wordpress_post_date_string(postdate,str(datetime.now()))
+ # if visitdate and visitdate2:
+ # print ('Post exists, checking visit date')
+ # except KeyError as error:
+ # print (' Post exists but does not have post date in visitdate field:',error)
+ if len(result) > 0:
+ d1list = result[0]['date'].split("-")
+ d2list = postdate.split("-")
+ if d1list[0] == d2list[0] and d1list[1] == d2list[1]:
+ return int(result[0]['id']), result[0]['link']
+ print(' -No existing post with same name: ' + postname)
+ return False, False
+
+##################################################################################################
+
+# Function to get the featured photo ID of a WordPress post
+def get_wordpress_featured_photo_id(post_id):
+ """ Get photoid from featured photo
+
+ Args:
+ post_id (_type_): _description_
+
+ Returns:
+ _type_: _description_
+ """
+ # Make a GET request to the WordPress REST API to retrieve media details
+ response = requests.get(f"{env.wpAPOurl}/{post_id}",timeout=env.request_timeout)
+ # Check if the request was successful
+ if response.status_code == 200:
+ # Parse the JSON response
+ media_items = response.json()
+
+ # Loop through the media items associated with the post
+ # for item in media_items:
+ # # Check if the media item is the featured image
+ # if item.get('post', None) == int(post_id):
+ # # Return the ID of the featured image
+ return media_items['featured_media']
+ # If the request failed or the featured image was not found, return None
+ return None
+# # Example usage
+# featured_photo_id = get_featured_photo_id(POST_ID)
+# print(f"The featured photo ID for post {POST_ID} is: {featured_photo_id}")
+
+##################################################################################################
+
+def post_to_x2(title, content, headers,date, rating, address, picslist,local_outputs):
+ """
+ Post to x2.
+
+ This function posts content to a social media platform using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ date (str): The date of the post.
+ rating (int): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ instasession: The Instagram session for posting.
+
+ Returns:
+ str: The media ID of the posted content.
+ """
+ pics = ((picslist[1:-1]).replace("'","")).split(",")
+ # Replace the following strings with your own keys and secrets
+ CONSUMER_KEY = env.x_consumer_key
+ CONSUMER_SECRET = env.x_consumer_secret
+ ACCESS_TOKEN = env.x_access_token
+ ACCESS_TOKEN_SECRET = env.x_access_token_secret
+ # Authenticate to Twitter
+ auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
+ auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
+ # Create an API object to use the Twitter API
+ #api = tweepy.API(auth)
+ img_list = pics
+ imgs_vid = []
+ imgs_pic = []
+ client_v1 = get_twitter_conn_v1(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
+ client_v2 = get_twitter_conn_v2(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
+ for img in img_list:
+ if 'montage.mp4' in img:
+ imgs_vid.append(img.strip())
+ else:
+ imgs_pic.append(img.strip())
+ if imgs_vid:
+ try:
+ video_path = imgs_vid[0]
+ # Message to post along with the video
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
+ .all()
+ business_url = attrib_list[0].businessurl
+ wpurl = attrib_list[0].wpurl
+ if wpurl: # Don't post of website URL does not exist yet
+ if business_url: #Sometimes Business URL does not exist, so account for it
+ status_message=str(title)+': My Review - '+wpurl+'\n Business website: '+\
+ business_url + '\n'
+ else:
+ status_message = str(title) + ': My Review - '+ wpurl + '\n'
+ status_message2 = status_message +' '+str(get_hastags(address, title, 'short'))\
+ +' '
+ status_message_short = status_message2[:279]
+ # Upload video
+ media = client_v1.media_upload(filename=video_path)
+ # Post tweet with video
+ # tweetlat = (local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ # title).all())[0].latitude
+ # tweetlong = (local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ # title).all())[0].longitude
+ if media.processing_info['state'] != 'failed':
+ client_v2.create_tweet(text=status_message_short,media_ids=[media.media_id])
+# client_v2.create_tweet(text=status_message_short, lat=tweetlat , \
+# long=tweetlong ,media_ids=[media.media_id])
+ else:
+ print ('Problem uploading video to twitter: ',media.processing_info['error'])
+ return False
+ else:
+ print (' Skipping xtwitter post because wordpress URL is missing')
+ except AttributeError as error:
+ print("AttributeError An error occurred:",error) # An error occurred:
+ else:
+ print (' xtwitter: No video available, skipping twitter post for : ',title)
+ return False
+ time.sleep(env.facebooksleep)
+ return True
+
+##################################################################################################
+
+def post_to_threads(title, content,headers, date, rating, address, picslist, local_outputs):
+ img_list = ((picslist[1:-1]).replace("'","")).split(",")
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ business_url = attrib_list[0].businessurl
+ wpurl = attrib_list[0].wpurl
+ auth_token = env.threads_access_token
+ group_id = env.threads_page_id
+ imgs_id = []
+ imgs_vid = []
+ imgs_pic = []
+ if wpurl and (attrib_list[0].picsLocalpath != '[]'):
+ if business_url:
+ status_message = (
+ f'{str(title)}: My Review - {wpurl} \n Business website: {business_url}'\
+ + ' \n\n') + content
+ else:
+ status_message = f'{str(title)}: My Review - ' + wpurl + ' \n\n' + content
+ for img in img_list:
+ if 'montage.mp4' in img:
+ imgs_vid.append(img.strip())
+ else:
+ imgs_pic.append(img.strip())
+ if imgs_vid:
+ try:
+ post_id = post_threads_video(group_id, imgs_vid,auth_token,title, status_message,
+ date, rating, address)
+ imgs_id.append(post_id['id'])
+ except AttributeError as error:
+ print(" An error occurred:",error)
+ return False
+ time.sleep(env.facebooksleep)
+ print(' threads response: ',post_id)
+ else:
+ print (' threads: Wordpress URL or no pictures so skipping threads posting')
+ return True
+
+##################################################################################################
+
+def post_facebook3(title, content,headers, date, rating, address, picslist, local_outputs):
+ """
+ Post to Facebook3.
+
+ This function posts content to Facebook using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ date (str): The date of the post.
+ rating (int): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ instasession: The Instagram session for posting.
+
+ Returns:
+ bool: Indicates if the post was successfully made.
+ """
+ pics = ((picslist[1:-1]).replace("'","")).split(",")
+ group_id = env.facebookpageID
+ auth_token = env.facebookpass
+ imgs_id = []
+ imgs_vid = []
+ imgs_pic = []
+ img_list = pics
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ business_url = attrib_list[0].businessurl
+ wpurl = attrib_list[0].wpurl
+ if wpurl and (attrib_list[0].picsLocalpath != '[]'):
+ if business_url:
+ status_message = (
+ f'{str(title)}: My Review - {wpurl} \n Business website: {business_url}'\
+ + ' \n\n') + content
+ else:
+ status_message = f'{str(title)}: My Review - ' + wpurl + ' \n\n' + content
+ for img in img_list:
+ if 'montage.mp4' in img:
+ imgs_vid.append(img.strip())
+ else:
+ imgs_pic.append(img.strip())
+ if imgs_vid:
+ try:
+ post_id = post_facebook_video(group_id, imgs_vid,auth_token,title, status_message,
+ date, rating, address)
+ imgs_id.append(post_id['id'])
+ except AttributeError as error:
+ print(" An error occurred:",error)
+ return False
+ time.sleep(env.facebooksleep)
+ print(' Facebook response: ',post_id)
+ else:
+ print (' facebook: Wordpress URL or no pictures so skipping Facebook posting')
+ return True
+
+##################################################################################################
+
+def post_to_threads2(title, content, headers, date, rating, address, picslist, local_outputs):
+ """
+ Posts content to threads if picslist is not empty and contains 'montage.mp4'.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers information.
+ date: Date information.
+ rating: Rating information.
+ address: Address information.
+ picslist: List of pictures.
+ local_outputs: Local output information.
+
+ Returns:
+ bool: True if the post was successfully uploaded to Instagram, False otherwise.
+ """
+ pics = ((picslist[1:-1]).replace("'","")).split(",")
+ if pics != '[]' and "montage.mp4" in pics:
+ outputmontage = ''
+ addresshtml = re.sub(" ", ".",address)
+ #content = content + get_hastags(address, title)
+ pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
+ #video, outputmontage = make_montage_video_from_google(pics)
+ for loop in pics:
+ if "montage.mp4" in loop:
+ outputmontage = loop
+ break
+ if pathlib.Path.exists(outputmontage):
+ try:
+ data = title + "\n"+ address+"\nGoogle map to destination: " \
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n" \
+ + content + "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title,'long')+ \
+ "\n\nhttps://www.joeeatswhat.com "+"\n\n"
+ local_outputs['instasession'].video_upload(outputmontage, data)
+ except AttributeError as error:
+ print(" An error occurred uploading video to Threads:", type(error).__name__)
+ return False
+ return True
+ else:
+ return False
+
+###################################################################################################
+
+# def tiktok_upload_video(session_id, file_path, title, tags, schedule_time=None):
+# url = 'https://www.tiktok.com/api/upload/video/'
+# headers = {
+# 'Cookie': f'sessionid={session_id}'
+# }
+# data = {
+# 'title': title,
+# 'tags': ','.join(tags),
+# 'schedule_time': schedule_time
+# }
+# files = {
+# 'video': open(file_path, 'rb')
+# }
+# response = requests.post(url, headers=headers, data=data, files=files)
+# return response.json()
+
+def post_to_tiktok(title, content, headers2, date, rating, address, picslist, local_outputs):
+ """
+ Posts content to TikTok with specified session ID, video file, title, hashtags, and optional
+ scheduling.
+
+ Args:
+ title (str): The title of the video.
+ content (str): The content of the video.
+ headers: Headers information.
+ date: Date information.
+ rating: Rating information.
+ address: Address information.
+ picslist: List of pictures.
+ local_outputs: Local output information.
+
+ Returns:
+ None
+ """
+ # Replace 'your_sessionid_cookie' with your actual TikTok sessionid cookie.
+ #session_id = env.tiktok_client_secret
+
+ # Replace 'path_to_video.mp4' with the path to your video file.
+ #file_path = 'path_to_video.mp4'
+
+ # Replace 'Your video title' with the title of your video.
+ #title = 'Your video title'
+
+ # Replace the following list with the hashtags you want to add to your post.
+ tags = get_hastags(address, title,'long')
+
+ # If you want to schedule your video, replace 'schedule_timestamp' with the Unix timestamp.
+ # Leave it as None if you want to upload immediately.
+ schedule_time = None # or Unix timestamp (e.g., 1672592400)
+ pics = ((picslist[1:-1]).replace("'","").replace(" ","")).split(",")
+ if any(element.endswith("montage.mp4") for element in pics):
+ for pic in pics:
+ if 'montage.mp4' in pic:
+ file_path = pic
+ else:
+ return False
+ #content = content + get_hastags(address, title)
+ #pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
+# video, outputmontage = make_montage_video_from_google(pics)
+ # try:
+ # instasession.video_upload(outputmontage, data)
+ # except AttributeError as error:
+ # print(" An error occurred uploading video to Instagram:", type(error).__name__)
+ # return False
+ # return True
+ # """
+ # client_key string The unique identification key
+ # provisioned to the partner.
+ # client_secret string The unique identification secret provisioned
+ # to the partner.
+ # code string The authorization code from the web, iOS, Android or desktop
+ # authorization callback. The value should be URL decoded.
+ # grant_type string Its value should always be set as
+ # authorization_code.
+ # redirect_uri string Its value must be the same as the redirect_uri used
+ # for requesting code.
+ # curl --location --request POST 'https://open.tiktokapis.com/v2/oauth/token/' \
+ # --header 'Content-Type: application/x-www-form-urlencoded' \
+ # --header 'Cache-Control: no-cache' \
+ # --data-urlencode 'client_key=CLIENT_KEY' \
+ # --data-urlencode 'client_secret=CLIENT_SECRET' \
+ # --data-urlencode 'code=CODE' \
+ # --data-urlencode 'grant_type=authorization_code' \
+ # --data-urlencode 'redirect_uri=REDIRECT_URI'
+ # """
+
+# curl --location 'https://open.tiktokapis.com/v2/post/publish/inbox/video/init/' \
+# --header 'Authorization: Bearer act.example12345Example12345Example' \
+# --header 'Content-Type: application/json; charset=UTF-8'
+# --data '{
+# "source_info": {
+# "source": "FILE_UPLOAD",
+# "video_size": exampleVideoSize,
+# "chunk_size" : exampleChunkSize,
+# "total_chunk_count": exampleTotalChunkCount
+# }
+# }'
+
+
+# curl --location 'https://open.tiktokapis.com/v2/post/publish/video/init/' \
+# --header 'Authorization: Bearer act.example12345Example12345Example' \
+# --header 'Content-Type: application/json; charset=UTF-8' \
+# --data-raw '{
+# "post_info": {
+# "title": "this will be a funny #cat video on your @tiktok #fyp",
+# "privacy_level": "MUTUAL_FOLLOW_FRIENDS",
+# "disable_duet": false,
+# "disable_comment": true,
+# "disable_stitch": false,
+# "video_cover_timestamp_ms": 1000
+# },
+# "source_info": {
+# "source": "FILE_UPLOAD",
+# "video_size": 50000123,
+# "chunk_size": 10000000,
+# "total_chunk_count": 5
+# }
+# }'
+
+
+
+
+# https://api.tiktok.com/open-api/v2/aweme/post/?aweme-type=video
+# You will need to include the following headers:
+
+# Content-Type: application/json
+# X-SS-TOKEN: [Your App ID]
+# X-TikTok-Signature: [Your App Secret]
+# And the following JSON body:
+
+# {
+# "device_platform": "android",
+# "device_version": "11",
+# "app_name": "musical.ly",
+# "app_version": "7.0.3",
+# "resolution": "1080*1920",
+# "os_version": "11",
+# "model": "vivo 1906",
+# "manufacturer": "vivo",
+# "language": "en",
+# "country": "US"
+# }
+
+ connect_json_body = {
+ "device_platform": "android",
+ "device_version": "11",
+ "app_name": "musical.ly",
+ "app_version": "7.0.3",
+ "resolution": "1080*1920",
+ "os_version": "11",
+ "model": "vivo 1906",
+ "manufacturer": "vivo",
+ "language": "en",
+ "country": "US"
+ }
+ connect_json_header = {
+ 'Content-Type': 'application/json',
+ 'X-SS-TOKEN': env.tiktok_app_id, #[Your App ID],
+ 'X-TikTok-Signature': env.tiktok_client_secret, #[Your App Secret]
+ }
+ connect_response = requests.post('https://open.tiktokapis.com/v2/post/publish/video/init/',headers=connect_json_header,\
+ data=connect_json_body,timeout=env.request_timeout)
+
+#request https://api.tiktok.com/open-api/v2/aweme/post/?aweme-type=video
+# https://api.tiktok.com/open-api/v2/aweme/post/
+# You will need to include the following headers:
+
+# Content-Type: multipart/form-data
+# X-SS-TOKEN: [Your App ID]
+# X-TikTok-Signature: [Your App Secret]
+# Authorization: Bearer [Your Access Token]
+# And the following form data:
+
+# video: [Your Video File]
+# desc: [Your Video Description]
+# Once you have made this request, your video will be uploaded to TikTok.
+ post_json_header = {
+ 'X-SS-TOKEN': env.tiktok_app_id,#[Your App ID],
+ 'X-TikTok-Signature': env.tiktok_client_secret,#[Your App Secret]
+ 'Authorization': 'ww'#Bearer [Your Access Token]
+ }
+ post_json_body = {
+ 'video': file_path,
+ 'desc': content+tags
+ }
+
+ post_response = requests.post('https://api.tiktok.com/open-api/v2/aweme/post/',headers=post_json_header,\
+ data=post_json_body,timeout=env.request_timeout)
+
+
+
+ # headers = ['Content-Type: application/x-www-form-urlencoded','Cache-Control: no-cache']
+ # data = ['client_key='+env.tiktok_client_key,'client_secret='+env.tiktok_client_secret,\
+ # 'code='+env.tiktok_app_id,'grant_type=authorization_code','redirect_uri=http://www.joeeatswhat.com']
+ # allheaders = headers + data
+
+ # try:
+ # data2 = {'source_info':{'source':"FILE_UPLOAD",file_path}}
+ # response = requests.post('https://open.tiktokapis.com/v2/oauth/token/,headers:',allheaders,\
+ # 'data:',data2,'timeout:',env.request_timeout)
+ # except BaseException as error:
+ # print(" An error occurred uploading video to TikTok:", type(error).__name__)
+ # return False
+ # Call the function to upload the video
+ # response = tiktok_upload_video(session_id, file_path, title, tags, schedule_time)
+ print(' tikTok response: ',post_response)
+ return True
+###################################################################################################
+
+def post_to_instagram2(title, content, headers, date, rating, address, picslist, local_outputs):
+ """
+ Posts content to Instagram with relevant information and media.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers for the post.
+ date: Date of the post.
+ rating: Rating of the post.
+ address: Address related to the post.
+ picslist: List of pictures for the post.
+ local_outputs: Local outputs for the post.
+
+ Returns:
+ bool: True if the post was successfully uploaded, False otherwise.
+ """
+
+ outputmontage = ''
+ addresshtml = re.sub(" ", ".",address)
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ if wpurl := attrib_list[0].wpurl:
+ if business_url := attrib_list[0].businessurl:
+ data = title + "\n"+ address+"\n"+business_url+"\n"+"Review: "+wpurl+\
+ "\nGoogle map to destination: " \
+ r"https://www.google.com/maps/dir/?api=1&destination="\
+ +addresshtml +"\n"+"Review: "+wpurl+"\n\n"+ content + "\n"+rating+"\n"+date+\
+ "\n\n"+get_hastags(address, title,'long')+"\n\nhttps://www.joeeatswhat.com"+"\n\n"
+ else:
+ print (" Missing business url for : "+title+" not using it in intagram post")
+ data = title + "\n"+ address+"\n"+"Review: "+wpurl+"\nGoogle map to destination: " \
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\nReview: "\
+ +wpurl+"\n\n"+ content + "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title\
+ ,'long')+"\n\nhttps://www.joeeatswhat.com"+"\n\n"
+ instasession = local_outputs['instagram']
+ if picslist != '[]' and "montage.mp4" in picslist:
+ #content = content + get_hastags(address, title)
+ pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
+ #video, outputmontage = make_montage_video_from_google(pics)
+ for loop in pics:
+ if "montage.mp4" in loop:
+ outputmontage = loop
+ break
+ pathoutputmontage = outputmontage[1:-1]
+ if pathlib.Path.exists(pathoutputmontage):
+ try:
+ duration, fps, (width, height)=with_moviepy(outputmontage)
+ if duration < 60:
+ instasession.video_upload(outputmontage, data)
+ else:
+ if not os.path.isfile(outputmontage+".trim.mp4"):
+ video = VideoFileClip(outputmontage)
+ video = video.subclip(0, 60)
+ print (' IG video duration too long 60 : ',duration, fps, (width,height))
+ video.write_videofile(outputmontage+".trim.mp4")
+ instasession.video_upload(outputmontage+".trim.mp4", data)
+ except BaseException as error:
+ print(" An error occurred uploading video to Instagram:", type(error).__name__)
+ return False
+ return True
+ else:
+ print (' Missing wordpress post for instagram : ',title)
+ return False
+
+##################################################################################################
+
+def with_moviepy(filename):
+ from moviepy.editor import VideoFileClip
+ clip = VideoFileClip(filename)
+ duration = clip.duration
+ fps = clip.fps
+ width, height = clip.size
+ return duration, fps, (width, height)
+
+##################################################################################################
+
+def post_to_wordpress(title,content,headers,date,rating,address,picslist,local_outputs):
+ """
+ Post to WordPress.
+
+ This function posts content to a WordPress site using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers for the request.
+ date (str): The date of the post.
+ rating (str): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ local_outputs: Outputs for the post.
+
+ Returns:
+ None
+"""
+ # post
+ #new_post = False
+ #countreview = False
+ addresshtml = re.sub(" ", ".",address)
+ googleadress = r""+str(address)+r""
+ contentpics = ''
+ picchop = ''
+ linkslist=[]
+ # picl = picslist[1:-1]
+ # pic2 = picl.replace(",","")
+ # # #re.sub(r',','',picl) #re.sub( r'[^a-zA-Z0-9]','',tempdate[1])
+ # pic3= pic2.replace("'","")
+ # picchop = pic3.split(" ")
+ # line = re.sub('[!@#$]', '', line)
+ #picchop = re.sub(',\'','',picslist[1:-1])
+ picchop = picslist[1:-1].replace(",","").replace("'","").split(" ")
+ print (' Figuring out date of Post : ',title)
+ #specifify the formatting of the date_string.
+ # formatting = '%b/%Y/%d'
+ date_string = date
+ if "a day" in date_string:
+ date = dt.timedelta(days=-1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - date
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "day" in date:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta(days=tempdate)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() + relativedelta(days=tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a week" in date:
+# date = dt.timedelta(weeks= -1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - relativedelta(weeks= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "week" in date:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta(weeks= tempdate)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() + relativedelta(weeks= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a month" in date:
+# date = dt.timedelta(months= -1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - relativedelta(months = 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "month" in date:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta(months= tempdate)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() + relativedelta(months = tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a year" in date:
+# date = dt.timedelta(years= -1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - relativedelta(years= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "year" in date:
+ try:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta( years= tempdate)
+# newdate = dt.datetime.strptime(date_string).date()
+ newdate = datetime.today() + relativedelta(years= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+ else:
+ #specifify the formatting of the date_string.
+ formatting = '%Y-%b-%d'
+ month = date[:3]
+ year = date[3:]
+ day = '01'
+ date_string = year+'-'+ month+'-'+day
+ try:
+ newdate = dt.datetime.strptime(date_string, formatting)\
+ .date()
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+# try:
+# newdate = dt.datetime.strptime(date_string, formatting)\
+# .date()
+# except AttributeError as error:
+# print(" An error getting date occurred:", error)
+ visitdate = newdate.strftime("%b%Y")
+ newdate = str(newdate)
+ #formatting = '%b/%Y/%d' #specifify the formatting of the date_string.
+ #newdate2 = dt.datetime.strptime(str(newdate), formatting).date()
+ dateparts = (str(newdate)).split("-")
+ dateparts2 = dateparts[2].split(" ")
+ visitdate2 = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
+ .all()[0].visitdate
+ if visitdate != visitdate2:
+ database_update_row(title,"visitdate",visitdate,"forceall",local_outputs)
+ print (f'UPDATED: {visitdate2} to {visitdate} for {title}')
+ #dateparts = dateparts2[0]
+# print ('dateparts',dateparts)
+ newdate2 = dateparts[0]+'-'+dateparts[1]+'-'+dateparts2[0]+'T22:00:00'
+ #newdate2 = str(re.sub(r'-','/',str(newdate.date())))+'T22:00:00'
+ print (' Got Date: ', newdate2, newdate)
+ post_id, post_link = check_wordpress_post(title,newdate2,headers,local_outputs)
+ featured_photo_id = get_wordpress_featured_photo_id(post_id)
+ print(f" Featured photo ID: for {title} post {post_id} is: {featured_photo_id}")
+ if env.block_google_maps is not True:
+ try:
+ database_update_row(title,"wpurl",post_link,"forceall",local_outputs)
+ except AttributeError as error :
+ print ('Could not check to see post already exists',error)
+ if not post_id:
+ googleadress = r""+address+r""
+ post_data = {
+ "title": title,
+ # "content": address+'\n\n'+content+'\n'+rating+'\n\n' ,
+ "content": googleadress+'\n\n'+content+'\n'+rating ,
+ "status": "publish", # Set to 'draft' if you want to save as a draft
+ "date": newdate2,
+ "meta": {'visitdate':visitdate}
+ # "date": str(newdate)+'T22:00:00',
+ # "author":"joesteele"
+ }
+ try:
+ headers2 = headers
+ response = requests.post(env.wpAPOurl, json = post_data, headers=headers2,timeout=\
+ env.request_timeout)
+ if response.status_code != 201:
+ print ('Error: ',response, response.text)
+ else:
+ #new_post = True
+ post_id_json = response.json()
+ post_id = post_id_json.get('id')
+ print (' New post is has post_id = ',post_id)
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ #postneedsupdate = True
+ else:
+ print (' Post already existed: Post ID : ',post_id)
+ if not env.force_web_create:
+ return True
+ for pic in picchop:
+ if pic != '':
+ picslice2 = pic.split("/")[-1]
+ picslice = picslice2.split(".")
+ picname = picslice[0]
+ caption =title
+ description = title+"\n"+address
+ print (' Found Picture: ',picname)
+ file_id, link = check_wordpress_media(picname, headers)
+ # link = linknew['rendered']
+ if file_id is False:
+ print (' '+str(picname)+' was not already found in library, adding it')
+ # countreview = True
+ image = {
+ "file": open(pic, "rb"),
+ "post": post_id,
+ "caption": caption,
+ "description": description
+ }
+ try:
+ image_response = requests.post(env.wpAPI + "/media", headers=headers, \
+ files=image,timeout=env.request_timeout)
+ except AttributeError as error:
+ print(" An error uploading picture ' + picname+ ' occurred:", \
+ type(error).__name__)
+ if image_response.status_code != 201 :
+ print (' Error:Image ',picname,' wasnot successfully uploaded.response:'\
+ ,image_response)
+ else:
+ pic_dic=image_response.json()
+ file_id= pic_dic.get('id')
+ link = pic_dic.get('guid').get("rendered")
+ print (' ',picname,' was successfully uploaded to website with ID: ',\
+ file_id, link)
+ try:
+ links_dict = {'file_id' : file_id , 'link' : link}
+ linkslist.append(links_dict)
+ except AttributeError as error:
+ print(" An error adding to dictionary " , file_id , link , " occurred:",\
+ type(error).__name__) # An error occurred:
+ else:
+ print (' Photo ',picname,' was already in library and added to post with ID:',\
+ file_id,' : ',link)
+ try:
+ image_response = requests.post(env.wpAPI + "/media/" + str(file_id),\
+ headers=headers, data={"post" : post_id},timeout=env.request_timeout)
+ except AttributeError as error:
+ print (' Error- Image ',picname,' was not attached to post. response: ',\
+ image_response+' '+type(error).__name__)
+ try:
+ post_response = requests.post(env.wpAPI + "/posts/" + str(post_id),\
+ headers=headers,timeout=env.request_timeout)
+ if link in post_response.text:
+ print (' Image link for ', picname, 'already in content of post: '\
+ ,post_id, post_response.text, link)
+ else:
+ linkslist.append({'file_id' : file_id , 'link' : link})
+ # countreview = True
+ except AttributeError as error:
+ print(" An error loading the metadata from the post "+post_response.title+\
+ ' occurred: '+type(error).__name__)
+ #ratinghtml = post_response.text
+ first_mp4 = True
+ first_pic = True
+ fmedia = {}
+ contentpics = ""
+ for piclink in linkslist:
+ if piclink != '':
+ #for loop in linkslist:
+ print (' Adding ', piclink['link'], ' to posting')
+ try:
+ ext = piclink['link'].split( '.')[-1]
+ if ext == 'mp4':
+ if first_mp4:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
+ r'" autoplay="true"]'
+ first_mp4 = False
+ else:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
+ #[evp_embed_video url="http://example.com/wp-content/uploads/videos/vid1.mp4" autoplay="true"]
+ else:
+ contentpics+='\n '+r''
+ if first_pic:
+ fmedia = piclink['file_id']
+ first_pic = False
+ # fmedia.append = piclink{'file_id' }
+ # contentpics += '\n '+r'
' +'\n\n'
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ return False
+ try:
+# print ('featured_media = ',linkslist[0]['file_id'])
+ # if linkslist[0]['file_id']:
+ # print ('featuredmedia2 = ',linkslist[0]['file_id'])
+ if fmedia:
+ print ('Featured Media: ',fmedia)
+ else:
+ if linkslist:
+ fmedia = linkslist[0]['file_id']
+# print ('featured_media2 = ',file_id)
+ business_url_list = local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ title).all()
+ business_url = ""+\
+ title+""
+ # wpurllist = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ # wpurl = wpurllist[0].wpurl
+# if business_url or business_url is False:
+ status_message = str(title) + ':\nBusiness website: '+ business_url
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+'\n'+\
+ rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print (' response_piclinks: ',response_piclinks)
+ if fmedia and fmedia != 0 and featured_photo_id and featured_photo_id !=0:
+ print (" Featured Media: "+str(featured_photo_id)+" "+str(fmedia)+" looks OK")
+ else:
+ print (" fmedia is still empty and need to populate")
+ if fmedia:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+
+ '\n'+rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":\
+ title},headers=headers,timeout=env.request_timeout)
+ print (' Results of new results ID value : '+str(\
+ get_wordpress_featured_photo_id(post_id)))
+ else:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress\
+ +'\n'+rating+contentpics,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print ('Results of new results ID with no picture value : '+str\
+ (get_wordpress_featured_photo_id(post_id)))
+ except AttributeError as error:
+ print(" An error writing images to the post " + post_response.title + ' occurred:',\
+ type(error).__name__) # An error occurred')
+ return False
+ return True
+
+##################################################################################################
+
+def build_picslist(picchop, piclink, file_id):
+ """
+ Builds a list of pictures for posting based on the provided picture links.
+
+ Args:
+ picchop (list): List of picture links to process.
+ piclink (str): The picture link to be added to the list.
+
+ Returns:
+ str: A string containing the formatted list of pictures for posting.
+ Raises:
+ AttributeError: If an error occurs during picture processing.
+ """
+
+ for piclink in picchop:
+ if piclink != '':
+ print (' Adding ', piclink['link'], ' to posting')
+ try:
+ ext = piclink['link'].split( '.')[-1]
+ if ext == 'mp4':
+ if first_mp4:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
+ r'" autoplay="true"]'
+ first_mp4 = False
+ else:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
+ else:
+ contentpics+='\n '+r''
+ if first_pic:
+ fmedia = piclink['file_id']
+ first_pic = False
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ return False
+ return contentpics
+
+##################################################################################################
+
+def get_wordpress_post_date_string(date_string, date):
+ """
+ Parses a date string and returns two formatted date strings.
+
+ Args:
+ date_string (str): The input date string to be parsed.
+ date (str): The keyword indicating the date offset.
+
+ Returns:
+ tuple: A tuple containing two formatted date strings.
+ Raises:
+ AttributeError: If an error occurs during date parsing.
+ """
+
+
+ if "a day" in date_string:
+ date = dt.timedelta(days=-1)
+ newdate = datetime.today() - date
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "day" in date_string:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(days=tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a week" in date_string:
+ newdate = datetime.today() - relativedelta(weeks= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "week" in date_string:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(weeks= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a month" in date_string:
+ newdate = datetime.today() - relativedelta(months = 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "month" in date_string:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(months = tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a year" in date_string:
+ newdate = datetime.today() - relativedelta(years= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "year" in date_string:
+ try:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(years= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+ else:
+ #specifify the formatting of the date_string.
+ formatting = '%Y-%b-%d'
+ month = date[:3]
+ year = date[3:]
+ day = '01'
+ date_string = year+'-'+ month+'-'+day
+ try:
+ newdate = dt.datetime.strptime(date_string, formatting)\
+ .date()
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+ newdate = str(newdate)
+ #formatting = '%b/%Y/%d' #specifify the formatting of the date_string.
+ #newdate2 = dt.datetime.strptime(str(newdate), formatting).date()
+ dateparts = (str(newdate)).split("-")
+ dateparts2 = dateparts[2].split(" ")
+ newdate2 = dateparts[0]+'-'+dateparts[1]+'-'+dateparts2[0]+'T22:00:00'
+ print (' Got Date: ', newdate2, newdate)
+ return (newdate,newdate2,visitdate)
+
+##################################################################################################
+
+def create_wordpress_post(newdate2, picchop, title, address, headers, post_id, linkslist,\
+ local_outputs, content, googleadress, rating, featured_photo_id):
+ """
+ Creates a WordPress post with pictures and content.
+
+ Args:
+ newdate2: The date of the post.
+ picchop (list): List of picture links to process.
+ title: The title of the post.
+ address: The address associated with the post.
+ headers: The headers for the HTTP request.
+ post_id: The ID of the post.
+ linkslist: List of links to pictures.
+ local_outputs: Local outputs for the post.
+ content: The content of the post.
+ googleadress: The Google address for the post.
+ rating: The rating of the post.
+ featured_photo_id: The ID of the featured photo.
+
+ Returns:
+ bool: True if the post creation is successful, False otherwise.
+ Raises:
+ AttributeError: If an error occurs during post creation or processing.
+ """
+
+ if not post_id:
+ addresshtml = re.sub(" ", ".",address)
+ googleadress = r""+address+r""
+ post_data = {
+ "title": title,
+ "content": googleadress+'\n\n'+content+'\n'+rating ,
+ "status": "publish", # Set to 'draft' if you want to save as a draft
+ "date": newdate2
+ }
+ try:
+ headers2 = headers
+ response = requests.post(env.wpAPOurl, json = post_data, headers=headers2,timeout=\
+ env.request_timeout)
+ if response.status_code != 201:
+ print ('Error: ',response, response.text)
+ else:
+ post_id_json = response.json()
+ post_id = post_id_json.get('id')
+ print (' New post has post_id = ',post_id)
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ else:
+ print (' Post already existed: Post ID : ',post_id)
+ for pic in picchop:
+ if pic != '':
+ picslice2 = pic.split("/")[-1]
+ picslice = picslice2.split(".")
+ picname = picslice[0]
+ caption =title
+ description = title+"\n"+address
+ print (' Found Picture: ',picname)
+ file_id, link = check_wordpress_media(picname, headers)
+ if file_id is False:
+ print(f' {str(picname)} was not already found in library, adding it')
+ image = {
+ "file": open(pic, "rb"),
+ "post": post_id,
+ "caption": caption,
+ "description": description
+ }
+ try:
+ image_response = requests.post(env.wpAPI + "/media", headers=headers, \
+ files=image,timeout=env.request_timeout)
+ except AttributeError as error:
+ print(f" An error uploading picture {picname} occurred:", \
+ type(error).__name__)
+ if image_response.status_code != 201 :
+ print (f' Error:Image {picname} wasnot successfully uploaded. response:'\
+ ,image_response)
+ else:
+ pic_dic=image_response.json()
+ file_id= pic_dic.get('id')
+ link = pic_dic.get('guid').get("rendered")
+ print (f' {picname} was successfully uploaded to website with ID: ',\
+ file_id, link)
+ try:
+ links_dict = {'file_id' : file_id , 'link' : link}
+ linkslist.append(links_dict)
+ except AttributeError as error:
+ print(f" An error adding to dictionary {file_id} {link} occurred:",\
+ type(error).__name__) # An error occurred:
+ else:
+ print (f' Photo {picname} was already in library and added to post with ID: \
+ {file_id} : {link}')
+ try:
+ image_response = requests.post(env.wpAPI + "/media/" + str(file_id),\
+ headers=headers, data={"post" : post_id},timeout=env.request_timeout)
+ except AttributeError as error:
+ print (' Error- Image ',picname,' was not attached to post. response: ',\
+ image_response+' '+type(error).__name__)
+ try:
+ post_response = requests.post(env.wpAPI + "/posts/" + str(post_id),\
+ headers=headers,timeout=env.request_timeout)
+ if link in post_response.text:
+ print (' Image link for ', picname, 'already in content of post: '\
+ ,post_id, post_response.text, link)
+ else:
+ linkslist.append({'file_id' : file_id , 'link' : link})
+ except AttributeError as error:
+ print(" An error loading the metadata from the post "+post_response.title+\
+ ' occurred: '+type(error).__name__)
+ first_mp4 = True
+ first_pic = True
+ fmedia = {}
+ contentpics = ""
+ for piclink in linkslist:
+ if piclink != '':
+ print (' Adding ', piclink['link'], ' to posting')
+ try:
+ ext = piclink['link'].split( '.')[-1]
+ if ext == 'mp4':
+ if first_mp4:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
+ r'" autoplay="true"]'
+ first_mp4 = False
+ else:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
+ else:
+ contentpics+='\n '+r''
+ if first_pic:
+ fmedia = piclink['file_id']
+ first_pic = False
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ return False
+ try:
+ if fmedia:
+ print ('Featured Media: ',fmedia)
+ else:
+ if linkslist:
+ fmedia = linkslist[0]['file_id']
+ business_url_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
+ .all()
+ business_url = f"{title}"
+ status_message = f'{str(title)}: Business website: {business_url}'
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+'\n'+\
+ rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print (' ',response_piclinks)
+ if fmedia and fmedia != 0 and featured_photo_id and featured_photo_id !=0:
+ print (" Featured Media: "+str(featured_photo_id)+" "+str(fmedia)+" looks OK")
+ else:
+ print (" fmedia is still empty and need to populate")
+ if fmedia:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress\
+ +'\n'+rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":\
+ title},headers=headers,timeout=env.request_timeout)
+ print (' Results of new results ID value : '+\
+ str(get_wordpress_featured_photo_id(post_id)))
+ else:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+\
+ googleadress+'\n'+rating+contentpics,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print ('Results of new results ID with no picture value : '+\
+ str(get_wordpress_featured_photo_id(post_id)))
+ except AttributeError as error:
+ print(" An error writing images to the post " + post_response.title + ' occurred:',\
+ type(error).__name__) # An error occurred')
+ return False
+ return True
+
+##################################################################################################
+
+def post_to_wordpress2(title,content,headers,date,rating,address,picslist,local_outputs):
+ """
+ Post to WordPress.
+
+ This function posts content to a WordPress site using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers for the request.
+ date (str): The date of the post.
+ rating (str): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ local_outputs: Outputs for the post.
+
+ Returns:
+ None
+"""
+ linkslist = ()
+ addresshtml = re.sub(" ", ".",address)
+ googleadress = r""+str(address)+r""
+ picchop = picslist[1:-1].replace(",","").replace("'","").split(" ")
+ print (' Figuring out date of Post : ',title)
+ #specifify the formatting of the date_string.
+ # formatting = '%b/%Y/%d'
+ date_string = date
+ newdate,newdate2,visitdate = get_wordpress_post_date_string(date_string,date)
+ post_id, post_link = check_wordpress_post(title,newdate2,headers,local_outputs)
+ if picslist and picslist != '':
+ content_pics = build_picslist(picchop,picslist,post_id) #file_id
+ featured_photo_id = get_wordpress_featured_photo_id(post_id)
+ print(f" Featured photo ID: for {title} post {post_id} is: {featured_photo_id}")
+ if env.block_google_maps is not True or env.forcegoogleupdate is True:
+ try:
+ database_update_row(title,"wpurl",post_link,"forceall",local_outputs)
+ except AttributeError as error :
+ print (f' Error: {error}')
+ else:
+
+ if post_id:
+ print (' Post already existed: Post ID : ',post_id)
+ print (' Found post for : '+title)
+ if env.force_web_create:
+ create_wordpress_post(newdate2,picchop,title,address,headers,post_id,linkslist,\
+ local_outputs,content,googleadress,rating,featured_photo_id)
+ #update_wordpress()
+ else:
+ print (' Found existing post but skipping updating post')
+ else:
+ create_wordpress_post(newdate2,picchop,title,address,headers,post_id,linkslist,\
+ local_outputs,content,googleadress,rating,featured_photo_id)
+ print (' Creating wordpress post from scratch for: '+title)
+ return True
+
+##################################################################################################
+
+def process_reviews2(outputs):
+ """
+ Processes reviews data, updates social media platforms, and writes data to files.
+
+ Args:
+ outputs: Data outputs containing reviews and social media information.
+
+ Returns:
+ None
+ """
+
+ # Process
+ webcount = xtwittercount = instagramcount = facebookcount = tiktokcount = 0
+# webcount=xtwittercount=instagramcount=yelpcount=threadscount=facebookcount=tiktokcount = 0
+ if env.datasource == 'db':
+ cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
+ 'address','dictPostComplete']
+ rows_orig = list(outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
+ ttt = list(outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
+ ows_orig = list(outputs['data'])
+ rows_orig2 = list(outputs['xlsdf'].values)
+ rows3 = outputs['data'].iter_rows(min_row=1, max_row=outputs['data'])
+ rows4 = pd.DataFrame(outputs['xlsdf'])
+ rows5 = pd.DataFrame(outputs['posts'])
+ rows6 = pd.DataFrame(outputs['data'])
+# df2 = pd.DataFrame(outputs['xlsdf'].values, columns=cols2).iter_rows(min_row=1, max_row=outputs\
+# ['data'].max_row)
+# df3 = pd.DataFrame(outputs['xlsdf'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
+# rows = [({0:p.id},{1:p.name}, { 2:p.comment}, {3: p.rating}, {4:p.picsURL},\
+# {5:p.picsLocalpath},{6:p.source},{7:p.date},{8:p.address},{9:p.dictPostComplete})\
+# for p in rows_orig]
+ # rows = list((outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row)))
+ rows = outputs['posts']
+ else:
+ rows_orig = outputs['posts']
+ rows = rows_orig
+ if env.google:
+ print('Configuration says to update google Reviews prior to processing them')
+ options = build_google_chrome_options(
+ headless=not env.showchrome,
+ log_level=3,
+ ignore_certificate_errors_spki_list=True,
+ remote_debugging_pipe=True,
+ )
+ # Setting the driver path and requesting a page
+ caps = webdriver.DesiredCapabilities.CHROME.copy()
+ caps['acceptInsecureCerts'] = True
+ caps['acceptSslCerts'] = True
+ options.set_capability('cloud:options', caps)
+ #driver = webdriver.Chrome(desired_capabilities=caps)
+ if is_docker():
+ driver = webdriver.Remote("http://192.168.10.9:4444/wd/hub", options=options)
+ print ("IN A DOCKER CONTAINER, USING REMOTE CHROME")
+ else:
+ driver = webdriver.Chrome(options=options) # Firefox(options=options)
+ # Changing the property of the navigator value for webdriver to undefined
+ set_stealth_driver(driver)
+ driver.get(env.URL)
+ time.sleep(5)
+ google_scroll(counter_google(driver), driver)
+ webdata = get_google_data(driver,outputs)
+ if env.datasource == 'db':
+ write_to_database(webdata, outputs)
+ else:
+ write_to_xlsx2(webdata, outputs)
+ driver.close()
+ # outputs['data'].save(xls)
+ print('Done getting google reviews and writing them to xls file !')
+ else:
+ print ('Configuration says to skip creation of new reviews from google for this run')
+ print('Processing Reviews')
+ for processrow in rows:
+ if processrow.name != "name": # Skip header line of xls sheet
+ outputs['postssession'].query(Posts).filter(Posts.name == processrow.name).\
+ update({"google" : 1})
+ print ("Processing : ",processrow.name)
+ writtento = ast.literal_eval(processrow.dictPostComplete)
+ # Check to see if the website has already been written to according to the xls sheet,\
+ # if it has not... then process
+ if (writtento["web"] == 0 or writtento["instagram"]==0 or writtento["facebook"]==0 or\
+ writtento["xtwitter"]==0 or writtento["yelp"]==0 or writtento["tiktok"]==0 or \
+ writtento["threads"]==0 ) and (check_is_port_open(env.wpAPI)) and (env.web \
+ or env.instagram or env.yelp or env.xtwitter or env.tiktok or env.facebook or \
+ env.threads or env.google)and (processrow.comment is not None) :
+ if (env.web and processrow.web is False) or env.force_web_create is True:
+ #if writtento["web"] == 0 :
+ try:
+ #date_string = date
+ #newdate,newdate2,visitdate = get_wordpress_post_date_string(date_string,date)
+ post_id, post_link = get_wordpress_post_id_and_link(processrow.name,\
+ outputs['web'] )
+# post_id, post_link = check_wordpress_post(processrow.name,processrow.date,outputs['web'],outputs)
+ if env.forcegoogleupdate is True and env.block_google_maps is not True:
+ if post_link:
+ database_update_row(processrow.name,"wpurl",post_link,"forceall"\
+ ,outputs)
+ else:
+ print (' Error getting wordpress links to update databse')
+ except AttributeError as error :
+ print ('Could not check to see post already exists',error)
+ webcount=process_socials("web",processrow,outputs['web'],"post_to_wordpress",\
+ webcount, outputs)
+ if env.instagram and processrow.instagram is False:
+ instagramcount = process_socials("instagram",processrow,outputs['web'],\
+ "post_to_instagram2",instagramcount, outputs)
+ if env.facebook and processrow.facebook is False :
+ facebookcount = process_socials("facebook",processrow,outputs['web'],\
+ "post_facebook3",facebookcount, outputs)
+ if env.xtwitter and processrow.xtwitter is False:
+ xtwittercount = process_socials("xtwitter",processrow,outputs['web'],\
+ "post_to_x2",xtwittercount, outputs)
+ if env.tiktok and processrow.tiktok is False:
+ tiktokcount = process_socials("tiktok",processrow,outputs['web'],\
+ "post_to_tiktok",tiktokcount, outputs)
+ return
+
+##################################################################################################
+
+def process_socials(social_name,social_post,headers,sub_process,social_count, local_outputs):
+ """Summary:
+ Function to process social media posts.
+
+ Explanation:
+ This function processes social media posts based on the provided parameters.
+
+ Args:
+ - social_name: The name of the social media platform.
+ - social_post: The post content for the social media platform.
+ - sub_process: The sub-process for posting.
+ - social_count: The count of social media posts.
+ - local_outputs: Dictionary containing outputs from the process.
+
+ Returns:
+ Count of the social that was selected
+ """
+ post_handler_map = {
+ "web": post_to_wordpress,
+ "instagram": post_to_instagram2,
+ "facebook": post_facebook3,
+ "xtwitter": post_to_x2,
+ "tiktok": post_to_tiktok,
+ }
+ writtento = ast.literal_eval(social_post.dictPostComplete)
+ post_record = local_outputs['postssession'].query(Posts).filter(
+ Posts.name == social_post.name
+ ).first()
+ social_column = getattr(Posts, social_name)
+ social_already_written = local_outputs['postssession'].query(Posts).filter(
+ Posts.name == social_post.name,
+ social_column.is_(True)
+ ).first()
+ if social_already_written is None and ((post_record is not None and post_record.wpurl is not
+ None)or social_name == 'web'):
+ if social_count < env.postsperrun or (social_name == 'web' and env.force_web_create is \
+ True):
+ try:
+ print(' Starting to generate ',social_name,' post')
+ new_social_post = post_handler_map[sub_process](social_post.name, social_post.comment,\
+ headers, social_post.date, social_post.rating, social_post.address,\
+ social_post.picsLocalpath,local_outputs )
+ try:
+ print (' Start generating content to post to : ',social_post.name)
+ writtento[social_name] = 1
+ social_post.dictPostComplete = str(writtento)
+ except AttributeError as error:
+ print(" An error occurred setting value to go into Excel file:", type(error)\
+ .__name__)
+ print (' Success Posting to xtwitter: '+social_post.name)
+ if new_social_post:
+ social_count +=1
+ try:
+ print(' write to xls for :',social_name)
+ local_outputs['datawb'].save(env.xls)
+ print(' Successfully wrote to xls for social - ',social_name)
+ except AttributeError as error:
+ print(" An error occurred writing Excel file:", type(error).__name__)
+ try:
+ print(' write to DB for Social - ',social_name)
+ local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ social_post.name).update({social_name : True})
+ local_outputs['postssession'].commit()
+ print(' Successfully wrote to database')
+ except AttributeError as error:
+ print(" An error occurred writing database", type(error).__name__)
+ except AttributeError as error:
+ print(' Error writing social - ',social_name,' post : ',error,social_post.name,\
+ social_post.comment, local_outputs,social_post.date, social_post.rating,\
+ social_post.address, social_post.picsLocalpath, writtento[social_name],\
+ type(error).__name__ )
+ else:
+ print (' Exceeded the number of social - ',social_name,' posts per run, skipping',\
+ social_post.name)
+ else:
+ print (' ',social_name,': Skipping posting for ',social_post.name,' previously written')
+ return social_count
+
+##################################################################################################
+
+if __name__ == "__main__":
+ print('starting ...')
+ preload()
+ print('making connections ...')
+ outputs = get_auth_connect()
+ process_reviews2(outputs)
+ print('Done!')
+
+##################################################################################################
+=======
+""" Script to download google maps reviews (that you create) and store them
+and then on a cron'd basis post them to social media connectors """
+import time
+import os
+from pathlib import Path
+import pathlib
+import re
+from datetime import datetime
+import ast
+import base64
+import datetime as dt
+from urllib.request import urlretrieve
+import inspect
+import requests
+#import json
+import jsonpickle
+import urllib3
+import pandas as pd
+from dateutil.relativedelta import relativedelta
+from openpyxl import load_workbook
+import instagrapi
+from moviepy.editor import VideoFileClip, concatenate_videoclips
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.common.exceptions import NoSuchElementException
+import tweepy
+#import asyncio
+#import aiohttp
+import sqlalchemy
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import null, update
+import googlemaps
+import env
+#import inspect
+Base = declarative_base()
+
+##################################################################################################
+
+class Users(Base):
+ """Class representing a user config"""
+ __tablename__ = 'userConfig'
+ id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
+ user = sqlalchemy.Column(sqlalchemy.String(length=11, collation="utf8"))
+ instagram = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ web = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ facebook = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ tiktok = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ xtwitter = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ threads = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ yelp = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ google = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ data = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ postsperrun = sqlalchemy.Column(sqlalchemy.String(length=11, collation="utf8"))
+ needreversed = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ wpAPI = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ platform = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ LinuxDriverLocation = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ WindowsDriverLocation = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ xls = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ googleurl = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ instagramuser = sqlalchemy.Column(sqlalchemy.String(length=32, collation="utf8"))
+ instagrampass = sqlalchemy.Column(sqlalchemy.String(length=32, collation="utf8"))
+ #active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+
+##################################################################################################
+
+class Posts(Base):
+ """Class representing the attributes of a post"""
+ __tablename__ = 'posts'
+ id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
+ name = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ comment = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ rating = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ picsURL = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ picsLocalpath = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ source = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+ date = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+ address = sqlalchemy.Column(sqlalchemy.String(length=256, collation="utf8"))
+ dictPostComplete = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ #googleurl = sqlalchemy.Column(sqlalchemy.String(length=128, collation="utf8"))
+ wpurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ businessurl = sqlalchemy.Column(sqlalchemy.String(length=2048, collation="utf8"))
+ longitude = sqlalchemy.Column(sqlalchemy.Float())
+ latitude = sqlalchemy.Column(sqlalchemy.Float())
+ google = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ facebook = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ instagram = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ xtwitter = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ threads = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ yelp = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ web = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ tiktok = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
+ #active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
+ place_id = sqlalchemy.Column(sqlalchemy.String(length=126, collation="utf8"))
+ review_id = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ googledetails = sqlalchemy.Column(sqlalchemy.String(length=4096, collation="utf8"))
+ #businessurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ pluscode = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+ googleurl = sqlalchemy.Column(sqlalchemy.String(length=512, collation="utf8"))
+ visitdate = sqlalchemy.Column(sqlalchemy.String(length=64, collation="utf8"))
+
+
+##################################################################################################
+
+def preload():
+ """
+ Removes a specific file if it exists.
+
+ Returns:
+ None
+ """
+
+ file=pathlib.Path("./config/joeteststeele_uuid_and_cookie.json")
+ if pathlib.Path.exists(file):
+ pathlib.Path.unlink(file)
+# today = datetime.today().strftime('%Y-%m-%d')
+ return
+
+##################################################################################################
+
+def clearlist(my_list):
+ """
+ Clears all elements in a list.
+
+ Args:
+ my_list (list): The list to be cleared.
+
+ Returns:
+ list: The input list with all elements cleared.
+ """
+
+ for listelement in my_list:
+ listelement.clear
+ return my_list
+
+##################################################################################################
+
+def get_auth_connect():
+ """Make all connections to socials and DB, etec.."""
+ connections = {}
+ if env.mariadb:
+ print('Connecting to MariaDB for configuration and storage')
+ #from sqlalchemy import create_engine
+ engine = sqlalchemy.create_engine("mysql+mysqldb://"+env.mariadbuser+":"+env.mariadbpass+
+ "@"+env.mariadbserver+"/"+env.mariadbdb+"?charset=utf8mb4", echo=False)
+ Session = sqlalchemy.orm.sessionmaker()
+ Session.configure(bind=engine)
+ session = Session()
+ usersession = session.query(Users).filter(Users.user=='joesteele')
+ dbuser = usersession[0]
+ #for userloop in usersession:
+ print("- " + dbuser.user + ' ' + dbuser.googleurl)
+ connections['user'] =dbuser
+ posts = session.query(Posts).all()
+ connections['posts'] = posts
+ connections['postssession'] = session
+ if env.data:
+ print(' loading XLS content data source ...')
+ if os.path.exists(env.xls):
+ wb = load_workbook(filename = env.xls)
+ xls_wb_df = pd.read_excel(env.xls)
+ elif os.path.exists('./GoogleScrape/'+ env.xls):
+ wb = load_workbook(filename = './GoogleScrape/'+ env.xls)
+ xls_wb_df = pd.read_excel('./GoogleScrape/'+ env.xls)
+ else:
+ input("Not able to find xls file Press any key to continue...")
+ ws = wb['Sheet1']
+ #xls_wb_df = pd.read_excel(xls)
+ connections |= {'xlsdf':xls_wb_df,'data':ws,'datawb':wb}
+# connections.update({'data':ws})
+# connections.update({'datawb':wb})
+
+ sheet = wb.active
+ c_row = sheet.max_row
+ c_column = sheet.max_column
+ #out_data=[]
+ #import inspect
+ #local_dict=Posts
+ column_list = []
+ my_list = []
+ my_list_data = []
+ #my_post = Posts
+ #my_dict = {}
+ for x in inspect.getmembers(Posts):
+ if not (x[0].startswith('_') or 'metadata' in x[0]):
+ column_list.append(x[0])
+ # solumn_list2[0][0]
+ #solumn_list2 = tuple(x for x in solumn_list2 if ('metadata' not in solumn_list2[0][0])\
+ # or(not solumn_list2[0][0].startswith('_')))
+# for a in range(1, c_row + 1):
+ for a in range(1, c_row + 1):
+ for b in range(2, c_column+1):
+ ob = sheet.cell(row=a, column=b)
+ my_list.append(ob.value)
+# my_post.getattr(Posts, column_list[b]) == ob.value #my_post.(eval(b,column_list))
+ #my_dict[b] = ob.value
+ my_list_data.append(str(my_list))
+ print (my_list)
+ my_list = []
+ #out_data.append(str(my_dict))
+ connections['xls_list'] = my_list_data
+# connections['xls_list'] = out_data
+ if env.instagram:
+ print(' Connecting to Instagram ...')
+ instasessionclient = instagrapi.Client()
+ instasessionclient.login(env.instagramuser, env.instagrampass)
+ connections['instagram'] = instasessionclient
+ if env.facebook:
+ print(' Connecting to facebook ...')
+ # page_id_1 = facebookpageID
+ # facebook_access_token = 'paste-your-page-access-token-here'
+ # image_url = 'https://graph.facebook.com/{}/photos'.formatting(page_id_1)
+ # image_location = 'http://image.careers-portal.co.za/f_output.jpg'
+ # img_payload = {
+ # 'message': msg,
+ # 'url': image_location,
+ # 'access_token': facebook_access_token
+ # }
+ # #Send the POST request
+ # r = requests.post(image_url, data=img_payload)
+ # print(r.text)
+ connections['facebook'] = posts
+ if env.yelp:
+ print(' Connecting to yelp ...')
+ if env.xtwitter:
+ print(' Connecting to xtwitter ...')
+ if env.threads:
+ print(' Connecting to threads ...')
+ threadssessionclient = instagrapi.Client()
+ threadssessionclient.login(env.instagramuser, env.instagrampass)
+ connections |= {'threads':threadssessionclient}
+ if env.web:
+ print(' Connecting to joeeatswhat.com ...')
+ data_string = f"{env.user}:{env.password}"
+ token = base64.b64encode(data_string.encode()).decode("utf-8")
+ connections['web'] = {"Authorization": f"Basic {token}"}
+ else:
+ connections['web'] = ""
+ if env.tiktok :
+ print(' Connecting to Instagram ...')
+ return connections
+
+##################################################################################################
+
+def get_twitter_conn_v1(api_key, api_secret, access_token, access_token_secret) -> tweepy.API:
+ """Get twitter conn 1.1"""
+ auth = tweepy.OAuth1UserHandler(api_key, api_secret)
+ auth.set_access_token(
+ access_token,
+ access_token_secret,
+ )
+ return tweepy.API(auth)
+
+##################################################################################################
+
+def get_twitter_conn_v2(api_key, api_secret, access_token, access_token_secret) -> tweepy.Client:
+ """Get twitter conn 2.0"""
+ return tweepy.Client(
+ consumer_key=api_key,
+ consumer_secret=api_secret,
+ access_token=access_token,
+ access_token_secret=access_token_secret,
+ )
+
+##################################################################################################
+
+def get_hastags(address, name, hashtype):
+ """
+ Generates hashtags based on the address, name, and type provided.
+
+ Args:
+ address (str): The address related to the content.
+ name (str): The name associated with the content.
+ hashtype (str): The type of hashtags to generate.
+
+ Returns:
+ str: The generated hashtags based on the input parameters.
+ """
+
+ name_no_spaces = re.sub( r'[^a-zA-Z]','',name)
+ addressdict = address.rsplit(r' ',3)
+ try:
+ zip_code = addressdict[3]
+ except:
+ zip_code = '34787'
+ try:
+ state = addressdict[2]
+ except:
+ state = 'Florida'
+ try:
+ city = re.sub( r'[^a-zA-Z]','',addressdict[1])
+ except:
+ city = 'WinterGarden'
+ if 'short' in hashtype:
+ defaulttags = '#'+name_no_spaces+' #foodie #food #joeeatswhat @timberjoe'
+ else:
+ defaulttags = "\n\n\n#"+name_no_spaces+\
+ " #foodie #music #food #travel #drinks #instagood #feedme #joeeatswhat @timberjoe"
+ citytag = f"#{city}"
+ statetag = f"#{state}"
+ ziptag = f"#{zip_code}"
+ if statetag in ['FL', 'fl','Fl']:
+ statetag += '#Florida'
+ if statetag == 'OR':
+ statetag += '#Oregon'
+ if statetag == 'MA':
+ statetag += '#Massachusetts'
+ return defaulttags+" "+citytag+" "+statetag+" "+ziptag+" "
+
+##################################################################################################
+
+# Grab a count of how far we need to scroll
+def counter_google(driver):
+ """
+ Counts the number of Google search results pages.
+
+ Args:
+ driver: The Selenium WebDriver instance.
+
+ Returns:
+ int: The total number of search result pages.
+ """
+
+ result = driver.find_element(By.CLASS_NAME,'Qha3nb').text
+ result = result.replace(',', '')
+ result = result.split(' ')
+ result = result[0].split('\n')
+ return int(result[0]) // 10 + 1
+
+##################################################################################################
+
+def make_montage_video_from_google(inphotos,cleanname):
+ """
+ Creates a montage video from a list of input photos.
+
+ Args:
+ inphotos (list): List of paths to input photo files.
+
+ Returns:
+ tuple: A tuple containing the path to the output video file and a boolean indicating succe
+ """
+
+# Load the photos from the folder
+# Set the duration of each photo to 2 seconds
+ if not inphotos:
+ return False, False
+ directory = inphotos[0].rsplit(r'/', 1)
+ folder = directory[0]
+ output = folder+"/"+cleanname+"-montage.mp4"
+ if not os.path.exists(output) and len(inphotos) >0:
+ video = VideoFileClip(inphotos[0])
+ for photo in inphotos :
+ #clip = VideoFileClip("myHolidays.mp4").subclip(50,60)
+ clip = VideoFileClip(photo)
+ # Concatenate the photos into a clip
+ if ".jpg" in photo:
+ clip.duration = 2
+ try:
+ video = concatenate_videoclips([video, clip], method="compose")
+ except AttributeError as error:
+ print(" An error occurred :", type(error).__name__) # An error occurred:
+ # Load the audio file
+ # audio = AudioFileClip("audio.mp3")
+ # Set the audio as the soundtrack of the montage
+ # montage = montage.set_audio(audio)
+ # Write the final montage to a file
+ outputvideo = video.write_videofile(output, fps=24)
+ else:
+ outputvideo = False
+ return outputvideo, output
+
+##################################################################################################
+
+def is_docker():
+ """
+ Checks if the code is running in a Docker container.
+
+ Returns:
+ bool: True if running in a Docker container, False otherwise.
+ """
+ cgroup = Path('/proc/self/cgroup')
+ #print (cgroup.read_text())
+ return Path('/.dockerenv').is_file() or cgroup.is_file() and 'docker' in \
+ cgroup.read_text(encoding="utf-8")
+
+##################################################################################################
+
+def post_facebook_video(group_id, video_path, auth_token, title, content, date, rating, address):
+ """
+ Posts a video to a Facebook group with specified details.
+
+ Args:
+ group_id (str): The ID of the Facebook group.
+ video_path (list): List of paths to the video files to be uploaded.
+ auth_token (str): The authentication token for posting to Facebook.
+ title (str): The title of the video.
+ content (str): Additional content to be included in the post.
+ date (str): The date of the post.
+ rating (str): The rating associated with the post.
+ address (str): The address related to the post.
+
+ Returns:
+ dict or bool: The response JSON if successful, False if an error occurs.
+ """
+
+ url = f"https://graph-video.facebook.com/{group_id}/videos?access_token=" + auth_token
+ addresshtml = re.sub(" ", ".",address)
+ files = {eachfile: open(eachfile, 'rb') for eachfile in video_path}
+ data = { "title":title,"description" : title + "\n"+ address+"\nGoogle map to destination: "
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n"+ content +
+ "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title, 'long')+
+ "\n\nhttps://www.joeeatswhat.com"+"\n\n","published" : True,
+ "alt_text" : title
+ }
+ try:
+ r = requests.post(url, files=files, data=data,timeout=env.request_timeout).json()
+ except AttributeError as error:
+ print(" An error getting date occurred:", error) # An error occurred:
+ r = False
+ time.sleep(env.facebooksleep)
+ return r
+
+##################################################################################################
+
+##################################################################################################
+
+def post_threads_video(group_id, video_path, auth_token, title, content, date, rating, address):
+ """
+ Posts a video to a Facebook group with specified details.
+
+ Args:
+ group_id (str): The ID of the Facebook group.
+ video_path (list): List of paths to the video files to be uploaded.
+ auth_token (str): The authentication token for posting to Facebook.
+ title (str): The title of the video.
+ content (str): Additional content to be included in the post.
+ date (str): The date of the post.
+ rating (str): The rating associated with the post.
+ address (str): The address related to the post.
+
+ Returns:
+ dict or bool: The response JSON if successful, False if an error occurs.
+ """
+ # Get url from wordpress - right now threads can only get video and pics from and external URL
+
+ connect_url = f"https://graph.threads.net/v1.0/{env.threads_page_id}/threads?media_type=VIDEO&video_url=https://www.example.com/images/bronz-fonz.jpg&text=#BronzFonz&access_token=" + auth_token
+ addresshtml = re.sub(" ", ".",address)
+ files = {eachfile: open(eachfile, 'rb') for eachfile in video_path}
+ data = { "title":title,"description" : title + "\n"+ address+"\nGoogle map to destination: "
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n"+ content +
+ "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title, 'long')+
+ "\n\nhttps://www.joeeatswhat.com"+"\n\n","published" : True,
+ "alt_text" : title
+ }
+ try:
+ r = requests.post(connect_url, files=files, data=data,timeout=env.request_timeout).json()
+ except AttributeError as error:
+ print(" An error getting date occurred:", error) # An error occurred:
+ r = False
+ time.sleep(env.facebooksleep)
+ return r
+
+##################################################################################################
+
+def get_google_data(driver, local_outputs):
+ """
+ Retrieves data from Google Maps including name, address, and review details.
+
+ Args:
+ driver: The Selenium WebDriver instance.
+ local_outputs: Output information.
+
+ Returns:
+ list: A list of data extracted from Google Maps.
+ """
+ print(' get google data...', end ="")
+ # Click on more botton on each text reviews
+ more_elemets = driver.find_elements(By.CSS_SELECTOR, '.w8nwRe.kyuRq')
+ for list_more_element in more_elemets:
+ print (".", end ="")
+ list_more_element.click()
+ print ("")
+ # Find Pictures that have the expansion indicator to see the rest of the pictures under
+ # them and click it to expose them all
+ more_pics = driver.find_elements(By.CLASS_NAME, 'Tya61d')
+ print(' Found extra pics',end = "")
+ for list_more_pics in more_pics:
+ if 'showMorePhotos' in list_more_pics.get_attribute("jsaction") :
+ print('.', end = '')
+ list_more_pics.click()
+ print ('.')
+ elements = driver.find_elements(By.CLASS_NAME, 'jftiEf')
+ lst_data = []
+ for data in elements:
+ name = data.find_element(By.CSS_SELECTOR, 'div.d4r55.YJxk2d').text
+ try:
+ address = data.find_element(By.CSS_SELECTOR, 'div.RfnDt.xJVozb').text
+ except NoSuchElementException :
+ address = 'Unknonwn'
+ print ('Name of location: ',name, ' Address:',address)
+ try:
+ visitdate = data.find_element(By.CSS_SELECTOR, 'span.rsqaWe').text
+ except NoSuchElementException :
+ visitdate = "Unknown"
+ print(' Visited: ',visitdate)
+ if re.match('^[a-zA-Z]+', visitdate) is None and re.match('^[a-zA-Z]+', visitdate) is not None:
+ #if visitdate[:1].isalpha:
+ newdate,newdate2,visitdate = get_wordpress_post_date_string(visitdate, str(datetime.now()))
+ print(' Visited altered to : ',visitdate)
+ try:
+ text = data.find_element(By.CSS_SELECTOR, 'div.MyEned').text
+ except NoSuchElementException :
+ text = ''
+ try:
+ score = data.find_element(By.CSS_SELECTOR, 'span.kvMYJc').get_attribute("aria-label")
+ #find_element(By.CSS_SELECTOR,'aria-label').text #) ##QA0Szd > div > div > div.w6VYqd >
+ # div:nth-child(2) > div > div.e07Vkf.kA9KIf > div > div > div.m6QErb.DxyBCb.kA9KIf.dS8AEf
+ # > div.m6QErb > div:nth-child(3) > div:nth-child(2) > div > div:nth-child(4) > div.DU9Pgb
+ # > span.kvMYJc
+ except NoSuchElementException as error:
+ score = "Unknown"
+ print ('Error: ',error)
+ # Grab more info from google maps entry on this particular review
+ if (len(local_outputs['postssession'].query(Posts).filter(Posts.name == name,Posts.google\
+ is not True).all()) == 0 or env.forcegoogleupdate) and env.block_google_maps is not\
+ True:
+ gmaps = googlemaps.Client(env.googleapipass)
+ place_ids = gmaps.find_place(name+address, input_type = 'textquery', fields='')
+ if len(place_ids['candidates']) == 1 :
+ place_id = place_ids['candidates'][0]['place_id']
+ details = gmaps.place(place_id)
+ # Get place details
+ try:
+ businessurl = details['result']['website']
+ latitude = details['result']['geometry']['location']['lat']
+ longitude = details['result']['geometry']['location']['lng']
+ pluscode = details['result']['plus_code']['compound_code']
+ googleurl = details['result']['url']
+ database_update_row(name,"businessurl",businessurl,"onlyempty",local_outputs)
+ database_update_row(name,"latitude",latitude,"onlyempty",local_outputs)
+ database_update_row(name,"longitude",longitude,"onlyempty",local_outputs)
+ database_update_row(name,"pluscode",pluscode,"onlyempty",local_outputs)
+ database_update_row(name,"googleurl",googleurl,"onlyempty",local_outputs)
+ database_update_row(name,"place_id",place_id,"onlyempty",local_outputs)
+ database_update_row(name,"googledetails",details,"onlyempty",local_outputs)
+ database_update_row(name,"google",True,"onlyempty",local_outputs)
+ except KeyError as error:
+ print('Error writing business details from google maps : ',error)
+ else:
+ if env.forcegoogleupdate:
+ database_update_row(name,"google",True,"forceall",local_outputs)
+ if len(local_outputs['postssession'].query(Posts).filter(Posts.name == name,\
+ Posts.google is not True).all()) > 0:
+ print (' Post was already in database, skipping update unless overriden')
+ # else:
+ # database_update_row(name,"google",True,"forceall",local_outputs)
+ pics= []
+ pics2 = []
+ more_specific_pics = []
+ more_specific_pics = data.find_elements(By.CLASS_NAME, 'Tya61d')
+ if len(more_specific_pics) > 0:
+ # check to see if folder for pictures and videos already exists, if not, create it
+ cleanname = re.sub( r'[^a-zA-Z0-9]','', name)
+ if not os.path.exists('./Output/Pics/'+cleanname):
+ os.makedirs('./Output/Pics/'+cleanname)
+ # Walk through all the pictures and videos for a given review
+ lmpics = ''
+ for lmpics in more_specific_pics:
+ # Grab URL from style definiton (long multivalue string), and remove the -p-k
+ # so that it is full size
+ urlmedia = re.sub(r'=\S*-p-k-no', '=-no', (re.findall(r"['\"](.*?)['\"]",
+ lmpics.get_attribute("style")))[0])
+ print (' Pic URL : ',urlmedia)
+ pics.append(urlmedia)
+ # Grab the name of the file and remove all spaces and special charecters to name the
+ # folder
+ filename = re.sub( r'[^a-zA-Z0-9]','', str(lmpics.get_attribute("aria-label")))
+ if lmpics == more_specific_pics[0]:
+ lmpics.click()
+ time.sleep(2)
+ #iframe = driver.find_element(By.TAG_NAME, "iframe")
+ tempdate = str((driver.find_element(By.CLASS_NAME,'mqX5ad')).text).rsplit("-",1)
+ visitdate = re.sub( r'[^a-zA-Z0-9]','',tempdate[1])
+ #print (' Visited: ',visitdate)
+ # Check to see if it has a sub div, which represents the label with the video length
+ # displayed, this will be done
+ # because videos are represented by pictures in the main dialogue, so we need
+ # to click through and grab the video URL
+ if lmpics.find_elements(By.CSS_SELECTOR,'div.fontLabelMedium.e5A3N') :
+ ext='.mp4'
+ lmpics.click()
+ time.sleep(2)
+ # After we click the right side is rendered in an iframe Store iframe
+ # web element
+ iframe = driver.find_element(By.TAG_NAME, "iframe")
+ # switch to selected iframe
+ driver.switch_to.frame(iframe)
+ # Now find button and click on button
+ video_elements = driver.find_elements(By.XPATH ,'//video') #.get_attribute('src')
+ urlmedia = str((video_elements[0]).get_attribute("src"))
+ current_url = video_elements[0]._parent.current_url
+ # return back away from iframe
+ driver.switch_to.default_content()
+ else:
+ # The default path if it is not a video link
+ ext='.jpg'
+ filename = filename+ext
+ # Test to see if file already exists, and if it does not grab the media and store it
+ # in location folder
+ if not os.path.exists('./Output/Pics/'+cleanname+'/'+visitdate):
+ os.makedirs('./Output/Pics/'+cleanname+'/'+visitdate)
+ if not os.path.isfile('./Output/Pics/'+cleanname+'/'+visitdate+'/'+filename):
+ urlretrieve(urlmedia, './Output/Pics/'+cleanname+'/'+visitdate+'/'+filename)
+ # Store the local path to be used in the excel document
+ pics_local_path = "./Output/Pics/"+cleanname+"/"+visitdate+'/'+filename
+ pics2.append(pics_local_path)
+ if env.forcegoogleupdate:
+ database_update_row(name,"review_id",current_url,"forceall",local_outputs)
+ # Add the correct extension to the file name
+ if pics2 and not os.path.isfile(
+ "./Output/Pics/"
+ + cleanname
+ + "/"
+ + visitdate
+ + '/'
+ + cleanname
+ + '-montage.mp4'
+ ):
+ make_montage_video_from_google(pics2,cleanname)
+ for loop in pics2:
+ if "montage.mp4" in loop:
+ outputmontage = loop
+ break
+ #sif pathlib.Path.exists(outputmontage):
+ pics2.append("./Output/Pics/"+cleanname+"/"+visitdate+'/'+cleanname+'-montage.mp4')
+ dict_post_complete= {'google':1,'web':0,'yelp':0,'facebook':0,'xtwitter':0,
+ 'instagram':0,'tiktok':0}
+ lst_data.append([name , text, score,pics,pics2,"GoogleMaps",visitdate,address,
+ dict_post_complete])
+ if env.force_web_create:
+ database_update_row(name,"visitdate",visitdate,"forceall",local_outputs)
+ return lst_data
+
+##################################################################################################
+
+# Do the google_scroll
+def google_scroll(counter_google_scroll,driver):
+ """
+ Scrolls down a Google search results page a specified number of times.
+
+ Args:
+ counter_google_scroll (int): The number of times to scroll down the page.
+ driver: The Selenium WebDriver instance.
+
+ Returns:
+ int: The result of the last scroll operation.
+
+ Raises:
+ AttributeError: If an error occurs during scrolling.
+ """
+ print('google_scroll...', end ="")
+ time.sleep(3)
+ scrollable_div = driver.find_element(By.XPATH,
+ '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[5]/div[2]')
+# '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[2]/div[10]/div')
+ for _i in range(counter_google_scroll):
+ try:
+ google_scroller = driver.execute_script(
+ 'document.getElementsByClassName("dS8AEf")[0].\
+ scrollTop=document.getElementsByClassName("dS8AEf")[0].scrollHeight',
+ scrollable_div
+ )
+ time.sleep(3)
+ print('.',end = "")
+ except AttributeError as e:
+ print(f"Error while google_scroll: {e}")
+ break
+ print ('')
+ return google_scroller
+
+##################################################################################################
+
+def write_to_xlsx2(data, local_outputs):
+ """
+ Writes data to an Excel file and updates the database with new entries.
+
+ Args:
+ data: Data to be written to the Excel file.
+ local_outputs: Output information.
+
+ Returns:
+ Data: The data that was written to the Excel file.
+ """
+
+ print('write to excel...')
+ sqlalchemy.null()
+ cols = ["name", "comment", 'rating','picsURL','picsLocalpath','source','date','address',
+ 'dictPostComplete']
+ cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
+ 'address','dictPostComplete']
+ df = pd.DataFrame(data, columns=cols)
+ df2 = pd.DataFrame(local_outputs['xlsdf'].values, columns=cols2)
+ #df2 = df1.where((pd.notnull(df)), None) # take out NAN problems
+ #df3.astype(object).where(pd.notnull(df2), None)
+ print ('Dropped items not included in sync to database: ',df2.dropna(inplace=True))
+ rows = list(data)
+ if env.needreversed:
+ rows = reversed(rows)
+ #jsonposts = json.dumps(local_outputs['posts'], default=Posts)
+ print("Encode Object into JSON formatted Data using jsonpickle")
+ jsonposts = jsonpickle.encode(local_outputs['posts'], unpicklable=False)
+ for processrow in df2.values:
+ if processrow[1] in df.values:
+ print (' Row ',processrow.id,' ', processrow.name ,' already in XLS sheet')
+ d2_row = Posts(name=processrow.name ,comment=processrow.comment,rating=\
+ processrow.rating,picsURL=processrow.picsURL,pics_local_path=processrow.\
+ picsLocalpath,source=processrow.source,date=processrow.date,address=processrow.\
+ address,dict_post_complete=processrow.dictPostComplete)
+ elif processrow.name is not None:
+# Create a Python dictionary object with all the column values
+# d_row = {'name':processrow.name ,'comment':processrow.comment,'rating':processrow.rating,
+# 'picsURL':processrow.picsURL,'pics_local_path':processrow.picsLocalpath, 'source':\
+# processrow.source,'date':processrow.date,'address':processrow.address,'dict_post_complete'\
+# :processrow.dictPostComplete}
+ d2_row = Posts(name=processrow.name ,comment=processrow.comment,rating=processrow.\
+ rating,picsURL=processrow.picsURL,pics_local_path=processrow.picsLocalpath,\
+ source=processrow.source,date=processrow.date,address=processrow.address,\
+ dict_post_complete=processrow.dictPostComplete)
+ print (' Row ',processrow[0],' ', processrow.name ,' added to XLS sheet')
+ # Append the above Python dictionary object as a row to the existing pandas DataFrame
+ # Using the DataFrame.append() function
+ try:
+ if processrow.name in jsonposts : #local_outputs['posts']):
+ print (' Row ',processrow[0],' ', processrow.name ,' already in Database')
+ else:
+ local_outputs['postssession'].add(d2_row)
+ local_outputs['postssession'].commit()
+ print (' Row ',processrow[0],' ', processrow.name ,' added to Database')
+ except AttributeError as error:
+ print(' Not able to write to post data table: ' , type(error))
+ local_outputs['postssession'].rollback()
+ raise
+ df.to_excel(env.xls)
+ return data
+
+##################################################################################################
+
+def write_to_database(data, local_outputs):
+ """
+ Writes data to the database and updates the database with new entries.
+
+ Args:
+ data: Data to be written to the database.
+ local_outputs: Local output information.
+
+ Returns:
+ Data: The data that was written to the database.
+ """
+ column_list=[]
+ print('write to database ...')
+ for x in inspect.getmembers(Posts):
+# if not (x[0].startswith('_') or 'metadata' in x[0] or 'registry' in x[0] or 'id' in x[0]):
+ if not (x[0].startswith('_') or 'metadata' in x[0] or 'registry' in x[0]):
+ column_list.append(x[0])
+ #cols = ["name", "comment", 'rating','picsURL','picsLocalpath','source','date','address',
+ # 'dictPostComplete','visitdate']
+ #cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
+ # 'address','dictPostComplete','visitdate']
+ #df = pd.DataFrame(local_outputs["xls"], columns=cols)
+# df = pd.DataFrame(local_outputs['xlsdf'])
+ df = pd.DataFrame(local_outputs['xlsdf'].values, columns=column_list)
+ #df2 = pd.DataFrame(local_outputs['posts'], columns=column_list)
+ df2 = pd.DataFrame(local_outputs['posts'])
+ # print ('Dropped items not included in sync to database: ',df2.dropna(inplace=True))
+# rows = list(data)
+ # if env.needreversed:
+ # rows = reversed(rows)
+ #jsonposts = json.dumps(local_outputs['posts'], default=Posts)
+ df.to_excel(env.xls)
+ print("Encode Object into JSON formatted Data using jsonpickle")
+ jsonposts = jsonpickle.encode(local_outputs['posts'], unpicklable=False)
+ for processrow in data:
+# getdata = local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0])
+ #if processrow[0] in local_outputs['posts']:
+# if getdata.count() >0:
+ # if len(result) > 0:
+# print (' Row ',processrow[0],' already in database')
+# d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
+# ,picsURL=processrow[3],picsLocalpath=processrow[4],\
+# source=processrow[5],date=processrow[6],address=processrow[7],\
+# dictPostComplete=processrow[8])
+# d2_dict = {'name':processrow[0] ,'comment':processrow[1],'rating':processrow[2]\
+# ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
+# 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
+# 'dictPostComplete':str(processrow[8])}
+# if env.forcegoogleupdate:
+# print (' Row ',processrow[0],' updated in database due to forcegoogleupdate')
+# local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0]).update\
+# (d2_dict)
+# local_outputs['postssession'].commit()
+# elif processrow[0] is not None:
+# # Create a Python dictionary object with all the column values
+# # d_row = {'name':processrow.name ,'comment':processrow.comment,'rating':processrow.rating,
+# # 'picsURL':processrow.picsURL,'pics_local_path':processrow.picsLocalpath, 'source':
+# # processrow.source,'date':processrow.date,'address':processrow.address,'dict_post_complete'
+# # :processrow.dictPostComplete}
+# d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
+# ,picsURL=str(processrow[3]),picsLocalpath=str(processrow[4]),\
+# source=processrow[5],date=processrow[6],address=processrow[7],\
+# dictPostComplete=str(processrow[8]))
+# print (' Row ',processrow[0],' added to Database')
+# # Append the above Python dictionary object as a row to the existing pandas DataFrame
+# # Using the DataFrame.append() function
+ try:
+
+ getdata2 = local_outputs['postssession'].query(Posts).filter(Posts.name \
+ == processrow[0])
+ if getdata2.count() >0:
+ print (' Row ',processrow[0],' already in Database')
+ if env.forcegoogleupdate:
+ print (' Row ',processrow[0],' updated in database due to forcegoogleupdate')
+ d2_dict = {'name':processrow[0] ,'comment':processrow[1],'rating':processrow[2]\
+ ,'picsURL':str(processrow[3]),'picsLocalpath':str(processrow[4]),\
+ 'source':processrow[5],'date':processrow[6],'address':processrow[7],\
+ 'dictPostComplete':str(processrow[8])}
+ print (' Row ',processrow[0],' updated in Database')
+ local_outputs['postssession'].query(Posts).filter(Posts.name == processrow[0]).\
+ update(d2_dict)
+ local_outputs['postssession'].commit()
+ else:
+ d2_row = Posts(name=processrow[0] ,comment=processrow[1],rating=processrow[2]\
+ ,picsURL=str(processrow[3]),picsLocalpath=str(processrow[4]),\
+ source=processrow[5],date=processrow[6],address=processrow[7],\
+ dictPostComplete=str(processrow[8]))
+ print (' Row ',processrow[0],' added to Database')
+ local_outputs['postssession'].add(d2_row)
+ local_outputs['postssession'].commit()
+ print (' Row ',processrow[0],' added to Database')
+ except AttributeError as error:
+ print(' Not able to write to post data table: ' , type(error))
+ local_outputs['postssession'].rollback()
+ raise
+ processrow = []
+ df.to_excel(env.xls)
+ return data
+
+##################################################################################################
+
+def database_update_row(review_name, column_name, column_value, update_style, local_outputs):
+ """
+ Updates a row in the database based on the specified review name, column name, value,
+ and update style.
+
+ Args:
+ review_name (str): The name of the review to update.
+ column_name (str): The name of the column to update.
+ column_value: The value to update the column with.
+ update_style (str): The style of update to perform.
+ local_outputs: Local output information.
+
+ Returns:
+ bool: True if the row was successfully updated, False otherwise.
+ """
+
+ try:
+ if update_style == "forceall" and column_value is not False:
+ local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).update\
+ ({column_name : column_value})
+ print (' Force Updated ',column_name, ' to: ',column_value)
+ elif update_style == "onlyempty" and column_value is not False:
+ postval = local_outputs['postssession'].query(Posts).filter(Posts.name == review_name,\
+ getattr(Posts,column_name).is_not(null())).all()
+ if len(postval) == 0 :
+ local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).\
+ update({column_name : column_value})
+ print (' Updated blank ',postval ,' on value',column_name, ' to: ',\
+ column_value)
+ elif update_style == "toggletrue":
+ postval = local_outputs['postssession'].query(Posts).filter(Posts.name == review_name\
+ ,getattr(Posts,column_name).is_not(1)).all()
+ local_outputs['postssession'].query(Posts).filter(Posts.name == review_name).update\
+ ({column_name : "1"})
+ print (' Updated ',column_name, ' on value: ',postval[0].column_value, ' to: ',\
+ column_value)
+ except AttributeError as error:
+ print(" Not able to write to post data table to update ",review_name," ",column_name,"\
+ to: ",column_value , type(error), error)
+ local_outputs['postssession'].rollback()
+ raise
+# else:
+ local_outputs['postssession'].commit()
+ #time.sleep(env.facebooksleep)
+ return True
+
+##################################################################################################
+
+def check_wordpress_media(filename, headers):
+ """
+ Checks if a media file exists in the WordPress media folder.
+
+ Args:
+ filename (str): The name of the media file to check.
+ headers: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the media file if found, otherwise
+ (False, False).
+ """
+
+ file_name_minus_extension = filename
+ response = requests.get(env.wpAPI + "/media?search="+file_name_minus_extension,\
+ headers=headers,timeout=env.request_timeout)
+ try:
+ if result := response.json():
+ file_id = int(result[0]['id'])
+ link = result[0]['guid']['rendered']
+ return file_id, link
+ else:
+ return False,False
+ except AttributeError:
+ print(' No existing media with same name in Wordpress media folder: '+filename)
+ return (False, False)
+
+##################################################################################################
+
+def check_is_port_open(host):
+ """
+ Checks if a port on a host is open.
+
+ Args:
+ host (str): The host to check for an open port.
+ port (int): The port number to check.
+
+ Returns:
+ bool: True if the port is open, False otherwise.
+ """
+
+ try:
+ is_web_up = urllib3.request("GET", host, timeout=env.request_timeout)
+ if is_web_up.status == 200:
+ return True
+ except AttributeError as error:
+ print ('Could not open port to website: ', host, type(error))
+ return False
+
+##################################################################################################
+
+def get_wordpress_post_id_and_link(postname, headers2):
+ """
+ Retrieves the ID and link of a WordPress post based on the post name.
+
+ Args:
+ postname (str): The name of the WordPress post to retrieve.
+ headers2: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the WordPress post.
+ """
+
+ response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,timeout=\
+ env.request_timeout)
+ result = response.json()
+ if len(result) > 0:
+ return int(result[0]['id']), result[0]['link']
+ print(' No existing post with same name: ' + postname)
+ return False, False
+
+##################################################################################################
+
+def check_wordpress_post(postname, postdate, headers2,local_outputs):
+ """
+ Checks if a WordPress post with the given name and date exists.
+
+ Args:
+ postname (str): The name of the WordPress post to check.
+ postdate: The date of the WordPress post to check.
+ headers2: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the existing post if found,
+ otherwise (False, False).
+ """
+
+ try:
+ response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,\
+ timeout=env.request_timeout)
+ result = response.json()
+ except AttributeError as error:
+ print ('Could not query for post on wordpress: ', postname,postdate, type(error))
+ return False, False
+ # try:
+ # newdate,newdate2,visitdate = get_wordpress_post_date_string(result[0]['date'],result[0]['date'])
+ # newdate3,newdate4,visitdate2 = get_wordpress_post_date_string(postdate,str(datetime.now()))
+ # if visitdate and visitdate2:
+ # print ('Post exists, checking visit date')
+ # except KeyError as error:
+ # print (' Post exists but does not have post date in visitdate field:',error)
+ if len(result) > 0:
+ d1list = result[0]['date'].split("-")
+ d2list = postdate.split("-")
+ if d1list[0] == d2list[0] and d1list[1] == d2list[1]:
+ return int(result[0]['id']), result[0]['link']
+ else:
+ print(' -No existing post with same name: ' + postname)
+ return False, False
+
+##################################################################################################
+def check_wordpress_post2(postname, postdate, post_id, headers2,local_outputs):
+ """
+ Checks if a WordPress post with the given name and date exists.
+
+ Args:
+ postname (str): The name of the WordPress post to check.
+ postdate: The date of the WordPress post to check.
+ headers2: Additional headers for the request.
+
+ Returns:
+ tuple: A tuple containing the ID and link of the existing post if found,
+ otherwise (False, False).
+ """
+
+ try:
+ response = requests.get(env.wpAPI+"/posts?search="+postname, headers=headers2,\
+ timeout=env.request_timeout)
+ result = response.json()
+ except AttributeError as error:
+ print ('Could not query for post on wordpress: ', postname,postdate, type(error))
+ return False, False
+ # try:
+ # newdate,newdate2,visitdate = get_wordpress_post_date_string(result[0]['date'],result[0]['date'])
+ # newdate3,newdate4,visitdate2 = get_wordpress_post_date_string(postdate,str(datetime.now()))
+ # if visitdate and visitdate2:
+ # print ('Post exists, checking visit date')
+ # except KeyError as error:
+ # print (' Post exists but does not have post date in visitdate field:',error)
+ if len(result) > 0:
+ d1list = result[0]['date'].split("-")
+ d2list = postdate.split("-")
+ if d1list[0] == d2list[0] and d1list[1] == d2list[1]:
+ return int(result[0]['id']), result[0]['link']
+ print(' -No existing post with same name: ' + postname)
+ return False, False
+
+##################################################################################################
+
+# Function to get the featured photo ID of a WordPress post
+def get_wordpress_featured_photo_id(post_id):
+ """ Get photoid from featured photo
+
+ Args:
+ post_id (_type_): _description_
+
+ Returns:
+ _type_: _description_
+ """
+ # Make a GET request to the WordPress REST API to retrieve media details
+ response = requests.get(f"{env.wpAPOurl}/{post_id}",timeout=env.request_timeout)
+ # Check if the request was successful
+ if response.status_code == 200:
+ # Parse the JSON response
+ media_items = response.json()
+
+ # Loop through the media items associated with the post
+ # for item in media_items:
+ # # Check if the media item is the featured image
+ # if item.get('post', None) == int(post_id):
+ # # Return the ID of the featured image
+ return media_items['featured_media']
+ # If the request failed or the featured image was not found, return None
+ return None
+# # Example usage
+# featured_photo_id = get_featured_photo_id(POST_ID)
+# print(f"The featured photo ID for post {POST_ID} is: {featured_photo_id}")
+
+##################################################################################################
+
+def post_to_x2(title, content, headers,date, rating, address, picslist,local_outputs):
+ """
+ Post to x2.
+
+ This function posts content to a social media platform using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ date (str): The date of the post.
+ rating (int): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ instasession: The Instagram session for posting.
+
+ Returns:
+ str: The media ID of the posted content.
+ """
+ pics = ((picslist[1:-1]).replace("'","")).split(",")
+ # Replace the following strings with your own keys and secrets
+ CONSUMER_KEY = env.x_consumer_key
+ CONSUMER_SECRET = env.x_consumer_secret
+ ACCESS_TOKEN = env.x_access_token
+ ACCESS_TOKEN_SECRET = env.x_access_token_secret
+ # Authenticate to Twitter
+ auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
+ auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
+ # Create an API object to use the Twitter API
+ #api = tweepy.API(auth)
+ img_list = pics
+ imgs_vid = []
+ imgs_pic = []
+ client_v1 = get_twitter_conn_v1(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
+ client_v2 = get_twitter_conn_v2(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
+ for img in img_list:
+ if 'montage.mp4' in img:
+ imgs_vid.append(img.strip())
+ else:
+ imgs_pic.append(img.strip())
+ if imgs_vid:
+ try:
+ # Message to post along with the video
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
+ .all()
+ if wpurl := attrib_list[0].wpurl:
+ if business_url := attrib_list[0].businessurl:
+ status_message = (
+ f'{str(title)}: My Review - '
+ + wpurl
+ + '\n Business website: '
+ + business_url
+ + '\n'
+ )
+ else:
+ status_message = f'{str(title)}: My Review - ' + wpurl + '\n'
+ status_message2 = status_message +' '+str(get_hastags(address, title, 'short'))\
+ +' '
+ status_message_short = status_message2[:279]
+ video_path = imgs_vid[0]
+ # Upload video
+ media = client_v1.media_upload(filename=video_path)
+ # Post tweet with video
+ # tweetlat = (local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ # title).all())[0].latitude
+ # tweetlong = (local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ # title).all())[0].longitude
+ if media.processing_info['state'] != 'failed':
+ client_v2.create_tweet(text=status_message_short,media_ids=[media.media_id])
+# client_v2.create_tweet(text=status_message_short, lat=tweetlat , \
+# long=tweetlong ,media_ids=[media.media_id])
+ else:
+ print ('Problem uploading video to twitter: ',media.processing_info['error'])
+ return False
+ else:
+ print (' Skipping xtwitter post because wordpress URL is missing')
+ except AttributeError as error:
+ print("AttributeError An error occurred:",error) # An error occurred:
+ else:
+ print (' xtwitter: No video available, skipping twitter post for : ',title)
+ return False
+ time.sleep(env.facebooksleep)
+ return True
+
+##################################################################################################
+
+def post_to_threads(title, content,headers, date, rating, address, picslist, local_outputs):
+ img_list = ((picslist[1:-1]).replace("'","")).split(",")
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ business_url = attrib_list[0].businessurl
+ wpurl = attrib_list[0].wpurl
+ auth_token = env.threads_access_token
+ group_id = env.threads_page_id
+ imgs_vid = []
+ if wpurl and (attrib_list[0].picsLocalpath != '[]'):
+ if business_url:
+ status_message = (
+ f'{str(title)}: My Review - {wpurl} \n Business website: {business_url}'\
+ + ' \n\n') + content
+ else:
+ status_message = f'{str(title)}: My Review - ' + wpurl + ' \n\n' + content
+ imgs_pic = []
+ for img in img_list:
+ if 'montage.mp4' in img:
+ imgs_vid.append(img.strip())
+ else:
+ imgs_pic.append(img.strip())
+ if imgs_vid:
+ imgs_id = []
+ try:
+ post_id = post_threads_video(group_id, imgs_vid,auth_token,title, status_message,
+ date, rating, address)
+ imgs_id.append(post_id['id'])
+ except AttributeError as error:
+ print(" An error occurred:",error)
+ return False
+ time.sleep(env.facebooksleep)
+ print(' threads response: ',post_id)
+ else:
+ print (' threads: Wordpress URL or no pictures so skipping threads posting')
+ return True
+
+##################################################################################################
+
+def post_facebook3(title, content,headers, date, rating, address, picslist, local_outputs):
+ """
+ Post to Facebook3.
+
+ This function posts content to Facebook using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ date (str): The date of the post.
+ rating (int): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ instasession: The Instagram session for posting.
+
+ Returns:
+ bool: Indicates if the post was successfully made.
+ """
+ pics = ((picslist[1:-1]).replace("'","")).split(",")
+ group_id = env.facebookpageID
+ auth_token = env.facebookpass
+ imgs_vid = []
+ img_list = pics
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ business_url = attrib_list[0].businessurl
+ wpurl = attrib_list[0].wpurl
+ if wpurl and (attrib_list[0].picsLocalpath != '[]'):
+ if business_url:
+ status_message = (
+ f'{str(title)}: My Review - {wpurl} \n Business website: {business_url}'\
+ + ' \n\n') + content
+ else:
+ status_message = f'{str(title)}: My Review - ' + wpurl + ' \n\n' + content
+ imgs_pic = []
+ for img in img_list:
+ if 'montage.mp4' in img:
+ imgs_vid.append(img.strip())
+ else:
+ imgs_pic.append(img.strip())
+ if imgs_vid:
+ imgs_id = []
+ try:
+ post_id = post_facebook_video(group_id, imgs_vid,auth_token,title, status_message,
+ date, rating, address)
+ imgs_id.append(post_id['id'])
+ except AttributeError as error:
+ print(" An error occurred:",error)
+ return False
+ time.sleep(env.facebooksleep)
+ print(' Facebook response: ',post_id)
+ else:
+ print (' facebook: Wordpress URL or no pictures so skipping Facebook posting')
+ return True
+
+##################################################################################################
+
+def post_to_threads2(title, content, headers, date, rating, address, picslist, local_outputs):
+ """
+ Posts content to threads if picslist is not empty and contains 'montage.mp4'.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers information.
+ date: Date information.
+ rating: Rating information.
+ address: Address information.
+ picslist: List of pictures.
+ local_outputs: Local output information.
+
+ Returns:
+ bool: True if the post was successfully uploaded to Instagram, False otherwise.
+ """
+ pics = ((picslist[1:-1]).replace("'","")).split(",")
+ if pics != '[]' and "montage.mp4" in pics:
+ outputmontage = ''
+ addresshtml = re.sub(" ", ".",address)
+ #content = content + get_hastags(address, title)
+ pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
+ #video, outputmontage = make_montage_video_from_google(pics)
+ for loop in pics:
+ if "montage.mp4" in loop:
+ outputmontage = loop
+ break
+ if pathlib.Path.exists(outputmontage):
+ try:
+ data = title + "\n"+ address+"\nGoogle map to destination: " \
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\n\n" \
+ + content + "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title,'long')+ \
+ "\n\nhttps://www.joeeatswhat.com "+"\n\n"
+ local_outputs['instasession'].video_upload(outputmontage, data)
+ except AttributeError as error:
+ print(" An error occurred uploading video to Threads:", type(error).__name__)
+ return False
+ return True
+ else:
+ return False
+
+###################################################################################################
+
+# def tiktok_upload_video(session_id, file_path, title, tags, schedule_time=None):
+# url = 'https://www.tiktok.com/api/upload/video/'
+# headers = {
+# 'Cookie': f'sessionid={session_id}'
+# }
+# data = {
+# 'title': title,
+# 'tags': ','.join(tags),
+# 'schedule_time': schedule_time
+# }
+# files = {
+# 'video': open(file_path, 'rb')
+# }
+# response = requests.post(url, headers=headers, data=data, files=files)
+# return response.json()
+
+def post_to_tiktok(title, content, headers2, date, rating, address, picslist, local_outputs):
+ """
+ Posts content to TikTok with specified session ID, video file, title, hashtags, and optional
+ scheduling.
+
+ Args:
+ title (str): The title of the video.
+ content (str): The content of the video.
+ headers: Headers information.
+ date: Date information.
+ rating: Rating information.
+ address: Address information.
+ picslist: List of pictures.
+ local_outputs: Local output information.
+
+ Returns:
+ None
+ """
+ # Replace 'your_sessionid_cookie' with your actual TikTok sessionid cookie.
+ #session_id = env.tiktok_client_secret
+
+ # Replace 'path_to_video.mp4' with the path to your video file.
+ #file_path = 'path_to_video.mp4'
+
+ # Replace 'Your video title' with the title of your video.
+ #title = 'Your video title'
+
+ # Replace the following list with the hashtags you want to add to your post.
+ tags = get_hastags(address, title,'long')
+
+ # If you want to schedule your video, replace 'schedule_timestamp' with the Unix timestamp.
+ # Leave it as None if you want to upload immediately.
+ #schedule_time = None # or Unix timestamp (e.g., 1672592400)
+ pics = ((picslist[1:-1]).replace("'","").replace(" ","")).split(",")
+ if not any(element.endswith("montage.mp4") for element in pics):
+ return False
+ for pic in pics:
+ if 'montage.mp4' in pic:
+ file_path = pic
+ # """
+ # client_key string The unique identification key
+ # provisioned to the partner.
+ # client_secret string The unique identification secret provisioned
+ # to the partner.
+ # code string The authorization code from the web, iOS, Android or desktop
+ # authorization callback. The value should be URL decoded.
+ # grant_type string Its value should always be set as
+ # authorization_code.
+ # redirect_uri string Its value must be the same as the redirect_uri used
+ # for requesting code.
+ # curl --location --request POST 'https://open.tiktokapis.com/v2/oauth/token/' \
+ # --header 'Content-Type: application/x-www-form-urlencoded' \
+ # --header 'Cache-Control: no-cache' \
+ # --data-urlencode 'client_key=CLIENT_KEY' \
+ # --data-urlencode 'client_secret=CLIENT_SECRET' \
+ # --data-urlencode 'code=CODE' \
+ # --data-urlencode 'grant_type=authorization_code' \
+ # --data-urlencode 'redirect_uri=REDIRECT_URI'
+ # """
+
+# curl --location 'https://open.tiktokapis.com/v2/post/publish/inbox/video/init/' \
+# --header 'Authorization: Bearer act.example12345Example12345Example' \
+# --header 'Content-Type: application/json; charset=UTF-8'
+# --data '{
+# "source_info": {
+# "source": "FILE_UPLOAD",
+# "video_size": exampleVideoSize,
+# "chunk_size" : exampleChunkSize,
+# "total_chunk_count": exampleTotalChunkCount
+# }
+# }'
+
+
+# curl --location 'https://open.tiktokapis.com/v2/post/publish/video/init/' \
+# --header 'Authorization: Bearer act.example12345Example12345Example' \
+# --header 'Content-Type: application/json; charset=UTF-8' \
+# --data-raw '{
+# "post_info": {
+# "title": "this will be a funny #cat video on your @tiktok #fyp",
+# "privacy_level": "MUTUAL_FOLLOW_FRIENDS",
+# "disable_duet": false,
+# "disable_comment": true,
+# "disable_stitch": false,
+# "video_cover_timestamp_ms": 1000
+# },
+# "source_info": {
+# "source": "FILE_UPLOAD",
+# "video_size": 50000123,
+# "chunk_size": 10000000,
+# "total_chunk_count": 5
+# }
+# }'
+
+
+
+
+# https://api.tiktok.com/open-api/v2/aweme/post/?aweme-type=video
+# You will need to include the following headers:
+
+# Content-Type: application/json
+# X-SS-TOKEN: [Your App ID]
+# X-TikTok-Signature: [Your App Secret]
+# And the following JSON body:
+
+# {
+# "device_platform": "android",
+# "device_version": "11",
+# "app_name": "musical.ly",
+# "app_version": "7.0.3",
+# "resolution": "1080*1920",
+# "os_version": "11",
+# "model": "vivo 1906",
+# "manufacturer": "vivo",
+# "language": "en",
+# "country": "US"
+# }
+
+ connect_json_body = {
+ "device_platform": "android",
+ "device_version": "11",
+ "app_name": "musical.ly",
+ "app_version": "7.0.3",
+ "resolution": "1080*1920",
+ "os_version": "11",
+ "model": "vivo 1906",
+ "manufacturer": "vivo",
+ "language": "en",
+ "country": "US"
+ }
+ connect_json_header = {
+ 'Content-Type': 'application/json',
+ 'X-SS-TOKEN': env.tiktok_app_id, #[Your App ID],
+ 'X-TikTok-Signature': env.tiktok_client_secret, #[Your App Secret]
+ }
+ connect_response = requests.post('https://open.tiktokapis.com/v2/post/publish/video/init/',headers=connect_json_header,\
+ data=connect_json_body,timeout=env.request_timeout)
+
+#request https://api.tiktok.com/open-api/v2/aweme/post/?aweme-type=video
+# https://api.tiktok.com/open-api/v2/aweme/post/
+# You will need to include the following headers:
+
+# Content-Type: multipart/form-data
+# X-SS-TOKEN: [Your App ID]
+# X-TikTok-Signature: [Your App Secret]
+# Authorization: Bearer [Your Access Token]
+# And the following form data:
+
+# video: [Your Video File]
+# desc: [Your Video Description]
+# Once you have made this request, your video will be uploaded to TikTok.
+ post_json_header = {
+ 'X-SS-TOKEN': env.tiktok_app_id,#[Your App ID],
+ 'X-TikTok-Signature': env.tiktok_client_secret,#[Your App Secret]
+ 'Authorization': 'ww'#Bearer [Your Access Token]
+ }
+ post_json_body = {
+ 'video': file_path,
+ 'desc': content+tags
+ }
+
+ post_response = requests.post('https://api.tiktok.com/open-api/v2/aweme/post/',headers=post_json_header,\
+ data=post_json_body,timeout=env.request_timeout)
+
+
+
+ # headers = ['Content-Type: application/x-www-form-urlencoded','Cache-Control: no-cache']
+ # data = ['client_key='+env.tiktok_client_key,'client_secret='+env.tiktok_client_secret,\
+ # 'code='+env.tiktok_app_id,'grant_type=authorization_code','redirect_uri=http://www.joeeatswhat.com']
+ # allheaders = headers + data
+
+ # try:
+ # data2 = {'source_info':{'source':"FILE_UPLOAD",file_path}}
+ # response = requests.post('https://open.tiktokapis.com/v2/oauth/token/,headers:',allheaders,\
+ # 'data:',data2,'timeout:',env.request_timeout)
+ # except BaseException as error:
+ # print(" An error occurred uploading video to TikTok:", type(error).__name__)
+ # return False
+ # Call the function to upload the video
+ # response = tiktok_upload_video(session_id, file_path, title, tags, schedule_time)
+ print(' tikTok response: ',post_response)
+ return True
+###################################################################################################
+
+def post_to_instagram2(title, content, headers, date, rating, address, picslist, local_outputs):
+ """
+ Posts content to Instagram with relevant information and media.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers for the post.
+ date: Date of the post.
+ rating: Rating of the post.
+ address: Address related to the post.
+ picslist: List of pictures for the post.
+ local_outputs: Local outputs for the post.
+
+ Returns:
+ bool: True if the post was successfully uploaded, False otherwise.
+ """
+
+ outputmontage = ''
+ addresshtml = re.sub(" ", ".",address)
+ attrib_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ if wpurl := attrib_list[0].wpurl:
+ if business_url := attrib_list[0].businessurl:
+ data = title + "\n"+ address+"\n"+business_url+"\n"+"Review: "+wpurl+\
+ "\nGoogle map to destination: " \
+ r"https://www.google.com/maps/dir/?api=1&destination="\
+ +addresshtml +"\n"+"Review: "+wpurl+"\n\n"+ content + "\n"+rating+"\n"+date+\
+ "\n\n"+get_hastags(address, title,'long')+"\n\nhttps://www.joeeatswhat.com"+"\n\n"
+ else:
+ print (" Missing business url for : "+title+" not using it in intagram post")
+ data = title + "\n"+ address+"\n"+"Review: "+wpurl+"\nGoogle map to destination: " \
+ r"https://www.google.com/maps/dir/?api=1&destination="+addresshtml +"\nReview: "\
+ +wpurl+"\n\n"+ content + "\n"+rating+"\n"+date+"\n\n"+ get_hastags(address, title\
+ ,'long')+"\n\nhttps://www.joeeatswhat.com"+"\n\n"
+ instasession = local_outputs['instagram']
+ if picslist != '[]' and "montage.mp4" in picslist:
+ #content = content + get_hastags(address, title)
+ pics = ((picslist[1:-1].replace(",","")).replace("'","")).split(" ")
+ #video, outputmontage = make_montage_video_from_google(pics)
+ for loop in pics:
+ if "montage.mp4" in loop:
+ outputmontage = loop
+ break
+ pathoutputmontage = outputmontage[1:-1]
+ if pathlib.Path.exists(pathoutputmontage):
+ try:
+ duration, fps, (width, height)=with_moviepy(outputmontage)
+ if duration < 60:
+ instasession.video_upload(outputmontage, data)
+ else:
+ if not os.path.isfile(outputmontage+".trim.mp4"):
+ video = VideoFileClip(outputmontage)
+ video = video.subclip(0, 60)
+ print (' IG video duration too long 60 : ',duration, fps, (width,height))
+ video.write_videofile(outputmontage+".trim.mp4")
+ instasession.video_upload(outputmontage+".trim.mp4", data)
+ except BaseException as error:
+ print(" An error occurred uploading video to Instagram:", type(error).__name__)
+ return False
+ return True
+ else:
+ print (' Missing wordpress post for instagram : ',title)
+ return False
+
+##################################################################################################
+
+def with_moviepy(filename):
+ from moviepy.editor import VideoFileClip
+ clip = VideoFileClip(filename)
+ duration = clip.duration
+ fps = clip.fps
+ width, height = clip.size
+ return duration, fps, (width, height)
+
+##################################################################################################
+
+def post_to_wordpress(title,content,headers,date,rating,address,picslist,local_outputs):
+ """
+ Post to WordPress.
+
+ This function posts content to a WordPress site using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers for the request.
+ date (str): The date of the post.
+ rating (str): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ local_outputs: Outputs for the post.
+
+ Returns:
+ None
+"""
+ # post
+ #new_post = False
+ #countreview = False
+ addresshtml = re.sub(" ", ".",address)
+ googleadress = r""+str(address)+r""
+ contentpics = ''
+ picchop = ''
+ linkslist=[]
+ # picl = picslist[1:-1]
+ # pic2 = picl.replace(",","")
+ # # #re.sub(r',','',picl) #re.sub( r'[^a-zA-Z0-9]','',tempdate[1])
+ # pic3= pic2.replace("'","")
+ # picchop = pic3.split(" ")
+ # line = re.sub('[!@#$]', '', line)
+ #picchop = re.sub(',\'','',picslist[1:-1])
+ picchop = picslist[1:-1].replace(",","").replace("'","").split(" ")
+ print (' Figuring out date of Post : ',title)
+ #specifify the formatting of the date_string.
+ # formatting = '%b/%Y/%d'
+ date_string = date
+ if "a day" in date_string:
+ date = dt.timedelta(days=-1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - date
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "day" in date:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta(days=tempdate)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() + relativedelta(days=tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a week" in date:
+# date = dt.timedelta(weeks= -1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - relativedelta(weeks= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "week" in date:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta(weeks= tempdate)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() + relativedelta(weeks= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a month" in date:
+# date = dt.timedelta(months= -1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - relativedelta(months = 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "month" in date:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta(months= tempdate)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() + relativedelta(months = tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a year" in date:
+# date = dt.timedelta(years= -1)
+# newdate = dt.datetime.strptime(date_string, formatting).date()
+ newdate = datetime.today() - relativedelta(years= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "year" in date:
+ try:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+# date = dt.timedelta( years= tempdate)
+# newdate = dt.datetime.strptime(date_string).date()
+ newdate = datetime.today() + relativedelta(years= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+ else:
+ #specifify the formatting of the date_string.
+ formatting = '%Y-%b-%d'
+ month = date[:3]
+ year = date[3:]
+ day = '01'
+ date_string = year+'-'+ month+'-'+day
+ try:
+ newdate = dt.datetime.strptime(date_string, formatting)\
+ .date()
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+# try:
+# newdate = dt.datetime.strptime(date_string, formatting)\
+# .date()
+# except AttributeError as error:
+# print(" An error getting date occurred:", error)
+ visitdate = newdate.strftime("%b%Y")
+ newdate = str(newdate)
+ #formatting = '%b/%Y/%d' #specifify the formatting of the date_string.
+ #newdate2 = dt.datetime.strptime(str(newdate), formatting).date()
+ dateparts = (str(newdate)).split("-")
+ dateparts2 = dateparts[2].split(" ")
+ visitdate2 = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
+ .all()[0].visitdate
+ if visitdate != visitdate2:
+ database_update_row(title,"visitdate",visitdate,"forceall",local_outputs)
+ print (f'UPDATED: {visitdate2} to {visitdate} for {title}')
+ #dateparts = dateparts2[0]
+# print ('dateparts',dateparts)
+ newdate2 = dateparts[0]+'-'+dateparts[1]+'-'+dateparts2[0]+'T22:00:00'
+ #newdate2 = str(re.sub(r'-','/',str(newdate.date())))+'T22:00:00'
+ print (' Got Date: ', newdate2, newdate)
+ post_id, post_link = check_wordpress_post(title,newdate2,headers,local_outputs)
+ featured_photo_id = get_wordpress_featured_photo_id(post_id)
+ print(f" Featured photo ID: for {title} post {post_id} is: {featured_photo_id}")
+ if env.block_google_maps is not True:
+ try:
+ database_update_row(title,"wpurl",post_link,"forceall",local_outputs)
+ except AttributeError as error :
+ print ('Could not check to see post already exists',error)
+ if not post_id:
+ googleadress = r""+address+r""
+ post_data = {
+ "title": title,
+ # "content": address+'\n\n'+content+'\n'+rating+'\n\n' ,
+ "content": googleadress+'\n\n'+content+'\n'+rating ,
+ "status": "publish", # Set to 'draft' if you want to save as a draft
+ "date": newdate2,
+ "meta": {'visitdate':visitdate}
+ # "date": str(newdate)+'T22:00:00',
+ # "author":"joesteele"
+ }
+ try:
+ headers2 = headers
+ response = requests.post(env.wpAPOurl, json = post_data, headers=headers2,timeout=\
+ env.request_timeout)
+ if response.status_code != 201:
+ print ('Error: ',response, response.text)
+ else:
+ #new_post = True
+ post_id_json = response.json()
+ post_id = post_id_json.get('id')
+ print (' New post is has post_id = ',post_id)
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ #postneedsupdate = True
+ else:
+ print (' Post already existed: Post ID : ',post_id)
+ if not env.force_web_create:
+ return True
+ for pic in picchop:
+ if pic != '':
+ picslice2 = pic.split("/")[-1]
+ picslice = picslice2.split(".")
+ picname = picslice[0]
+ caption =title
+ description = title+"\n"+address
+ print (' Found Picture: ',picname)
+ file_id, link = check_wordpress_media(picname, headers)
+ # link = linknew['rendered']
+ if file_id is False:
+ print (' '+str(picname)+' was not already found in library, adding it')
+ # countreview = True
+ image = {
+ "file": open(pic, "rb"),
+ "post": post_id,
+ "caption": caption,
+ "description": description
+ }
+ try:
+ image_response = requests.post(env.wpAPI + "/media", headers=headers, \
+ files=image,timeout=env.request_timeout)
+ except AttributeError as error:
+ print(" An error uploading picture ' + picname+ ' occurred:", \
+ type(error).__name__)
+ if image_response.status_code != 201 :
+ print (' Error:Image ',picname,' wasnot successfully uploaded.response:'\
+ ,image_response)
+ else:
+ pic_dic=image_response.json()
+ file_id= pic_dic.get('id')
+ link = pic_dic.get('guid').get("rendered")
+ print (' ',picname,' was successfully uploaded to website with ID: ',\
+ file_id, link)
+ try:
+ links_dict = {'file_id' : file_id , 'link' : link}
+ linkslist.append(links_dict)
+ except AttributeError as error:
+ print(" An error adding to dictionary " , file_id , link , " occurred:",\
+ type(error).__name__) # An error occurred:
+ else:
+ print (' Photo ',picname,' was already in library and added to post with ID:',\
+ file_id,' : ',link)
+ try:
+ image_response = requests.post(env.wpAPI + "/media/" + str(file_id),\
+ headers=headers, data={"post" : post_id},timeout=env.request_timeout)
+ except AttributeError as error:
+ print (' Error- Image ',picname,' was not attached to post. response: ',\
+ image_response+' '+type(error).__name__)
+ try:
+ post_response = requests.post(env.wpAPI + "/posts/" + str(post_id),\
+ headers=headers,timeout=env.request_timeout)
+ if link in post_response.text:
+ print (' Image link for ', picname, 'already in content of post: '\
+ ,post_id, post_response.text, link)
+ else:
+ linkslist.append({'file_id' : file_id , 'link' : link})
+ # countreview = True
+ except AttributeError as error:
+ print(" An error loading the metadata from the post "+post_response.title+\
+ ' occurred: '+type(error).__name__)
+ #ratinghtml = post_response.text
+ first_mp4 = True
+ first_pic = True
+ fmedia = {}
+ contentpics = ""
+ for piclink in linkslist:
+ if piclink != '':
+ #for loop in linkslist:
+ print (' Adding ', piclink['link'], ' to posting')
+ try:
+ ext = piclink['link'].split( '.')[-1]
+ if ext == 'mp4':
+ if first_mp4:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
+ r'" autoplay="true"]'
+ first_mp4 = False
+ else:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
+ #[evp_embed_video url="http://example.com/wp-content/uploads/videos/vid1.mp4" autoplay="true"]
+ else:
+ contentpics+='\n '+r''
+ if first_pic:
+ fmedia = piclink['file_id']
+ first_pic = False
+ # fmedia.append = piclink{'file_id' }
+ # contentpics += '\n '+r'
' +'\n\n'
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ return False
+ try:
+# print ('featured_media = ',linkslist[0]['file_id'])
+ # if linkslist[0]['file_id']:
+ # print ('featuredmedia2 = ',linkslist[0]['file_id'])
+ if fmedia:
+ print ('Featured Media: ',fmedia)
+ else:
+ if linkslist:
+ fmedia = linkslist[0]['file_id']
+# print ('featured_media2 = ',file_id)
+ business_url_list = local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ title).all()
+ business_url = ""+\
+ title+""
+ # wpurllist = local_outputs['postssession'].query(Posts).filter(Posts.name == title).all()
+ # wpurl = wpurllist[0].wpurl
+# if business_url or business_url is False:
+ status_message = str(title) + ':\nBusiness website: '+ business_url
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+'\n'+\
+ rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print (' response_piclinks: ',response_piclinks)
+ if fmedia and fmedia != 0 and featured_photo_id and featured_photo_id !=0:
+ print (" Featured Media: "+str(featured_photo_id)+" "+str(fmedia)+" looks OK")
+ else:
+ print (" fmedia is still empty and need to populate")
+ if fmedia:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+
+ '\n'+rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":\
+ title},headers=headers,timeout=env.request_timeout)
+ print (' Results of new results ID value : '+str(\
+ get_wordpress_featured_photo_id(post_id)))
+ else:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress\
+ +'\n'+rating+contentpics,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print ('Results of new results ID with no picture value : '+str\
+ (get_wordpress_featured_photo_id(post_id)))
+ except AttributeError as error:
+ print(" An error writing images to the post " + post_response.title + ' occurred:',\
+ type(error).__name__) # An error occurred')
+ return False
+ return True
+
+##################################################################################################
+
+def build_picslist(picchop, piclink, file_id):
+ """
+ Builds a list of pictures for posting based on the provided picture links.
+
+ Args:
+ picchop (list): List of picture links to process.
+ piclink (str): The picture link to be added to the list.
+
+ Returns:
+ str: A string containing the formatted list of pictures for posting.
+ Raises:
+ AttributeError: If an error occurs during picture processing.
+ """
+
+ for piclink in picchop:
+ if piclink != '':
+ print (' Adding ', piclink['link'], ' to posting')
+ try:
+ ext = piclink['link'].split( '.')[-1]
+ if ext == 'mp4':
+ if first_mp4:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
+ r'" autoplay="true"]'
+ first_mp4 = False
+ else:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
+ else:
+ contentpics+='\n '+r''
+ if first_pic:
+ fmedia = piclink['file_id']
+ first_pic = False
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ return False
+ return contentpics
+
+##################################################################################################
+
+def get_wordpress_post_date_string(date_string, date):
+ """
+ Parses a date string and returns two formatted date strings.
+
+ Args:
+ date_string (str): The input date string to be parsed.
+ date (str): The keyword indicating the date offset.
+
+ Returns:
+ tuple: A tuple containing two formatted date strings.
+ Raises:
+ AttributeError: If an error occurs during date parsing.
+ """
+
+
+ if "a day" in date_string:
+ date = dt.timedelta(days=-1)
+ newdate = datetime.today() - date
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "day" in date_string:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(days=tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a week" in date_string:
+ newdate = datetime.today() - relativedelta(weeks= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "week" in date_string:
+ tempdate = -(int(re.sub( r'[^0-9]','',date_string)))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(weeks= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a month" in date_string:
+ newdate = datetime.today() - relativedelta(months = 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "month" in date_string:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(months = tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "a year" in date_string:
+ newdate = datetime.today() - relativedelta(years= 1)
+ visitdate = newdate.strftime("%b%Y")
+ else:
+ if "year" in date_string:
+ try:
+ tempdate = -int(re.sub( r'[^0-9]','',date_string))
+ print ('Stuff - > ',tempdate)
+ newdate = datetime.today() + relativedelta(years= tempdate)
+ visitdate = newdate.strftime("%b%Y")
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+ else:
+ #specifify the formatting of the date_string.
+ formatting = '%Y-%b-%d'
+ month = date[:3]
+ year = date[3:]
+ day = '01'
+ date_string = year+'-'+ month+'-'+day
+ try:
+ newdate = dt.datetime.strptime(date_string, formatting)\
+ .date()
+ except AttributeError as error:
+ print(" An error getting date occurred:",error)
+ newdate = str(newdate)
+ #formatting = '%b/%Y/%d' #specifify the formatting of the date_string.
+ #newdate2 = dt.datetime.strptime(str(newdate), formatting).date()
+ dateparts = (str(newdate)).split("-")
+ dateparts2 = dateparts[2].split(" ")
+ newdate2 = dateparts[0]+'-'+dateparts[1]+'-'+dateparts2[0]+'T22:00:00'
+ print (' Got Date: ', newdate2, newdate)
+ return (newdate,newdate2,visitdate)
+
+##################################################################################################
+
+def create_wordpress_post(newdate2, picchop, title, address, headers, post_id, linkslist,\
+ local_outputs, content, googleadress, rating, featured_photo_id):
+ """
+ Creates a WordPress post with pictures and content.
+
+ Args:
+ newdate2: The date of the post.
+ picchop (list): List of picture links to process.
+ title: The title of the post.
+ address: The address associated with the post.
+ headers: The headers for the HTTP request.
+ post_id: The ID of the post.
+ linkslist: List of links to pictures.
+ local_outputs: Local outputs for the post.
+ content: The content of the post.
+ googleadress: The Google address for the post.
+ rating: The rating of the post.
+ featured_photo_id: The ID of the featured photo.
+
+ Returns:
+ bool: True if the post creation is successful, False otherwise.
+ Raises:
+ AttributeError: If an error occurs during post creation or processing.
+ """
+
+ if not post_id:
+ addresshtml = re.sub(" ", ".",address)
+ googleadress = r""+address+r""
+ post_data = {
+ "title": title,
+ "content": googleadress+'\n\n'+content+'\n'+rating ,
+ "status": "publish", # Set to 'draft' if you want to save as a draft
+ "date": newdate2
+ }
+ try:
+ headers2 = headers
+ response = requests.post(env.wpAPOurl, json = post_data, headers=headers2,timeout=\
+ env.request_timeout)
+ if response.status_code != 201:
+ print ('Error: ',response, response.text)
+ else:
+ post_id_json = response.json()
+ post_id = post_id_json.get('id')
+ print (' New post has post_id = ',post_id)
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ else:
+ print (' Post already existed: Post ID : ',post_id)
+ for pic in picchop:
+ if pic != '':
+ picslice2 = pic.split("/")[-1]
+ picslice = picslice2.split(".")
+ picname = picslice[0]
+ caption =title
+ description = title+"\n"+address
+ print (' Found Picture: ',picname)
+ file_id, link = check_wordpress_media(picname, headers)
+ if file_id is False:
+ print(f' {str(picname)} was not already found in library, adding it')
+ image = {
+ "file": open(pic, "rb"),
+ "post": post_id,
+ "caption": caption,
+ "description": description
+ }
+ try:
+ image_response = requests.post(env.wpAPI + "/media", headers=headers, \
+ files=image,timeout=env.request_timeout)
+ except AttributeError as error:
+ print(f" An error uploading picture {picname} occurred:", \
+ type(error).__name__)
+ if image_response.status_code != 201 :
+ print (f' Error:Image {picname} wasnot successfully uploaded. response:'\
+ ,image_response)
+ else:
+ pic_dic=image_response.json()
+ file_id= pic_dic.get('id')
+ link = pic_dic.get('guid').get("rendered")
+ print (f' {picname} was successfully uploaded to website with ID: ',\
+ file_id, link)
+ try:
+ links_dict = {'file_id' : file_id , 'link' : link}
+ linkslist.append(links_dict)
+ except AttributeError as error:
+ print(f" An error adding to dictionary {file_id} {link} occurred:",\
+ type(error).__name__) # An error occurred:
+ else:
+ print (f' Photo {picname} was already in library and added to post with ID: \
+ {file_id} : {link}')
+ try:
+ image_response = requests.post(env.wpAPI + "/media/" + str(file_id),\
+ headers=headers, data={"post" : post_id},timeout=env.request_timeout)
+ except AttributeError as error:
+ print (' Error- Image ',picname,' was not attached to post. response: ',\
+ image_response+' '+type(error).__name__)
+ try:
+ post_response = requests.post(env.wpAPI + "/posts/" + str(post_id),\
+ headers=headers,timeout=env.request_timeout)
+ if link in post_response.text:
+ print (' Image link for ', picname, 'already in content of post: '\
+ ,post_id, post_response.text, link)
+ else:
+ linkslist.append({'file_id' : file_id , 'link' : link})
+ except AttributeError as error:
+ print(" An error loading the metadata from the post "+post_response.title+\
+ ' occurred: '+type(error).__name__)
+ first_mp4 = True
+ first_pic = True
+ fmedia = {}
+ contentpics = ""
+ for piclink in linkslist:
+ if piclink != '':
+ print (' Adding ', piclink['link'], ' to posting')
+ try:
+ ext = piclink['link'].split( '.')[-1]
+ if ext == 'mp4':
+ if first_mp4:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + \
+ r'" autoplay="true"]'
+ first_mp4 = False
+ else:
+ contentpics += '\n' +r'[evp_embed_video url="' + piclink['link'] + r'"]'
+ else:
+ contentpics+='\n '+r''
+ if first_pic:
+ fmedia = piclink['file_id']
+ first_pic = False
+ except AttributeError as error:
+ print("An error occurred:", type(error).__name__) # An error occurred:
+ return False
+ try:
+ if fmedia:
+ print ('Featured Media: ',fmedia)
+ else:
+ if linkslist:
+ fmedia = linkslist[0]['file_id']
+ business_url_list = local_outputs['postssession'].query(Posts).filter(Posts.name == title)\
+ .all()
+ business_url = f"{title}"
+ status_message = f'{str(title)}: Business website: {business_url}'
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress+'\n'+\
+ rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print (' ',response_piclinks)
+ if fmedia and fmedia != 0 and featured_photo_id and featured_photo_id !=0:
+ print (" Featured Media: "+str(featured_photo_id)+" "+str(fmedia)+" looks OK")
+ else:
+ print (" fmedia is still empty and need to populate")
+ if fmedia:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+googleadress\
+ +'\n'+rating+contentpics,"featured_media":fmedia,"rank_math_focus_keyword":\
+ title},headers=headers,timeout=env.request_timeout)
+ print (' Results of new results ID value : '+\
+ str(get_wordpress_featured_photo_id(post_id)))
+ else:
+ response_piclinks = requests.post(env.wpAPI+"/posts/"+ str(post_id), \
+ data={"content" : title+' - '+status_message+'\n\n'+content+'\n'+\
+ googleadress+'\n'+rating+contentpics,"rank_math_focus_keyword":title},\
+ headers=headers,timeout=env.request_timeout)
+ print ('Results of new results ID with no picture value : '+\
+ str(get_wordpress_featured_photo_id(post_id)))
+ except AttributeError as error:
+ print(" An error writing images to the post " + post_response.title + ' occurred:',\
+ type(error).__name__) # An error occurred')
+ return False
+ return True
+
+##################################################################################################
+
+def post_to_wordpress2(title,content,headers,date,rating,address,picslist,local_outputs):
+ """
+ Post to WordPress.
+
+ This function posts content to a WordPress site using the provided data.
+
+ Args:
+ title (str): The title of the post.
+ content (str): The content of the post.
+ headers: Headers for the request.
+ date (str): The date of the post.
+ rating (str): The rating of the post.
+ address (str): The address associated with the post.
+ picslist (list): A list of pictures for the post.
+ local_outputs: Outputs for the post.
+
+ Returns:
+ None
+"""
+ linkslist = ()
+ addresshtml = re.sub(" ", ".",address)
+ googleadress = r""+str(address)+r""
+ picchop = picslist[1:-1].replace(",","").replace("'","").split(" ")
+ print (' Figuring out date of Post : ',title)
+ #specifify the formatting of the date_string.
+ # formatting = '%b/%Y/%d'
+ date_string = date
+ newdate,newdate2,visitdate = get_wordpress_post_date_string(date_string,date)
+ post_id, post_link = check_wordpress_post(title,newdate2,headers,local_outputs)
+ if picslist and picslist != '':
+ content_pics = build_picslist(picchop,picslist,post_id) #file_id
+ featured_photo_id = get_wordpress_featured_photo_id(post_id)
+ print(f" Featured photo ID: for {title} post {post_id} is: {featured_photo_id}")
+ if env.block_google_maps is not True or env.forcegoogleupdate is True:
+ try:
+ database_update_row(title,"wpurl",post_link,"forceall",local_outputs)
+ except AttributeError as error :
+ print (f' Error: {error}')
+ else:
+
+ if post_id:
+ print (' Post already existed: Post ID : ',post_id)
+ print (' Found post for : '+title)
+ if env.force_web_create:
+ create_wordpress_post(newdate2,picchop,title,address,headers,post_id,linkslist,\
+ local_outputs,content,googleadress,rating,featured_photo_id)
+ #update_wordpress()
+ else:
+ print (' Found existing post but skipping updating post')
+ else:
+ create_wordpress_post(newdate2,picchop,title,address,headers,post_id,linkslist,\
+ local_outputs,content,googleadress,rating,featured_photo_id)
+ print (' Creating wordpress post from scratch for: '+title)
+ return True
+
+##################################################################################################
+
+def process_reviews2(outputs):
+ """
+ Processes reviews data, updates social media platforms, and writes data to files.
+
+ Args:
+ outputs: Data outputs containing reviews and social media information.
+
+ Returns:
+ None
+ """
+
+ # Process
+ webcount = xtwittercount = instagramcount = facebookcount = tiktokcount = 0
+# webcount=xtwittercount=instagramcount=yelpcount=threadscount=facebookcount=tiktokcount = 0
+ if env.datasource == 'db':
+ cols2 = ["num","name", "comment", 'rating','picsURL','picsLocalpath','source','date',
+ 'address','dictPostComplete']
+ rows_orig = list(outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
+ ttt = list(outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
+ ows_orig = list(outputs['data'])
+ rows_orig2 = list(outputs['xlsdf'].values)
+ rows3 = outputs['data'].iter_rows(min_row=1, max_row=outputs['data'])
+ rows4 = pd.DataFrame(outputs['xlsdf'])
+ rows5 = pd.DataFrame(outputs['posts'])
+ rows6 = pd.DataFrame(outputs['data'])
+# df2 = pd.DataFrame(outputs['xlsdf'].values, columns=cols2).iter_rows(min_row=1, max_row=outputs\
+# ['data'].max_row)
+# df3 = pd.DataFrame(outputs['xlsdf'].iter_rows(min_row=1, max_row=outputs['data'].max_row))
+# rows = [({0:p.id},{1:p.name}, { 2:p.comment}, {3: p.rating}, {4:p.picsURL},\
+# {5:p.picsLocalpath},{6:p.source},{7:p.date},{8:p.address},{9:p.dictPostComplete})\
+# for p in rows_orig]
+ # rows = list((outputs['data'].iter_rows(min_row=1, max_row=outputs['data'].max_row)))
+ rows = outputs['posts']
+ else:
+ rows_orig = outputs['posts']
+ rows = rows_orig
+ if env.google:
+ print('Configuration says to update google Reviews prior to processing them')
+ options = webdriver.ChromeOptions()
+ options.add_argument("--log-level=3")
+ #options.add_argument("--ignore-certificate-error")
+ options.add_argument("--ignore-certificate-errors-spki-list")
+ #options.add_argument("--ignore-ssl-errors")
+ if not env.showchrome:
+ options.add_argument("--headless")
+ # show browser or not ||| HEAD => 43.03 ||| No Head => 39 seg
+ options.add_argument("--lang=en-US")
+ options.add_argument("--disable-blink-features=AutomationControlled")
+ options.add_argument("--remote-debugging-pipe")
+ # Exclude the collection of enable-automation switches
+ options.add_experimental_option("excludeSwitches", ["enable-automation"])
+ # Turn-off userAutomationExtension
+ options.add_experimental_option("useAutomationExtension", False)
+ # Setting the driver path and requesting a page
+ caps = webdriver.DesiredCapabilities.CHROME.copy()
+ caps['acceptInsecureCerts'] = True
+ caps['acceptSslCerts'] = True
+ options.set_capability('cloud:options', caps)
+ #driver = webdriver.Chrome(desired_capabilities=caps)
+ if is_docker():
+ driver = webdriver.Remote("http://192.168.10.9:4444/wd/hub", options=options)
+ print ("IN A DOCKER CONTAINER, USING REMOTE CHROME")
+ else:
+ driver = webdriver.Chrome(options=options) # Firefox(options=options)
+ # Changing the property of the navigator value for webdriver to undefined
+ driver.execute_script("Object.defineProperty(navigator,'webdriver',\
+ {get:()=> undefined})")
+ driver.get(env.URL)
+ time.sleep(5)
+ google_scroll(counter_google(driver), driver)
+ webdata = get_google_data(driver,outputs)
+ if env.datasource == 'db':
+ write_to_database(webdata, outputs)
+ else:
+ write_to_xlsx2(webdata, outputs)
+ driver.close()
+ # outputs['data'].save(xls)
+ print('Done getting google reviews and writing them to xls file !')
+ else:
+ print ('Configuration says to skip creation of new reviews from google for this run')
+ print('Processing Reviews')
+ for processrow in rows:
+ if processrow.name != "name": # Skip header line of xls sheet
+ outputs['postssession'].query(Posts).filter(Posts.name == processrow.name).\
+ update({"google" : 1})
+ print ("Processing : ",processrow.name)
+ writtento = ast.literal_eval(processrow.dictPostComplete)
+ # Check to see if the website has already been written to according to the xls sheet,\
+ # if it has not... then process
+ if (writtento["web"] == 0 or writtento["instagram"]==0 or writtento["facebook"]==0 or\
+ writtento["xtwitter"]==0 or writtento["yelp"]==0 or writtento["tiktok"]==0 or \
+ writtento["threads"]==0 ) and (check_is_port_open(env.wpAPI)) and (env.web \
+ or env.instagram or env.yelp or env.xtwitter or env.tiktok or env.facebook or \
+ env.threads or env.google)and (processrow.comment is not None) :
+ if (env.web and processrow.web is False) or env.force_web_create is True:
+ #if writtento["web"] == 0 :
+ try:
+ #date_string = date
+ #newdate,newdate2,visitdate = get_wordpress_post_date_string(date_string,date)
+ post_id, post_link = get_wordpress_post_id_and_link(processrow.name,\
+ outputs['web'] )
+# post_id, post_link = check_wordpress_post(processrow.name,processrow.date,outputs['web'],outputs)
+ if env.forcegoogleupdate is True and env.block_google_maps is not True:
+ if post_link:
+ database_update_row(processrow.name,"wpurl",post_link,"forceall"\
+ ,outputs)
+ else:
+ print (' Error getting wordpress links to update databse')
+ except AttributeError as error :
+ print ('Could not check to see post already exists',error)
+ webcount=process_socials("web",processrow,outputs['web'],"post_to_wordpress",\
+ webcount, outputs)
+ webcount = 0 # force all web content get created asap
+ if env.instagram and processrow.instagram is False:
+ instagramcount = process_socials("instagram",processrow,outputs['web'],\
+ "post_to_instagram2",instagramcount, outputs)
+ if env.facebook and processrow.facebook is False :
+ facebookcount = process_socials("facebook",processrow,outputs['web'],\
+ "post_facebook3",facebookcount, outputs)
+ if env.xtwitter and processrow.xtwitter is False:
+ xtwittercount = process_socials("xtwitter",processrow,outputs['web'],\
+ "post_to_x2",xtwittercount, outputs)
+ if env.tiktok and processrow.tiktok is False:
+ tiktokcount = process_socials("tiktok",processrow,outputs['web'],\
+ "post_to_tiktok",tiktokcount, outputs)
+ return
+
+##################################################################################################
+
+def process_socials(social_name,social_post,headers,sub_process,social_count, local_outputs):
+ """Summary:
+ Function to process social media posts.
+
+ Explanation:
+ This function processes social media posts based on the provided parameters.
+
+ Args:
+ - social_name: The name of the social media platform.
+ - social_post: The post content for the social media platform.
+ - sub_process: The sub-process for posting.
+ - social_count: The count of social media posts.
+ - local_outputs: Dictionary containing outputs from the process.
+
+ Returns:
+ Count of the social that was selected
+ """
+ writtento = ast.literal_eval(social_post.dictPostComplete)
+ if (len(local_outputs['postssession'].query(Posts).filter(Posts.name == social_post.name,\
+ getattr(Posts, social_name) is True).all())==0) and ((local_outputs['postssession'].\
+ query(Posts).filter(Posts.name == social_post.name).all()[0].wpurl is not \
+ None)or social_name == 'web'):
+ if social_count < env.postsperrun or (social_name == 'web' and env.force_web_create is \
+ True):
+ try:
+ print(' Starting to generate ',social_name,' post')
+ new_social_post = eval(sub_process)(social_post.name, social_post.comment,\
+ headers, social_post.date, social_post.rating, social_post.address,\
+ social_post.picsLocalpath,local_outputs )
+ try:
+ print (' Start generating content to post to : ',social_post.name)
+ writtento[social_name] = 1
+ social_post.dictPostComplete = str(writtento)
+ except AttributeError as error:
+ print(" An error occurred setting value to go into Excel file:", type(error)\
+ .__name__)
+ print (' Success Posting to xtwitter: '+social_post.name)
+ if new_social_post:
+ social_count +=1
+ try:
+ print(' write to xls for :',social_name)
+ local_outputs['datawb'].save(env.xls)
+ print(' Successfully wrote to xls for social - ',social_name)
+ except AttributeError as error:
+ print(" An error occurred writing Excel file:", type(error).__name__)
+ try:
+ print(' write to DB for Social - ',social_name)
+ local_outputs['postssession'].query(Posts).filter(Posts.name == \
+ social_post.name).update({social_name : True})
+ local_outputs['postssession'].commit()
+ print(' Successfully wrote to database')
+ except AttributeError as error:
+ print(" An error occurred writing database", type(error).__name__)
+ except AttributeError as error:
+ print(' Error writing social - ',social_name,' post : ',error,social_post.name,\
+ social_post.comment, local_outputs,social_post.date, social_post.rating,\
+ social_post.address, social_post.picsLocalpath, writtento[social_name],\
+ type(error).__name__ )
+ else:
+ print (' Exceeded the number of social - ',social_name,' posts per run, skipping',\
+ social_post.name)
+ else:
+ print (' ',social_name,': Skipping posting for ',social_post.name,' previously written')
+ return social_count
+
+##################################################################################################
+
+if __name__ == "__main__":
+ print('starting ...')
+ preload()
+ print('making connections ...')
+ outputs = get_auth_connect()
+ process_reviews2(outputs)
+ print('Done!')
+
+##################################################################################################
+>>>>>>> 3e400170b0b98bf52e9ea9f820987028d15bb00e