Skip to content

Commit

Permalink
Merge pull request #128 from callum-fortune/solve-description-errors
Browse files Browse the repository at this point in the history
Simplifies the _set_description function fixing hashtags and mentions
  • Loading branch information
wkaisertexas authored Apr 25, 2024
2 parents 513e209 + 456c926 commit 145cf8d
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 47 deletions.
2 changes: 1 addition & 1 deletion examples/basic_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@

# upload video to TikTok
upload_video(FILENAME,
description="This is a video I just downloaded",
description="This is a #cool video I just downloaded. #wow #cool check it out on @tiktok",
cookies="cookies.txt")
6 changes: 2 additions & 4 deletions src/tiktok_uploader/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTM
visibility = "//div[@class='tiktok-select-selector']"
options = ["Public", "Friends", "Private"]

hashtags = "//div[@class='mentionSuggestions']//*[contains(text(), '{}')]"
mentions = "//div[contains(concat(' ', normalize-space(@class), ' '), 'user-id') and .='{}']/.."

mention_box = "//input[contains(concat(' ', normalize-space(@class), ' '), 'search-friends')]"
mention_box = "//div[contains(@class, 'mention-list-popover')]"
mention_box_user_id = "//span[contains(@class, 'user-id')]"

comment = "//label[.='Comment']/following-sibling::div/input"
duet = "//label[.='Duet']/following-sibling::div/input"
Expand Down
109 changes: 67 additions & 42 deletions src/tiktok_uploader/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
upload_video : Uploads a single TikTok video
upload_videos : Uploads multiple TikTok videos
"""

from os.path import abspath, exists
from typing import List
import time
import pytz
import datetime
import pyperclip
import threading

from selenium.webdriver.common.by import By
Expand Down Expand Up @@ -268,61 +268,81 @@ def _set_description(driver, description: str) -> None:

saved_description = description # save the description in case it fails

WebDriverWait(driver, config['implicit_wait']).until(EC.presence_of_element_located(
(By.XPATH, config['selectors']['upload']['description'])
))

desc = driver.find_element(By.XPATH, config['selectors']['upload']['description'])

desc.click()

# desc populates with filename before clearing
WebDriverWait(driver, config['explicit_wait']).until(lambda driver: desc.text != '')

desc.send_keys(Keys.END)
_clear(desc)

try:
while description:
nearest_mention = description.find('@')
nearest_hash = description.find('#')

if nearest_mention == 0 or nearest_hash == 0:
desc.send_keys('@' if nearest_mention == 0 else '#')

name = description[1:].split(' ')[0]
if nearest_mention == 0: # @ case
mention_xpath = config['selectors']['upload']['mention_box']
condition = EC.presence_of_element_located((By.XPATH, mention_xpath))
mention_box = WebDriverWait(driver, config['explicit_wait']).until(condition)
mention_box.send_keys(name)
else:
desc.send_keys(name)
WebDriverWait(driver, config['explicit_wait']).until(lambda driver: desc.text == '')

desc.click()

time.sleep(config['implicit_wait'])
time.sleep(1)

if nearest_mention == 0: # @ case
mention_xpath = config['selectors']['upload']['mentions'].format('@' + name)
condition = EC.presence_of_element_located((By.XPATH, mention_xpath))
else:
hashtag_xpath = config['selectors']['upload']['hashtags'].format(name)
condition = EC.presence_of_element_located((By.XPATH, hashtag_xpath))

# if the element never appears (timeout exception) remove the tag and continue
try:
elem = WebDriverWait(driver, config['implicit_wait']).until(condition)
except:
desc.send_keys(Keys.BACKSPACE * (len(name) + 1))
description = description[len(name) + 2:]
continue

ActionChains(driver).move_to_element(elem).click(elem).perform()
try:
words = description.split(" ")
for word in words:
if word[0] == "#":
desc.send_keys(word)
desc.send_keys(' ' + Keys.BACKSPACE)
WebDriverWait(driver, config['implicit_wait']).until(EC.presence_of_element_located(
(By.XPATH, config['selectors']['upload']['mention_box'])
))
desc.send_keys(Keys.ENTER)
elif word[0] == "@":
logger.debug(green('- Adding Mention: ' + word))
desc.send_keys(word)
desc.send_keys(' ')
time.sleep(1)
desc.send_keys(Keys.BACKSPACE)

WebDriverWait(driver, config['explicit_wait']).until(EC.presence_of_element_located(
(By.XPATH, config['selectors']['upload']['mention_box_user_id'])
))

found = False
waiting_interval = 0.5
timeout = 5
start_time = time.time()

while not found and (time.time() - start_time < timeout):

user_id_elements = driver.find_elements(By.XPATH, config['selectors']['upload']['mention_box_user_id'])
time.sleep(1)

for i in range(len(user_id_elements)):
user_id_element = user_id_elements[i]
if user_id_element and user_id_element.is_enabled:

username = user_id_element.text.split(" ")[0]
if username.lower() == word[1:].lower():
found = True
print("Matching User found : Clicking User")
for j in range(i):
desc.send_keys(Keys.DOWN)
desc.send_keys(Keys.ENTER)
break

if not found:
print(f"No match. Waiting for {waiting_interval} seconds...")
time.sleep(waiting_interval)

description = description[len(name) + 2:]
else:
min_index = _get_splice_index(nearest_mention, nearest_hash, description)
desc.send_keys(word + ' ')

pyperclip.copy(description[:min_index])
desc.send_keys(Keys.CONTROL, 'v')
description = description[min_index:]
except Exception as exception:
print('Failed to set description: ', exception)
_clear(desc)
desc.send_keys(saved_description) # if fail, use saved description

desc.send_keys(saved_description)

def _clear(element) -> None:
"""
Expand All @@ -335,7 +355,6 @@ def _clear(element) -> None:
"""
element.send_keys(2 * len(element.text) * Keys.BACKSPACE)


def _set_video(driver, path: str = '', num_retries: int = 3, **kwargs) -> None:
"""
Sets the video to upload
Expand All @@ -353,6 +372,12 @@ def _set_video(driver, path: str = '', num_retries: int = 3, **kwargs) -> None:
for _ in range(num_retries):
try:
_change_to_upload_iframe(driver)
# Wait For Input File
driverWait = WebDriverWait(driver, config['explicit_wait'])
upload_boxWait = EC.presence_of_element_located(
(By.XPATH, config['selectors']['upload']['upload_video'])
)
driverWait.until(upload_boxWait)
upload_box = driver.find_element(
By.XPATH, config['selectors']['upload']['upload_video']
)
Expand Down

0 comments on commit 145cf8d

Please sign in to comment.