tiktokautouploader 4.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tiktokautouploader/Js_assets/login.js +40 -0
- tiktokautouploader/Js_assets/package.json +12 -0
- tiktokautouploader/__init__.py +3 -0
- tiktokautouploader/function.py +857 -0
- tiktokautouploader-4.0.dist-info/METADATA +152 -0
- tiktokautouploader-4.0.dist-info/RECORD +8 -0
- tiktokautouploader-4.0.dist-info/WHEEL +5 -0
- tiktokautouploader-4.0.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
const { chromium } = require('playwright-extra')
|
2
|
+
|
3
|
+
|
4
|
+
const stealth = require('puppeteer-extra-plugin-stealth')()
|
5
|
+
|
6
|
+
chromium.use(stealth)
|
7
|
+
|
8
|
+
|
9
|
+
function sleep(time) {
|
10
|
+
return new Promise(resolve => setTimeout(resolve, time));
|
11
|
+
}
|
12
|
+
|
13
|
+
|
14
|
+
async function checkForRedirect(page) {
|
15
|
+
const currentUrl = page.url();
|
16
|
+
const pattern = /^https:\/\/www\.tiktok\.com\/foryou/;
|
17
|
+
return pattern.test(currentUrl);
|
18
|
+
}
|
19
|
+
|
20
|
+
(async () => {
|
21
|
+
let redirected = false;
|
22
|
+
const browser = await chromium.launch({ headless: false });
|
23
|
+
const page = await browser.newPage();
|
24
|
+
await page.goto('https://www.tiktok.com/login');
|
25
|
+
|
26
|
+
while (!redirected) {
|
27
|
+
redirected = await checkForRedirect(page);
|
28
|
+
if (!redirected) {
|
29
|
+
await sleep(1000);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
sleep(2000)
|
34
|
+
const cookies = await page.context().cookies();
|
35
|
+
const fs = require('fs');
|
36
|
+
fs.writeFileSync('TK_cookies.json', JSON.stringify(cookies, null, 2));
|
37
|
+
|
38
|
+
|
39
|
+
await browser.close();
|
40
|
+
})();
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"name": "tiktokautouploader-assets",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"scripts": {
|
5
|
+
"postinstall": "npx playwright install chromium"
|
6
|
+
},
|
7
|
+
"dependencies": {
|
8
|
+
"playwright": "^1.48.2",
|
9
|
+
"playwright-extra": "^4.3.6",
|
10
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2"
|
11
|
+
}
|
12
|
+
}
|
@@ -0,0 +1,857 @@
|
|
1
|
+
from playwright.sync_api import sync_playwright
|
2
|
+
import json
|
3
|
+
import time
|
4
|
+
import subprocess
|
5
|
+
from inference_sdk import InferenceHTTPClient
|
6
|
+
import pkg_resources
|
7
|
+
import requests
|
8
|
+
from PIL import Image
|
9
|
+
import sys
|
10
|
+
import os
|
11
|
+
import warnings
|
12
|
+
warnings.simplefilter("ignore")
|
13
|
+
|
14
|
+
|
15
|
+
def check_for_updates():
|
16
|
+
current_version = pkg_resources.get_distribution("tiktokautouploader").version
|
17
|
+
response = requests.get("https://pypi.org/pypi/tiktokautouploader/json")
|
18
|
+
|
19
|
+
if response.status_code == 200:
|
20
|
+
latest_version = response.json()["info"]["version"]
|
21
|
+
if current_version != latest_version:
|
22
|
+
print(f"WARNING: You are using version {current_version} of tiktokautouploader, "
|
23
|
+
f"PLEASE UPDATE TO LATEST VERSION {latest_version} FOR BEST EXPERIENCE.")
|
24
|
+
|
25
|
+
def login_warning(accountname):
|
26
|
+
print(f"NO COOKIES FILE FOUND FOR ACCOUNT {accountname}, PLEASE LOG-IN TO {accountname} WHEN PROMPTED")
|
27
|
+
|
28
|
+
def save_cookies(cookies):
|
29
|
+
with open('TK_cookies.json', 'w') as file:
|
30
|
+
json.dump(cookies, file, indent=4)
|
31
|
+
|
32
|
+
def check_expiry(accountname):
|
33
|
+
with open(f'TK_cookies_{accountname}.json', 'r') as file:
|
34
|
+
cookies = json.load(file)
|
35
|
+
|
36
|
+
current_time = int(time.time())
|
37
|
+
cookies_expire = []
|
38
|
+
expired = False
|
39
|
+
for cookie in cookies:
|
40
|
+
if cookie['name'] in ['sessionid', 'sid_tt', 'sessionid_ss', 'passport_auth_status']:
|
41
|
+
expiry = cookie.get('expires')
|
42
|
+
cookies_expire.append(expiry < current_time)
|
43
|
+
|
44
|
+
if all(cookies_expire):
|
45
|
+
expired = True
|
46
|
+
|
47
|
+
return expired
|
48
|
+
|
49
|
+
def run_javascript():
|
50
|
+
js_file_path = pkg_resources.resource_filename(__name__, 'Js_assets/login.js')
|
51
|
+
result = subprocess.run(['node', js_file_path], capture_output=True, text=True)
|
52
|
+
return result
|
53
|
+
|
54
|
+
def install_js_dependencies():
|
55
|
+
js_dir = pkg_resources.resource_filename(__name__, 'Js_assets')
|
56
|
+
node_modules_path = os.path.join(js_dir, 'node_modules')
|
57
|
+
|
58
|
+
if not os.path.exists(node_modules_path):
|
59
|
+
print("JavaScript dependencies not found. Installing...")
|
60
|
+
try:
|
61
|
+
subprocess.run(['npm', 'install', '--silent'], cwd=js_dir, check=True)
|
62
|
+
except subprocess.CalledProcessError as e:
|
63
|
+
print("An error occurred during npm installation.")
|
64
|
+
print(f"Error details: {e}")
|
65
|
+
else:
|
66
|
+
time.sleep(0.1)
|
67
|
+
|
68
|
+
|
69
|
+
def read_cookies(cookies_path):
|
70
|
+
cookie_read = False
|
71
|
+
try:
|
72
|
+
with open(cookies_path , 'r') as cookiefile:
|
73
|
+
cookies = json.load(cookiefile)
|
74
|
+
|
75
|
+
for cookie in cookies:
|
76
|
+
if cookie.get('sameSite') not in ['Strict', 'Lax', 'None']:
|
77
|
+
cookie['sameSite'] = 'Lax'
|
78
|
+
|
79
|
+
cookie_read = True
|
80
|
+
except:
|
81
|
+
sys.exit("ERROR: CANT READ COOKIES FILE")
|
82
|
+
|
83
|
+
return cookies, cookie_read
|
84
|
+
|
85
|
+
def detect_redirect(page):
|
86
|
+
redirect_detected = False
|
87
|
+
|
88
|
+
def on_response(response):
|
89
|
+
nonlocal redirect_detected
|
90
|
+
if response.request.redirected_from:
|
91
|
+
redirect_detected = True
|
92
|
+
|
93
|
+
page.on('response', on_response)
|
94
|
+
|
95
|
+
return redirect_detected
|
96
|
+
|
97
|
+
def understood_Qs(question):
|
98
|
+
understood_terms = {
|
99
|
+
'touchdowns' : 'football',
|
100
|
+
'orange and round': 'basketball',
|
101
|
+
'used in hoops': 'basketball',
|
102
|
+
'has strings': 'guitar',
|
103
|
+
'oval and inflatable': 'football',
|
104
|
+
'strumming': 'guitar',
|
105
|
+
'bounces': 'basketball',
|
106
|
+
'musical instrument': 'guitar',
|
107
|
+
'laces': 'football',
|
108
|
+
'bands': 'guitar',
|
109
|
+
'leather': 'football',
|
110
|
+
'leaves':'tree',
|
111
|
+
'pages': 'book',
|
112
|
+
'throwing': 'football',
|
113
|
+
'tossed in a spiral': 'football',
|
114
|
+
'spiky crown': 'pineapple',
|
115
|
+
'pigskin': 'football',
|
116
|
+
'photography': 'camera',
|
117
|
+
'lens': 'camera',
|
118
|
+
'grow': 'tree',
|
119
|
+
'captures images': 'camera',
|
120
|
+
'keeps doctors': 'apple',
|
121
|
+
'crown': 'pineapple',
|
122
|
+
'driven': 'car',
|
123
|
+
}
|
124
|
+
|
125
|
+
for key in understood_terms.keys():
|
126
|
+
if key in question:
|
127
|
+
item = understood_terms.get(key)
|
128
|
+
return item
|
129
|
+
|
130
|
+
return 'N.A'
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
def get_image_src(page):
|
135
|
+
image_url = page.get_attribute("img#captcha-verify-image", "src")
|
136
|
+
return image_url
|
137
|
+
|
138
|
+
def download_image(image_url):
|
139
|
+
response = requests.get(image_url)
|
140
|
+
image_path = "captcha_image.jpg"
|
141
|
+
with open(image_path, "wb") as f:
|
142
|
+
f.write(response.content)
|
143
|
+
return image_path
|
144
|
+
|
145
|
+
def run_inference_on_image_tougher(image_path, object):
|
146
|
+
|
147
|
+
k = 'n|KIeDZnRZiJ};iVHz;R'
|
148
|
+
rk = ''.join(chr((ord(c) - 3) % 256) for c in k)
|
149
|
+
|
150
|
+
CLIENT = InferenceHTTPClient(
|
151
|
+
api_url="https://detect.roboflow.com",
|
152
|
+
api_key=f"{rk}"
|
153
|
+
)
|
154
|
+
|
155
|
+
results = CLIENT.infer(image_path, model_id="captcha-2-6ehbe/2")
|
156
|
+
|
157
|
+
class_names = []
|
158
|
+
bounding_boxes = []
|
159
|
+
for obj in results['predictions']:
|
160
|
+
class_names.append(obj['class'])
|
161
|
+
bounding_boxes.append({
|
162
|
+
"x": obj['x'],
|
163
|
+
"y": obj['y'],
|
164
|
+
"width": obj['width'],
|
165
|
+
"height": obj['height']
|
166
|
+
})
|
167
|
+
|
168
|
+
bounding_box = []
|
169
|
+
class_to_click = object
|
170
|
+
for i, classes in enumerate(class_names):
|
171
|
+
if classes == class_to_click:
|
172
|
+
bounding_box.append(bounding_boxes[i])
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
return bounding_box
|
177
|
+
|
178
|
+
def run_inference_on_image(image_path):
|
179
|
+
|
180
|
+
k = 'n|KIeDZnRZiJ};iVHz;R'
|
181
|
+
rk = ''.join(chr((ord(c) - 3) % 256) for c in k)
|
182
|
+
|
183
|
+
CLIENT = InferenceHTTPClient(
|
184
|
+
api_url="https://detect.roboflow.com",
|
185
|
+
api_key=f"{rk}"
|
186
|
+
)
|
187
|
+
|
188
|
+
results = CLIENT.infer(image_path, model_id="tk-3nwi9/2")
|
189
|
+
|
190
|
+
class_names = []
|
191
|
+
bounding_boxes = []
|
192
|
+
for obj in results['predictions']:
|
193
|
+
class_names.append(obj['class'])
|
194
|
+
bounding_boxes.append({
|
195
|
+
"x": obj['x'],
|
196
|
+
"y": obj['y'],
|
197
|
+
"width": obj['width'],
|
198
|
+
"height": obj['height']
|
199
|
+
})
|
200
|
+
|
201
|
+
already_written = []
|
202
|
+
bounding_box = []
|
203
|
+
class_to_click = []
|
204
|
+
for i, detected_class in enumerate(class_names):
|
205
|
+
if detected_class in already_written:
|
206
|
+
class_to_click.append(detected_class)
|
207
|
+
bounding_box.append(bounding_boxes[i])
|
208
|
+
index = already_written.index(detected_class)
|
209
|
+
bounding_box.append(bounding_boxes[index])
|
210
|
+
|
211
|
+
already_written.append(detected_class)
|
212
|
+
|
213
|
+
found = False
|
214
|
+
if len(class_to_click) == 1:
|
215
|
+
found = True
|
216
|
+
|
217
|
+
return bounding_box, found
|
218
|
+
|
219
|
+
def convert_to_webpage_coordinates(bounding_boxes, image_x, image_y, image_height_web, image_width_web, image_height_real, image_width_real):
|
220
|
+
|
221
|
+
webpage_coordinates = []
|
222
|
+
for box in bounding_boxes:
|
223
|
+
x_box = box['x']
|
224
|
+
y_box = box['y']
|
225
|
+
rel_x = (x_box * image_width_web) / image_width_real
|
226
|
+
rel_y = (y_box * image_height_web) / image_height_real
|
227
|
+
x_cord = image_x + rel_x
|
228
|
+
y_cord = image_y + rel_y
|
229
|
+
|
230
|
+
webpage_coordinates.append((x_cord, y_cord))
|
231
|
+
|
232
|
+
return webpage_coordinates
|
233
|
+
|
234
|
+
def click_on_objects(page, object_coords):
|
235
|
+
for (x, y) in object_coords:
|
236
|
+
page.mouse.click(x, y)
|
237
|
+
time.sleep(0.5)
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
def upload_tiktok(video, description, accountname, hashtags=None, sound_name=None, sound_aud_vol='mix', schedule=None, day=None, copyrightcheck=False, suppressprint=False, headless=True, stealth=False):
|
242
|
+
|
243
|
+
"""
|
244
|
+
UPLOADS VIDEO TO TIKTOK
|
245
|
+
------------------------------------------------------------------------------------------------------------------------------------------------c
|
246
|
+
video (str) -> path to video to upload
|
247
|
+
description (str) -> description for video
|
248
|
+
accountname (str) -> account to upload on
|
249
|
+
hashtags (str)(array) -> hashtags for video
|
250
|
+
sound_name (str) -> name of tik tok sound to use for video
|
251
|
+
sound_aud_vol (str) -> volume of tik tok sound, 'main', 'mix' or 'background', check documentation for more info -> https://github.com/haziq-exe/TikTokAutoUploader
|
252
|
+
schedule (str) -> format HH:MM, your local time to upload video
|
253
|
+
day (int) -> day to schedule video for, check documentation for more info -> https://github.com/haziq-exe/TikTokAutoUploader
|
254
|
+
copyrightcheck (bool) -> include copyright check or not; CODE FAILS IF FAIL COPYRIGHT CHECK
|
255
|
+
suppressprint (bool) -> True means function doesnt print anything to provide updates on progress
|
256
|
+
headless (bool) -> run in headless mode or not
|
257
|
+
stealth (bool) -> will wait second(s) before each operation
|
258
|
+
--------------------------------------------------------------------------------------------------------------------------------------------
|
259
|
+
"""
|
260
|
+
try:
|
261
|
+
check_for_updates()
|
262
|
+
except:
|
263
|
+
time.sleep(0.1)
|
264
|
+
|
265
|
+
retries = 0
|
266
|
+
cookie_read = False
|
267
|
+
oldQ = 'N.A'
|
268
|
+
|
269
|
+
if accountname == None:
|
270
|
+
sys.exit("PLEASE ENTER NAME OF ACCOUNT TO POST ON, READ DOCUMENTATION FOR MORE INFO")
|
271
|
+
|
272
|
+
if os.path.exists(f'TK_cookies_{accountname}.json'):
|
273
|
+
cookies, cookie_read = read_cookies(cookies_path=f'TK_cookies_{accountname}.json')
|
274
|
+
expired = check_expiry(accountname=accountname)
|
275
|
+
if expired == True:
|
276
|
+
os.remove(f'TK_cookies_{accountname}.json')
|
277
|
+
print(f"COOKIES EXPIRED FOR ACCOUNT {accountname}, PLEASE LOG-IN AGAIN")
|
278
|
+
cookie_read = False
|
279
|
+
|
280
|
+
if cookie_read == False:
|
281
|
+
install_js_dependencies()
|
282
|
+
login_warning(accountname=accountname)
|
283
|
+
result = run_javascript()
|
284
|
+
os.rename('TK_cookies.json', f'TK_cookies_{accountname}.json')
|
285
|
+
|
286
|
+
cookies, cookie_read = read_cookies(f"TK_cookies_{accountname}.json")
|
287
|
+
if cookie_read == False:
|
288
|
+
sys.exit("ERROR READING COOKIES")
|
289
|
+
|
290
|
+
|
291
|
+
with sync_playwright() as p:
|
292
|
+
|
293
|
+
browser = p.firefox.launch(headless=headless)
|
294
|
+
context = browser.new_context()
|
295
|
+
context.add_cookies(cookies)
|
296
|
+
page = context.new_page()
|
297
|
+
url = 'https://www.tiktok.com/tiktokstudio/upload?from=upload&lang=en'
|
298
|
+
|
299
|
+
if suppressprint == False:
|
300
|
+
print(f"Uploading to account '{accountname}'")
|
301
|
+
|
302
|
+
while retries < 2:
|
303
|
+
try:
|
304
|
+
page.goto(url, timeout=30000)
|
305
|
+
except:
|
306
|
+
retries +=1
|
307
|
+
time.sleep(5)
|
308
|
+
if retries == 2:
|
309
|
+
sys.exit("ERROR: TIK TOK PAGE FAILED TO LOAD, try again.")
|
310
|
+
else:
|
311
|
+
break
|
312
|
+
|
313
|
+
detected = False
|
314
|
+
captcha = False
|
315
|
+
while detected == False:
|
316
|
+
if page.locator('.upload-text-container').is_visible():
|
317
|
+
detected = True
|
318
|
+
else:
|
319
|
+
if page.locator('div.VerifyBar___StyledDiv-sc-12zaxoy-0.hRJhHT').is_visible():
|
320
|
+
detected = True
|
321
|
+
captcha = True
|
322
|
+
else:
|
323
|
+
time.sleep(0.1)
|
324
|
+
|
325
|
+
if captcha == True:
|
326
|
+
image = get_image_src(page)
|
327
|
+
if image:
|
328
|
+
if suppressprint == False:
|
329
|
+
print("CAPTCHA DETECTED, Attempting to solve")
|
330
|
+
solved = False
|
331
|
+
attempts = 0
|
332
|
+
question = page.locator('div.VerifyBar___StyledDiv-sc-12zaxoy-0.hRJhHT').text_content()
|
333
|
+
while solved == False:
|
334
|
+
attempts += 1
|
335
|
+
start_time = time.time()
|
336
|
+
while question == oldQ:
|
337
|
+
question = page.locator('div.VerifyBar___StyledDiv-sc-12zaxoy-0.hRJhHT').text_content()
|
338
|
+
if time.time() - start_time > 2:
|
339
|
+
break
|
340
|
+
if 'Select 2 objects that are the same' in question or 'Select two objects that are the same' in question:
|
341
|
+
found = False
|
342
|
+
while found == False:
|
343
|
+
page.click('span.secsdk_captcha_refresh--text')
|
344
|
+
image = get_image_src(page)
|
345
|
+
img_path = download_image(image)
|
346
|
+
b_box, found = run_inference_on_image(image_path=img_path)
|
347
|
+
|
348
|
+
with Image.open(img_path) as img:
|
349
|
+
image_size = img.size
|
350
|
+
|
351
|
+
imageweb = page.locator('#captcha-verify-image')
|
352
|
+
imageweb.wait_for()
|
353
|
+
box = imageweb.bounding_box()
|
354
|
+
image_x = box['x']
|
355
|
+
image_y = box['y']
|
356
|
+
image_height_web = box['height']
|
357
|
+
image_width_web = box['width']
|
358
|
+
image_width_real, image_height_real = image_size
|
359
|
+
|
360
|
+
webpage_coords = convert_to_webpage_coordinates(b_box, image_x, image_y, image_height_web, image_width_web, image_height_real, image_width_real)
|
361
|
+
if not webpage_coords:
|
362
|
+
webpage_coords.append((image_x + 50, image_y + 50))
|
363
|
+
click_on_objects(page, webpage_coords)
|
364
|
+
page.click("div.verify-captcha-submit-button")
|
365
|
+
time.sleep(0.5)
|
366
|
+
if attempts > 5:
|
367
|
+
sys.exit("FAILED TO SOLVE CAPTCHA")
|
368
|
+
while showedup == False:
|
369
|
+
if page.locator("div.captcha_verify_message.captcha_verify_message-pass").is_visible():
|
370
|
+
solved = True
|
371
|
+
showedup = True
|
372
|
+
os.remove('captcha_image.jpg')
|
373
|
+
if page.locator("div.captcha_verify_message.captcha_verify_message-fail").is_visible():
|
374
|
+
showedup = True
|
375
|
+
oldQ = question
|
376
|
+
page.click('span.secsdk_captcha_refresh--text')
|
377
|
+
else:
|
378
|
+
objectclick = understood_Qs(question)
|
379
|
+
while objectclick == 'N.A':
|
380
|
+
oldQ = question
|
381
|
+
page.click('span.secsdk_captcha_refresh--text')
|
382
|
+
start_time = time.time()
|
383
|
+
runs = 0
|
384
|
+
while question == oldQ:
|
385
|
+
runs += 1
|
386
|
+
question = page.locator('div.VerifyBar___StyledDiv-sc-12zaxoy-0.hRJhHT').text_content()
|
387
|
+
if runs > 1:
|
388
|
+
time.sleep(1)
|
389
|
+
if time.time() - start_time > 2:
|
390
|
+
break
|
391
|
+
objectclick = understood_Qs(question)
|
392
|
+
image = get_image_src(page)
|
393
|
+
img_path = download_image(image)
|
394
|
+
b_box = run_inference_on_image_tougher(image_path=img_path, object=objectclick)
|
395
|
+
|
396
|
+
with Image.open(img_path) as img:
|
397
|
+
image_size = img.size
|
398
|
+
|
399
|
+
imageweb = page.locator('#captcha-verify-image')
|
400
|
+
imageweb.wait_for()
|
401
|
+
box = imageweb.bounding_box()
|
402
|
+
image_x = box['x']
|
403
|
+
image_y = box['y']
|
404
|
+
image_height_web = box['height']
|
405
|
+
image_width_web = box['width']
|
406
|
+
image_width_real, image_height_real = image_size
|
407
|
+
|
408
|
+
webpage_coords = convert_to_webpage_coordinates(b_box, image_x, image_y, image_height_web, image_width_web, image_height_real, image_width_real)
|
409
|
+
if not webpage_coords:
|
410
|
+
webpage_coords.append((image_x + 50, image_y + 50))
|
411
|
+
click_on_objects(page, webpage_coords)
|
412
|
+
page.click("div.verify-captcha-submit-button")
|
413
|
+
time.sleep(1)
|
414
|
+
if attempts > 20:
|
415
|
+
sys.exit("FAILED TO SOLVE CAPTCHA")
|
416
|
+
showedup = False
|
417
|
+
while showedup == False:
|
418
|
+
if page.locator("div.captcha_verify_message.captcha_verify_message-pass").is_visible():
|
419
|
+
solved = True
|
420
|
+
showedup = True
|
421
|
+
os.remove('captcha_image.jpg')
|
422
|
+
if suppressprint == False:
|
423
|
+
print("CAPTCHA SOLVED")
|
424
|
+
if page.locator("div.captcha_verify_message.captcha_verify_message-fail").is_visible():
|
425
|
+
showedup = True
|
426
|
+
oldQ = question
|
427
|
+
page.click('span.secsdk_captcha_refresh--text')
|
428
|
+
|
429
|
+
|
430
|
+
try:
|
431
|
+
page.set_input_files('input[type="file"][accept="video/*"]', f'{video}')
|
432
|
+
except:
|
433
|
+
sys.exit("ERROR: FAILED TO INPUT FILE. Possible Issues: Wifi too slow, file directory wrong, or check documentation to see if captcha is solvable")
|
434
|
+
page.wait_for_selector('div[data-contents="true"]')
|
435
|
+
page.click('div[data-contents="true"]')
|
436
|
+
if suppressprint == False:
|
437
|
+
print("Entered File, waiting for tiktok to load onto their server, this may take a couple of minutes, depending on your video length")
|
438
|
+
time.sleep(0.5)
|
439
|
+
if description == None:
|
440
|
+
sys.exit("ERROR: PLEASE INCLUDE A DESCRIPTION")
|
441
|
+
|
442
|
+
for _ in range(len(video) + 2):
|
443
|
+
page.keyboard.press("Backspace")
|
444
|
+
page.keyboard.press("Delete")
|
445
|
+
|
446
|
+
time.sleep(0.5)
|
447
|
+
|
448
|
+
page.keyboard.type(description)
|
449
|
+
|
450
|
+
for _ in range(3):
|
451
|
+
page.keyboard.press("Enter")
|
452
|
+
|
453
|
+
if hashtags != None:
|
454
|
+
for hashtag in hashtags:
|
455
|
+
if hashtag[0] != '#':
|
456
|
+
hashtag = "#" + hashtag
|
457
|
+
|
458
|
+
page.keyboard.type(hashtag)
|
459
|
+
time.sleep(0.5)
|
460
|
+
try:
|
461
|
+
if stealth == True:
|
462
|
+
time.sleep(2)
|
463
|
+
page.click(f'span.hash-tag-topic:has-text("{hashtag}")', timeout=1000)
|
464
|
+
except:
|
465
|
+
try:
|
466
|
+
page.click('span.hash-tag-topic', timeout=1000)
|
467
|
+
except:
|
468
|
+
page.keyboard.press("Backspace")
|
469
|
+
try:
|
470
|
+
page.click('span.hash-tag-topic', timeout=1000)
|
471
|
+
except:
|
472
|
+
if suppressprint == False:
|
473
|
+
print(f"Tik tok hashtag not working for {hashtag}, moving onto next")
|
474
|
+
for _ in range(len(hashtag)):
|
475
|
+
page.keyboard.press("Backspace")
|
476
|
+
|
477
|
+
if suppressprint == False:
|
478
|
+
print("Description and Hashtags added")
|
479
|
+
|
480
|
+
try:
|
481
|
+
page.wait_for_selector('button:has-text("Post")[aria-disabled="false"]', timeout=12000000)
|
482
|
+
except:
|
483
|
+
sys.exit("ERROR: TIK TOK TOOK TOO LONG TO UPLOAD YOUR FILE (>20min). Try again, if issue persists then try a lower file size or different wifi connection")
|
484
|
+
|
485
|
+
time.sleep(0.2)
|
486
|
+
if suppressprint == False:
|
487
|
+
print("Tik tok done loading file onto servers")
|
488
|
+
|
489
|
+
if (schedule == None) and (day != None):
|
490
|
+
sys.exit("ERROR: CANT SCHEDULE FOR ANOTHER DAY USING 'day' WITHOUT ALSO INCLUDING TIME OF UPLOAD WITH 'schedule'; PLEASE ALSO INCLUDE TIME WITH 'schedule' PARAMETER")
|
491
|
+
|
492
|
+
if schedule != None:
|
493
|
+
try:
|
494
|
+
hour = schedule[0:2]
|
495
|
+
minute = schedule[3:]
|
496
|
+
if (int(minute) % 5) != 0:
|
497
|
+
sys.exit("MINUTE FORMAT ERROR: PLEASE MAKE SURE MINUTE YOU SCHEDULE AT IS A MULTIPLE OF 5 UNTIL 60 (i.e: 40), VIDEO SAVED AS DRAFT")
|
498
|
+
|
499
|
+
except:
|
500
|
+
sys.exit("SCHEDULE TIME ERROR: PLEASE MAKE SURE YOUR SCHEDULE TIME IS A STRING THAT FOLLOWS THE 24H FORMAT 'HH:MM', VIDEO SAVED AS DRAFT")
|
501
|
+
|
502
|
+
page.locator('label:has-text("Schedule")').click()
|
503
|
+
if stealth==True:
|
504
|
+
time.sleep(2)
|
505
|
+
visible = False
|
506
|
+
while visible == False:
|
507
|
+
if page.locator('button:has-text("Allow")').nth(0).is_visible():
|
508
|
+
if stealth == True:
|
509
|
+
time.sleep(1)
|
510
|
+
page.locator('button:has-text("Allow")').nth(0).click()
|
511
|
+
visible = True
|
512
|
+
time.sleep(0.1)
|
513
|
+
else:
|
514
|
+
if page.locator('div.TUXTextInputCore-trailingIconWrapper').nth(1).is_visible():
|
515
|
+
visible = True
|
516
|
+
time.sleep(0.1)
|
517
|
+
if day != None:
|
518
|
+
if stealth==True:
|
519
|
+
time.sleep(1)
|
520
|
+
page.locator('div.TUXTextInputCore-leadingIconWrapper:has(svg > path[d="M15 3a1 1 0 0 0-1 1v3h-1.4c-3.36 0-5.04 0-6.32.65a6 6 0 0 0-2.63 2.63C3 11.56 3 13.24 3 16.6v16.8c0 3.36 0 5.04.65 6.32a6 6 0 0 0 2.63 2.63c1.28.65 2.96.65 6.32.65h22.8c3.36 0 5.04 0 6.32-.65a6 6 0 0 0 2.63-2.63c.65-1.28.65-2.96.65-6.32V16.6c0-3.36 0-5.04-.65-6.32a6 6 0 0 0-2.63-2.63C40.44 7 38.76 7 35.4 7H34V4a1 1 0 0 0-1-1h-2a1 1 0 0 0-1 1v3H18V4a1 1 0 0 0-1-1h-2Zm-2.4 8H14v3a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-3h12v3a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-3h1.4c1.75 0 2.82 0 3.62.07a5.11 5.11 0 0 1 .86.14h.03a2 2 0 0 1 .88.91 5.11 5.11 0 0 1 .14.86c.07.8.07 1.87.07 3.62v1.9H7v-1.9c0-1.75 0-2.82.07-3.62a5.12 5.12 0 0 1 .14-.86v-.03a2 2 0 0 1 .88-.87l.03-.01a5.11 5.11 0 0 1 .86-.14c.8-.07 1.87-.07 3.62-.07ZM7 22.5h34v10.9c0 1.75 0 2.82-.07 3.62a5.11 5.11 0 0 1-.14.86v.03a2 2 0 0 1-.88.87l-.03.01a5.11 5.11 0 0 1-.86.14c-.8.07-1.87.07-3.62.07H12.6c-1.75 0-2.82 0-3.62-.07a5.11 5.11 0 0 1-.89-.15 2 2 0 0 1-.87-.87l-.01-.03a5.12 5.12 0 0 1-.14-.86C7 36.22 7 35.15 7 33.4V22.5Z"])').click()
|
521
|
+
time.sleep(0.2)
|
522
|
+
try:
|
523
|
+
if stealth==True:
|
524
|
+
time.sleep(1)
|
525
|
+
page.locator(f'span.day.valid:text-is("{day}")').click()
|
526
|
+
except:
|
527
|
+
sys.exit("SCHEDULE DAY ERROR: ERROR WITH SCHEDULED DAY, read documentation for more information on format of day")
|
528
|
+
try:
|
529
|
+
time.sleep(0.2)
|
530
|
+
page.locator('div.TUXTextInputCore-leadingIconWrapper:has(svg > path[d="M24 2a22 22 0 1 0 0 44 22 22 0 0 0 0-44ZM6 24a18 18 0 1 1 36 0 18 18 0 0 1-36 0Z"])').click()
|
531
|
+
time.sleep(0.2)
|
532
|
+
page.locator(f'.tiktok-timepicker-option-text.tiktok-timepicker-right:text-is("{minute}")').scroll_into_view_if_needed()
|
533
|
+
time.sleep(0.2)
|
534
|
+
if stealth==True:
|
535
|
+
time.sleep(2)
|
536
|
+
page.locator(f'.tiktok-timepicker-option-text.tiktok-timepicker-right:text-is("{minute}")').click()
|
537
|
+
time.sleep(0.2)
|
538
|
+
if page.locator("div.tiktok-timepicker-time-picker-container").is_visible():
|
539
|
+
time.sleep(0.1)
|
540
|
+
else:
|
541
|
+
page.locator('div.TUXTextInputCore-leadingIconWrapper:has(svg > path[d="M24 2a22 22 0 1 0 0 44 22 22 0 0 0 0-44ZM6 24a18 18 0 1 1 36 0 18 18 0 0 1-36 0Z"])').click()
|
542
|
+
page.locator(f'.tiktok-timepicker-option-text.tiktok-timepicker-left:text-is("{hour}")').scroll_into_view_if_needed()
|
543
|
+
if stealth == True:
|
544
|
+
time.sleep(2)
|
545
|
+
page.locator(f'.tiktok-timepicker-option-text.tiktok-timepicker-left:text-is("{hour}")').click()
|
546
|
+
time.sleep(1)
|
547
|
+
|
548
|
+
if suppressprint == False:
|
549
|
+
print("Done scheduling video")
|
550
|
+
|
551
|
+
except:
|
552
|
+
sys.exit("SCHEDULING ERROR: VIDEO SAVED AS DRAFT")
|
553
|
+
|
554
|
+
sound_fail = False
|
555
|
+
if sound_name != None:
|
556
|
+
try:
|
557
|
+
if stealth == True:
|
558
|
+
time.sleep(2)
|
559
|
+
page.click("div.TUXButton-label:has-text('Edit video')")
|
560
|
+
except:
|
561
|
+
sound_fail = True
|
562
|
+
if sound_fail == False:
|
563
|
+
page.wait_for_selector("input.search-bar-input")
|
564
|
+
page.fill(f"input.search-bar-input", f"{sound_name}")
|
565
|
+
time.sleep(0.2)
|
566
|
+
if stealth == True:
|
567
|
+
time.sleep(2)
|
568
|
+
page.click("div.TUXButton-label:has-text('Search')")
|
569
|
+
try:
|
570
|
+
page.wait_for_selector('div.music-card-container')
|
571
|
+
if stealth == True:
|
572
|
+
time.sleep(0.5)
|
573
|
+
page.click("div.music-card-container")
|
574
|
+
page.wait_for_selector("div.TUXButton-label:has-text('Use')")
|
575
|
+
if stealth == True:
|
576
|
+
time.sleep(1)
|
577
|
+
page.click("div.TUXButton-label:has-text('Use')")
|
578
|
+
except:
|
579
|
+
sys.exit(f"ERROR: SOUND '{sound_name}' NOT FOUND")
|
580
|
+
try:
|
581
|
+
page.wait_for_selector('img[src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMSAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgNy41MDE2QzAgNi42NzMxNyAwLjY3MTU3MyA2LjAwMTYgMS41IDYuMDAxNkgzLjU3NzA5QzMuODY4MDUgNi4wMDE2IDQuMTQ0NTggNS44NzQ4OCA0LjMzNDU1IDUuNjU0NDlMOC43NDI1NSAwLjU0MDUyQzkuMzQ3OCAtMC4xNjE2NjggMTAuNSAwLjI2NjM3NCAxMC41IDEuMTkzNDFWMTguOTY3MkMxMC41IDE5Ljg3NDUgOS4zODg5NCAyMC4zMTI5IDguNzY5NDIgMTkuNjVMNC4zMzE3OSAxNC45MDIxQzQuMTQyNjkgMTQuNjk5OCAzLjg3ODE2IDE0LjU4NDkgMy42MDEyMiAxNC41ODQ5SDEuNUMwLjY3MTU3MyAxNC41ODQ5IDAgMTMuOTEzNCAwIDEzLjA4NDlWNy41MDE2Wk01Ljg0OTQ1IDYuOTYwMjdDNS4yNzk1NiA3LjYyMTQzIDQuNDQ5OTcgOC4wMDE2IDMuNTc3MDkgOC4wMDE2SDJWMTIuNTg0OUgzLjYwMTIyQzQuNDMyMDMgMTIuNTg0OSA1LjIyNTY0IDEyLjkyOTUgNS43OTI5NSAxMy41MzY0TDguNSAxNi40MzI4VjMuODg1MjJMNS44NDk0NSA2Ljk2MDI3WiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPHBhdGggZD0iTTEzLjUxNSA3LjE5MTE5QzEzLjM0MjQgNi45NzU1OSAxMy4zMzk5IDYuNjYwNTYgMTMuNTM1MiA2LjQ2NTNMMTQuMjQyMyA1Ljc1ODE5QzE0LjQzNzYgNS41NjI5MyAxNC43NTU4IDUuNTYxNzUgMTQuOTM1NiA1Ljc3MTM2QzE2Ljk5NTkgOC4xNzM2MiAxNi45OTU5IDExLjgyOCAxNC45MzU2IDE0LjIzMDNDMTQuNzU1OCAxNC40Mzk5IDE0LjQzNzYgMTQuNDM4NyAxNC4yNDIzIDE0LjI0MzVMMTMuNTM1MiAxMy41MzY0QzEzLjMzOTkgMTMuMzQxMSAxMy4zNDI0IDEzLjAyNjEgMTMuNTE1IDEyLjgxMDVDMTQuODEzIDExLjE4ODUgMTQuODEzIDguODEzMTIgMTMuNTE1IDcuMTkxMTlaIiBmaWxsPSIjMTYxODIzIiBmaWxsLW9wYWNpdHk9IjAuNiIvPgo8cGF0aCBkPSJNMTYuNzE3MiAxNi43MTgzQzE2LjUyMTkgMTYuNTIzMSAxNi41MjMxIDE2LjIwNzQgMTYuNzA3MiAxNi4wMDE3QzE5LjcyNTcgMTIuNjMgMTkuNzI1NyA3LjM3MTY4IDE2LjcwNzIgNC4wMDAwMUMxNi41MjMxIDMuNzk0MjcgMTYuNTIxOSAzLjQ3ODU4IDE2LjcxNzIgMy4yODMzMkwxNy40MjQzIDIuNTc2MjFDMTcuNjE5NSAyLjM4MDk1IDE3LjkzNyAyLjM4MDIgMTguMTIzMyAyLjU4NDA4QzIxLjkwOTkgNi43MjkyNiAyMS45MDk5IDEzLjI3MjQgMTguMTIzMyAxNy40MTc2QzE3LjkzNyAxNy42MjE1IDE3LjYxOTUgMTcuNjIwNyAxNy40MjQzIDE3LjQyNTVMMTYuNzE3MiAxNi43MTgzWiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPC9zdmc+Cg=="]')
|
582
|
+
if stealth == True:
|
583
|
+
time.sleep(1)
|
584
|
+
page.click('img[src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMSAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgNy41MDE2QzAgNi42NzMxNyAwLjY3MTU3MyA2LjAwMTYgMS41IDYuMDAxNkgzLjU3NzA5QzMuODY4MDUgNi4wMDE2IDQuMTQ0NTggNS44NzQ4OCA0LjMzNDU1IDUuNjU0NDlMOC43NDI1NSAwLjU0MDUyQzkuMzQ3OCAtMC4xNjE2NjggMTAuNSAwLjI2NjM3NCAxMC41IDEuMTkzNDFWMTguOTY3MkMxMC41IDE5Ljg3NDUgOS4zODg5NCAyMC4zMTI5IDguNzY5NDIgMTkuNjVMNC4zMzE3OSAxNC45MDIxQzQuMTQyNjkgMTQuNjk5OCAzLjg3ODE2IDE0LjU4NDkgMy42MDEyMiAxNC41ODQ5SDEuNUMwLjY3MTU3MyAxNC41ODQ5IDAgMTMuOTEzNCAwIDEzLjA4NDlWNy41MDE2Wk01Ljg0OTQ1IDYuOTYwMjdDNS4yNzk1NiA3LjYyMTQzIDQuNDQ5OTcgOC4wMDE2IDMuNTc3MDkgOC4wMDE2SDJWMTIuNTg0OUgzLjYwMTIyQzQuNDMyMDMgMTIuNTg0OSA1LjIyNTY0IDEyLjkyOTUgNS43OTI5NSAxMy41MzY0TDguNSAxNi40MzI4VjMuODg1MjJMNS44NDk0NSA2Ljk2MDI3WiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPHBhdGggZD0iTTEzLjUxNSA3LjE5MTE5QzEzLjM0MjQgNi45NzU1OSAxMy4zMzk5IDYuNjYwNTYgMTMuNTM1MiA2LjQ2NTNMMTQuMjQyMyA1Ljc1ODE5QzE0LjQzNzYgNS41NjI5MyAxNC43NTU4IDUuNTYxNzUgMTQuOTM1NiA1Ljc3MTM2QzE2Ljk5NTkgOC4xNzM2MiAxNi45OTU5IDExLjgyOCAxNC45MzU2IDE0LjIzMDNDMTQuNzU1OCAxNC40Mzk5IDE0LjQzNzYgMTQuNDM4NyAxNC4yNDIzIDE0LjI0MzVMMTMuNTM1MiAxMy41MzY0QzEzLjMzOTkgMTMuMzQxMSAxMy4zNDI0IDEzLjAyNjEgMTMuNTE1IDEyLjgxMDVDMTQuODEzIDExLjE4ODUgMTQuODEzIDguODEzMTIgMTMuNTE1IDcuMTkxMTlaIiBmaWxsPSIjMTYxODIzIiBmaWxsLW9wYWNpdHk9IjAuNiIvPgo8cGF0aCBkPSJNMTYuNzE3MiAxNi43MTgzQzE2LjUyMTkgMTYuNTIzMSAxNi41MjMxIDE2LjIwNzQgMTYuNzA3MiAxNi4wMDE3QzE5LjcyNTcgMTIuNjMgMTkuNzI1NyA3LjM3MTY4IDE2LjcwNzIgNC4wMDAwMUMxNi41MjMxIDMuNzk0MjcgMTYuNTIxOSAzLjQ3ODU4IDE2LjcxNzIgMy4yODMzMkwxNy40MjQzIDIuNTc2MjFDMTcuNjE5NSAyLjM4MDk1IDE3LjkzNyAyLjM4MDIgMTguMTIzMyAyLjU4NDA4QzIxLjkwOTkgNi43MjkyNiAyMS45MDk5IDEzLjI3MjQgMTguMTIzMyAxNy40MTc2QzE3LjkzNyAxNy42MjE1IDE3LjYxOTUgMTcuNjIwNyAxNy40MjQzIDE3LjQyNTVMMTYuNzE3MiAxNi43MTgzWiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPC9zdmc+Cg=="]')
|
585
|
+
time.sleep(0.5)
|
586
|
+
sliders = page.locator("input.scaleInput")
|
587
|
+
|
588
|
+
if sound_aud_vol == 'background':
|
589
|
+
slider1 = sliders.nth(0)
|
590
|
+
bounding_box1 = slider1.bounding_box()
|
591
|
+
if bounding_box1:
|
592
|
+
x1 = bounding_box1["x"] + (bounding_box1["width"] * 0.92)
|
593
|
+
y1 = bounding_box1["y"] + bounding_box1["height"] / 2
|
594
|
+
if stealth == True:
|
595
|
+
time.sleep(1)
|
596
|
+
page.mouse.click(x1, y1)
|
597
|
+
|
598
|
+
slider2 = sliders.nth(1)
|
599
|
+
bounding_box2 = slider2.bounding_box()
|
600
|
+
if bounding_box2:
|
601
|
+
x2 = bounding_box2["x"] + (bounding_box2["width"] * 0.097)
|
602
|
+
y2 = bounding_box2["y"] + bounding_box2["height"] / 2
|
603
|
+
if stealth == True:
|
604
|
+
time.sleep(1)
|
605
|
+
page.mouse.click(x2, y2)
|
606
|
+
|
607
|
+
if sound_aud_vol == 'main':
|
608
|
+
slider1 = sliders.nth(0)
|
609
|
+
bounding_box1 = slider1.bounding_box()
|
610
|
+
if bounding_box1:
|
611
|
+
x1 = bounding_box1["x"] + (bounding_box1["width"] * 0.092)
|
612
|
+
y1 = bounding_box1["y"] + bounding_box1["height"] / 2
|
613
|
+
if stealth == True:
|
614
|
+
time.sleep(1)
|
615
|
+
page.mouse.click(x1, y1)
|
616
|
+
slider2 = sliders.nth(1)
|
617
|
+
bounding_box2 = slider2.bounding_box()
|
618
|
+
if bounding_box2:
|
619
|
+
x2 = bounding_box2["x"] + (bounding_box2["width"] * 0.92)
|
620
|
+
y2 = bounding_box2["y"] + bounding_box2["height"] / 2
|
621
|
+
if stealth == True:
|
622
|
+
time.sleep(1)
|
623
|
+
page.mouse.click(x2, y2)
|
624
|
+
except:
|
625
|
+
sys.exit("ERROR ADJUSTING SOUND VOLUME: please try again.")
|
626
|
+
|
627
|
+
page.wait_for_selector("div.TUXButton-label:has-text('Save edit')")
|
628
|
+
if stealth == True:
|
629
|
+
time.sleep(1)
|
630
|
+
page.click("div.TUXButton-label:has-text('Save edit')")
|
631
|
+
if suppressprint == False:
|
632
|
+
print("Added sound")
|
633
|
+
|
634
|
+
if sound_fail == False:
|
635
|
+
page.wait_for_selector('div[data-contents="true"]')
|
636
|
+
|
637
|
+
if copyrightcheck == True:
|
638
|
+
if stealth == True:
|
639
|
+
time.sleep(1)
|
640
|
+
page.locator('div[data-e2e="copyright_container"] span[data-part="thumb"]').click()
|
641
|
+
while copyrightcheck == True:
|
642
|
+
time.sleep(0.2)
|
643
|
+
if page.locator("span" ,has_text="No issues detected.").is_visible():
|
644
|
+
if suppressprint == False:
|
645
|
+
print("Copyright check complete")
|
646
|
+
break
|
647
|
+
if page.locator("span", has_text="Copyright issues detected.").is_visible():
|
648
|
+
sys.exit("COPYRIGHT CHECK FAILED: VIDEO SAVED AS DRAFT, COPYRIGHT AUDIO DETECTED FROM TIKTOK")
|
649
|
+
|
650
|
+
|
651
|
+
try:
|
652
|
+
if schedule == None:
|
653
|
+
if stealth == True:
|
654
|
+
time.sleep(1)
|
655
|
+
page.click('button:has-text("Post")', timeout=10000)
|
656
|
+
uploaded = False
|
657
|
+
checks = 0
|
658
|
+
while uploaded == False:
|
659
|
+
if page.locator(':has-text("Leaving the page does not interrupt")').nth(0).is_visible():
|
660
|
+
time.sleep(0.1)
|
661
|
+
break
|
662
|
+
time.sleep(0.2)
|
663
|
+
checks += 1
|
664
|
+
if checks == 25:
|
665
|
+
break
|
666
|
+
else:
|
667
|
+
if stealth == True:
|
668
|
+
time.sleep(1)
|
669
|
+
page.click('button:has-text("Schedule")', timeout=10000)
|
670
|
+
uploaded = False
|
671
|
+
checks = 0
|
672
|
+
while uploaded == False:
|
673
|
+
if page.locator(':has-text("Leaving the page does not interrupt")').nth(0).is_visible():
|
674
|
+
time.sleep(0.2)
|
675
|
+
break
|
676
|
+
time.sleep(0.2)
|
677
|
+
checks += 1
|
678
|
+
if checks == 25:
|
679
|
+
break
|
680
|
+
if suppressprint == False:
|
681
|
+
print("Done uploading video, NOTE: it may take a minute or two to show on TikTok")
|
682
|
+
except:
|
683
|
+
time.sleep(2)
|
684
|
+
sys.exit("POSSIBLE ERROR UPLOADING: Cannot confirm if uploaded successfully, Please check account in a minute or two to confirm.")
|
685
|
+
time.sleep(1)
|
686
|
+
|
687
|
+
page.close()
|
688
|
+
else:
|
689
|
+
try:
|
690
|
+
if stealth == True:
|
691
|
+
time.sleep(1)
|
692
|
+
page.click('button:has-text("Save draft")', timeout=10000)
|
693
|
+
except:
|
694
|
+
sys.exit("SAVE AS DRAFT BUTTON NOT FOUND; Please try account that has ability to save as draft")
|
695
|
+
|
696
|
+
time.sleep(0.5)
|
697
|
+
page.close()
|
698
|
+
|
699
|
+
browser = p.chromium.launch(headless=headless)
|
700
|
+
|
701
|
+
context = browser.new_context()
|
702
|
+
context.add_cookies(cookies)
|
703
|
+
page = context.new_page()
|
704
|
+
url2 = 'https://www.tiktok.com/tiktokstudio/content?tab=draft'
|
705
|
+
|
706
|
+
while retries < 2:
|
707
|
+
try:
|
708
|
+
page.goto(url2, timeout=30000)
|
709
|
+
except:
|
710
|
+
retries +=1
|
711
|
+
time.sleep(5)
|
712
|
+
if retries == 2:
|
713
|
+
sys.exit("ERROR: TIK TOK PAGE FAILED TO LOAD, try again.")
|
714
|
+
else:
|
715
|
+
break
|
716
|
+
|
717
|
+
try:
|
718
|
+
page.wait_for_selector("path[d='M37.37 4.85a4.01 4.01 0 0 0-.99-.79 3 3 0 0 0-2.72 0c-.45.23-.81.6-1 .79a9 9 0 0 1-.04.05l-19.3 19.3c-1.64 1.63-2.53 2.52-3.35 3.47a36 36 0 0 0-4.32 6.16c-.6 1.1-1.14 2.24-2.11 4.33l-.3.6c-.4.75-.84 1.61-.8 2.43a2.5 2.5 0 0 0 2.37 2.36c.82.05 1.68-.4 2.44-.79l.59-.3c2.09-.97 3.23-1.5 4.33-2.11a36 36 0 0 0 6.16-4.32c.95-.82 1.84-1.71 3.47-3.34l19.3-19.3.05-.06a3 3 0 0 0 .78-3.71c-.22-.45-.6-.81-.78-1l-.02-.02-.03-.03-3.67-3.67a8.7 8.7 0 0 1-.06-.05ZM16.2 26.97 35.02 8.15l2.83 2.83L19.03 29.8c-1.7 1.7-2.5 2.5-3.33 3.21a32 32 0 0 1-7.65 4.93 32 32 0 0 1 4.93-7.65c.73-.82 1.51-1.61 3.22-3.32Z']")
|
719
|
+
if stealth == True:
|
720
|
+
time.sleep(1)
|
721
|
+
page.click("path[d='M37.37 4.85a4.01 4.01 0 0 0-.99-.79 3 3 0 0 0-2.72 0c-.45.23-.81.6-1 .79a9 9 0 0 1-.04.05l-19.3 19.3c-1.64 1.63-2.53 2.52-3.35 3.47a36 36 0 0 0-4.32 6.16c-.6 1.1-1.14 2.24-2.11 4.33l-.3.6c-.4.75-.84 1.61-.8 2.43a2.5 2.5 0 0 0 2.37 2.36c.82.05 1.68-.4 2.44-.79l.59-.3c2.09-.97 3.23-1.5 4.33-2.11a36 36 0 0 0 6.16-4.32c.95-.82 1.84-1.71 3.47-3.34l19.3-19.3.05-.06a3 3 0 0 0 .78-3.71c-.22-.45-.6-.81-.78-1l-.02-.02-.03-.03-3.67-3.67a8.7 8.7 0 0 1-.06-.05ZM16.2 26.97 35.02 8.15l2.83 2.83L19.03 29.8c-1.7 1.7-2.5 2.5-3.33 3.21a32 32 0 0 1-7.65 4.93 32 32 0 0 1 4.93-7.65c.73-.82 1.51-1.61 3.22-3.32Z']")
|
722
|
+
page.wait_for_selector('div[data-contents="true"]')
|
723
|
+
time.sleep(0.2)
|
724
|
+
except:
|
725
|
+
sys.exit("ERROR ADDING SOUND: Video saved as draft")
|
726
|
+
|
727
|
+
if sound_name != None:
|
728
|
+
if stealth == True:
|
729
|
+
time.sleep(1)
|
730
|
+
page.click("div.TUXButton-label:has-text('Edit video')")
|
731
|
+
page.wait_for_selector("input.search-bar-input")
|
732
|
+
page.fill(f"input.search-bar-input", f"{sound_name}")
|
733
|
+
time.sleep(0.2)
|
734
|
+
if stealth == True:
|
735
|
+
time.sleep(1)
|
736
|
+
page.click("div.TUXButton-label:has-text('Search')")
|
737
|
+
try:
|
738
|
+
page.wait_for_selector('div.music-card-container')
|
739
|
+
if stealth == True:
|
740
|
+
time.sleep(1)
|
741
|
+
page.click("div.music-card-container")
|
742
|
+
page.wait_for_selector("div.TUXButton-label:has-text('Use')")
|
743
|
+
if stealth == True:
|
744
|
+
time.sleep(1)
|
745
|
+
page.click("div.TUXButton-label:has-text('Use')")
|
746
|
+
except:
|
747
|
+
sys.exit(f"ERROR: SOUND '{sound_name}' NOT FOUND")
|
748
|
+
try:
|
749
|
+
page.wait_for_selector('img[src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMSAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgNy41MDE2QzAgNi42NzMxNyAwLjY3MTU3MyA2LjAwMTYgMS41IDYuMDAxNkgzLjU3NzA5QzMuODY4MDUgNi4wMDE2IDQuMTQ0NTggNS44NzQ4OCA0LjMzNDU1IDUuNjU0NDlMOC43NDI1NSAwLjU0MDUyQzkuMzQ3OCAtMC4xNjE2NjggMTAuNSAwLjI2NjM3NCAxMC41IDEuMTkzNDFWMTguOTY3MkMxMC41IDE5Ljg3NDUgOS4zODg5NCAyMC4zMTI5IDguNzY5NDIgMTkuNjVMNC4zMzE3OSAxNC45MDIxQzQuMTQyNjkgMTQuNjk5OCAzLjg3ODE2IDE0LjU4NDkgMy42MDEyMiAxNC41ODQ5SDEuNUMwLjY3MTU3MyAxNC41ODQ5IDAgMTMuOTEzNCAwIDEzLjA4NDlWNy41MDE2Wk01Ljg0OTQ1IDYuOTYwMjdDNS4yNzk1NiA3LjYyMTQzIDQuNDQ5OTcgOC4wMDE2IDMuNTc3MDkgOC4wMDE2SDJWMTIuNTg0OUgzLjYwMTIyQzQuNDMyMDMgMTIuNTg0OSA1LjIyNTY0IDEyLjkyOTUgNS43OTI5NSAxMy41MzY0TDguNSAxNi40MzI4VjMuODg1MjJMNS44NDk0NSA2Ljk2MDI3WiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPHBhdGggZD0iTTEzLjUxNSA3LjE5MTE5QzEzLjM0MjQgNi45NzU1OSAxMy4zMzk5IDYuNjYwNTYgMTMuNTM1MiA2LjQ2NTNMMTQuMjQyMyA1Ljc1ODE5QzE0LjQzNzYgNS41NjI5MyAxNC43NTU4IDUuNTYxNzUgMTQuOTM1NiA1Ljc3MTM2QzE2Ljk5NTkgOC4xNzM2MiAxNi45OTU5IDExLjgyOCAxNC45MzU2IDE0LjIzMDNDMTQuNzU1OCAxNC40Mzk5IDE0LjQzNzYgMTQuNDM4NyAxNC4yNDIzIDE0LjI0MzVMMTMuNTM1MiAxMy41MzY0QzEzLjMzOTkgMTMuMzQxMSAxMy4zNDI0IDEzLjAyNjEgMTMuNTE1IDEyLjgxMDVDMTQuODEzIDExLjE4ODUgMTQuODEzIDguODEzMTIgMTMuNTE1IDcuMTkxMTlaIiBmaWxsPSIjMTYxODIzIiBmaWxsLW9wYWNpdHk9IjAuNiIvPgo8cGF0aCBkPSJNMTYuNzE3MiAxNi43MTgzQzE2LjUyMTkgMTYuNTIzMSAxNi41MjMxIDE2LjIwNzQgMTYuNzA3MiAxNi4wMDE3QzE5LjcyNTcgMTIuNjMgMTkuNzI1NyA3LjM3MTY4IDE2LjcwNzIgNC4wMDAwMUMxNi41MjMxIDMuNzk0MjcgMTYuNTIxOSAzLjQ3ODU4IDE2LjcxNzIgMy4yODMzMkwxNy40MjQzIDIuNTc2MjFDMTcuNjE5NSAyLjM4MDk1IDE3LjkzNyAyLjM4MDIgMTguMTIzMyAyLjU4NDA4QzIxLjkwOTkgNi43MjkyNiAyMS45MDk5IDEzLjI3MjQgMTguMTIzMyAxNy40MTc2QzE3LjkzNyAxNy42MjE1IDE3LjYxOTUgMTcuNjIwNyAxNy40MjQzIDE3LjQyNTVMMTYuNzE3MiAxNi43MTgzWiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPC9zdmc+Cg=="]')
|
750
|
+
if stealth == True:
|
751
|
+
time.sleep(1)
|
752
|
+
page.click('img[src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMSAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgNy41MDE2QzAgNi42NzMxNyAwLjY3MTU3MyA2LjAwMTYgMS41IDYuMDAxNkgzLjU3NzA5QzMuODY4MDUgNi4wMDE2IDQuMTQ0NTggNS44NzQ4OCA0LjMzNDU1IDUuNjU0NDlMOC43NDI1NSAwLjU0MDUyQzkuMzQ3OCAtMC4xNjE2NjggMTAuNSAwLjI2NjM3NCAxMC41IDEuMTkzNDFWMTguOTY3MkMxMC41IDE5Ljg3NDUgOS4zODg5NCAyMC4zMTI5IDguNzY5NDIgMTkuNjVMNC4zMzE3OSAxNC45MDIxQzQuMTQyNjkgMTQuNjk5OCAzLjg3ODE2IDE0LjU4NDkgMy42MDEyMiAxNC41ODQ5SDEuNUMwLjY3MTU3MyAxNC41ODQ5IDAgMTMuOTEzNCAwIDEzLjA4NDlWNy41MDE2Wk01Ljg0OTQ1IDYuOTYwMjdDNS4yNzk1NiA3LjYyMTQzIDQuNDQ5OTcgOC4wMDE2IDMuNTc3MDkgOC4wMDE2SDJWMTIuNTg0OUgzLjYwMTIyQzQuNDMyMDMgMTIuNTg0OSA1LjIyNTY0IDEyLjkyOTUgNS43OTI5NSAxMy41MzY0TDguNSAxNi40MzI4VjMuODg1MjJMNS44NDk0NSA2Ljk2MDI3WiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPHBhdGggZD0iTTEzLjUxNSA3LjE5MTE5QzEzLjM0MjQgNi45NzU1OSAxMy4zMzk5IDYuNjYwNTYgMTMuNTM1MiA2LjQ2NTNMMTQuMjQyMyA1Ljc1ODE5QzE0LjQzNzYgNS41NjI5MyAxNC43NTU4IDUuNTYxNzUgMTQuOTM1NiA1Ljc3MTM2QzE2Ljk5NTkgOC4xNzM2MiAxNi45OTU5IDExLjgyOCAxNC45MzU2IDE0LjIzMDNDMTQuNzU1OCAxNC40Mzk5IDE0LjQzNzYgMTQuNDM4NyAxNC4yNDIzIDE0LjI0MzVMMTMuNTM1MiAxMy41MzY0QzEzLjMzOTkgMTMuMzQxMSAxMy4zNDI0IDEzLjAyNjEgMTMuNTE1IDEyLjgxMDVDMTQuODEzIDExLjE4ODUgMTQuODEzIDguODEzMTIgMTMuNTE1IDcuMTkxMTlaIiBmaWxsPSIjMTYxODIzIiBmaWxsLW9wYWNpdHk9IjAuNiIvPgo8cGF0aCBkPSJNMTYuNzE3MiAxNi43MTgzQzE2LjUyMTkgMTYuNTIzMSAxNi41MjMxIDE2LjIwNzQgMTYuNzA3MiAxNi4wMDE3QzE5LjcyNTcgMTIuNjMgMTkuNzI1NyA3LjM3MTY4IDE2LjcwNzIgNC4wMDAwMUMxNi41MjMxIDMuNzk0MjcgMTYuNTIxOSAzLjQ3ODU4IDE2LjcxNzIgMy4yODMzMkwxNy40MjQzIDIuNTc2MjFDMTcuNjE5NSAyLjM4MDk1IDE3LjkzNyAyLjM4MDIgMTguMTIzMyAyLjU4NDA4QzIxLjkwOTkgNi43MjkyNiAyMS45MDk5IDEzLjI3MjQgMTguMTIzMyAxNy40MTc2QzE3LjkzNyAxNy42MjE1IDE3LjYxOTUgMTcuNjIwNyAxNy40MjQzIDE3LjQyNTVMMTYuNzE3MiAxNi43MTgzWiIgZmlsbD0iIzE2MTgyMyIgZmlsbC1vcGFjaXR5PSIwLjYiLz4KPC9zdmc+Cg=="]')
|
753
|
+
time.sleep(0.5)
|
754
|
+
sliders = page.locator("input.scaleInput")
|
755
|
+
|
756
|
+
if sound_aud_vol == 'background':
|
757
|
+
slider1 = sliders.nth(0)
|
758
|
+
bounding_box1 = slider1.bounding_box()
|
759
|
+
if bounding_box1:
|
760
|
+
x1 = bounding_box1["x"] + (bounding_box1["width"] * 0.92)
|
761
|
+
y1 = bounding_box1["y"] + bounding_box1["height"] / 2
|
762
|
+
if stealth == True:
|
763
|
+
time.sleep(1)
|
764
|
+
page.mouse.click(x1, y1)
|
765
|
+
|
766
|
+
slider2 = sliders.nth(1)
|
767
|
+
bounding_box2 = slider2.bounding_box()
|
768
|
+
if bounding_box2:
|
769
|
+
x2 = bounding_box2["x"] + (bounding_box2["width"] * 0.097)
|
770
|
+
y2 = bounding_box2["y"] + bounding_box2["height"] / 2
|
771
|
+
if stealth == True:
|
772
|
+
time.sleep(1)
|
773
|
+
page.mouse.click(x2, y2)
|
774
|
+
|
775
|
+
if sound_aud_vol == 'main':
|
776
|
+
slider1 = sliders.nth(0)
|
777
|
+
bounding_box1 = slider1.bounding_box()
|
778
|
+
if bounding_box1:
|
779
|
+
x1 = bounding_box1["x"] + (bounding_box1["width"] * 0.092)
|
780
|
+
y1 = bounding_box1["y"] + bounding_box1["height"] / 2
|
781
|
+
if stealth == True:
|
782
|
+
time.sleep(1)
|
783
|
+
page.mouse.click(x1, y1)
|
784
|
+
slider2 = sliders.nth(1)
|
785
|
+
bounding_box2 = slider2.bounding_box()
|
786
|
+
if bounding_box2:
|
787
|
+
x2 = bounding_box2["x"] + (bounding_box2["width"] * 0.92)
|
788
|
+
y2 = bounding_box2["y"] + bounding_box2["height"] / 2
|
789
|
+
if stealth == True:
|
790
|
+
time.sleep(1)
|
791
|
+
page.mouse.click(x2, y2)
|
792
|
+
except:
|
793
|
+
sys.exit("ERROR ADJUSTING SOUND VOLUME: please try again.")
|
794
|
+
|
795
|
+
page.wait_for_selector("div.TUXButton-label:has-text('Save edit')")
|
796
|
+
if stealth == True:
|
797
|
+
time.sleep(1)
|
798
|
+
page.click("div.TUXButton-label:has-text('Save edit')")
|
799
|
+
if suppressprint == False:
|
800
|
+
print("Added sound")
|
801
|
+
|
802
|
+
|
803
|
+
page.wait_for_selector('div[data-contents="true"]')
|
804
|
+
|
805
|
+
if copyrightcheck == True:
|
806
|
+
if stealth == True:
|
807
|
+
time.sleep(1)
|
808
|
+
page.locator('div[data-e2e="copyright_container"] span[data-part="thumb"]').click()
|
809
|
+
while copyrightcheck == True:
|
810
|
+
time.sleep(0.2)
|
811
|
+
if page.locator("span", has_text="No issues detected.").is_visible():
|
812
|
+
if suppressprint == False:
|
813
|
+
print("Copyright check complete")
|
814
|
+
break
|
815
|
+
if page.locator('span', has_text="Copyright issues detected.").is_visible():
|
816
|
+
sys.exit("COPYRIGHT CHECK FAILED: VIDEO SAVED AS DRAFT, COPYRIGHT AUDIO DETECTED FROM TIKTOK")
|
817
|
+
|
818
|
+
|
819
|
+
try:
|
820
|
+
if schedule == None:
|
821
|
+
if stealth == True:
|
822
|
+
time.sleep(1)
|
823
|
+
page.click('button:has-text("Post")', timeout=10000)
|
824
|
+
uploaded = False
|
825
|
+
checks = 0
|
826
|
+
while uploaded == False:
|
827
|
+
if page.locator(':has-text("Leaving the page does not interrupt")').nth(0).is_visible():
|
828
|
+
time.sleep(0.2)
|
829
|
+
break
|
830
|
+
time.sleep(0.2)
|
831
|
+
checks += 1
|
832
|
+
if checks == 25:
|
833
|
+
break
|
834
|
+
else:
|
835
|
+
if stealth == True:
|
836
|
+
time.sleep(1)
|
837
|
+
page.click('button:has-text("Schedule")', timeout=10000)
|
838
|
+
uploaded = False
|
839
|
+
checks = 0
|
840
|
+
while uploaded == False:
|
841
|
+
if page.locator(':has-text("Leaving the page does not interrupt")').nth(0).is_visible():
|
842
|
+
time.sleep(0.1)
|
843
|
+
break
|
844
|
+
time.sleep(0.2)
|
845
|
+
checks += 1
|
846
|
+
if checks == 25:
|
847
|
+
break
|
848
|
+
if suppressprint == False:
|
849
|
+
print("Done uploading video, NOTE: it may take a minute or two to show on TikTok")
|
850
|
+
except:
|
851
|
+
time.sleep(2)
|
852
|
+
sys.exit("POSSIBLE ERROR UPLOADING: Cannot confirm if uploaded successfully, Please check account in a minute or two to confirm.")
|
853
|
+
time.sleep(1)
|
854
|
+
|
855
|
+
page.close()
|
856
|
+
|
857
|
+
return "Completed"
|
@@ -0,0 +1,152 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: tiktokautouploader
|
3
|
+
Version: 4.0
|
4
|
+
Summary: Upload or schedule videos to TikTok with viral TikTok sounds and hashtags.
|
5
|
+
Project-URL: Homepage, https://github.com/haziq-exe/TikTokAutoUploader
|
6
|
+
Author-email: HAZIQ <haziqmk123@gmail.com>
|
7
|
+
License-File: LICENSE.md
|
8
|
+
Keywords: autoupload,tiktok,tiktokautoupload
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
16
|
+
Requires-Dist: inference>=0.18.1
|
17
|
+
Requires-Dist: pillow>=8.0.0
|
18
|
+
Requires-Dist: playwright>=1.0.0
|
19
|
+
Requires-Dist: requests>=2.0.0
|
20
|
+
Description-Content-Type: text/markdown
|
21
|
+
|
22
|
+
<div align="center">
|
23
|
+
<h1>tiktokautouploader</h1>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
|
27
|
+
### AUTOMATE TIKTOK UPLOADS 🤖. USE TRENDING SOUNDS 🔊, ADD WORKING HASHTAGS 💯, SCHEDULE UPLOADS 🗓️, AUTOSOLVES CAPTCHAS 🧠, AND MORE 🎁
|
28
|
+
|
29
|
+
[](https://pypi.org/project/tiktokautouploader/) [](https://opensource.org/licenses/MIT)
|
30
|
+
|
31
|
+
<p align="center">
|
32
|
+
<img src="READMEimage/READMEGIF.gif" alt="" width="900"/>
|
33
|
+
</p>
|
34
|
+
|
35
|
+
## 🚀 Features
|
36
|
+
|
37
|
+
- **🔐 Bypass/Auto Solve Captchas:** No need to worry about any captchas interrupting the process, they'll be solved!
|
38
|
+
- **🎵 Use TikTok Sounds:** Go viral by seamlessly adding popular TikTok sounds to your videos.
|
39
|
+
- **🗓 Schedule Uploads:** Upload videos at specific times or upto 10 days in advance with our scheduling feature.
|
40
|
+
- **🔍 Copyright Check:** Ensure your video is safe from copyright claims before uploading.
|
41
|
+
- **🏷 Add Working Hashtags:** Increase your reach by adding effective hashtags that actually work.
|
42
|
+
- **⏰ Cutdown on upload time:** Upload to TikTok with way less hassle and much more speed using our library.
|
43
|
+
- **📝 Upload to different accounts:** Stay organized and on top of multiple different accounts with our multi-account functionality.
|
44
|
+
|
45
|
+
⭐️ If you like this project please feel free to star it, Thank you.
|
46
|
+
|
47
|
+
## 📦 Installation
|
48
|
+
|
49
|
+
1. **Python Installation:** Install the package using `pip`:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
pip install tiktokautouploader
|
53
|
+
```
|
54
|
+
|
55
|
+
**NOTE:** IF YOU HAVE INSTALLED BEFORE, PLEASE MAKE SURE YOU UPGRADE TO THE LATEST VERSION.
|
56
|
+
|
57
|
+
---
|
58
|
+
|
59
|
+
## ⚙️ Pre-requisites
|
60
|
+
|
61
|
+
1. **Node.js:** You must have Node.js installed on your system, as some parts of this package rely on JavaScript code. If you don't have Node.js installed, you can download it from [nodejs.org](https://nodejs.org/).
|
62
|
+
|
63
|
+
- **Note:** The necessary JavaScript dependencies (`playwright`,`playwright-extra`, `puppeteer-extra-plugin-stealth`) will be AUTOMATICALLY installed the first time you run the function, so you don't need to install them manually. Make sure that `npm` (Node.js package manager) is available in your system's PATH.
|
64
|
+
|
65
|
+
|
66
|
+
2. **Browser Binaries:** If you don't have them already, you'll need to install the browser binaries for `playwright`. This library uses chromium and firefox.
|
67
|
+
|
68
|
+
to do so, just run the following command AFTER installing the package:
|
69
|
+
|
70
|
+
```bash
|
71
|
+
python -m playwright install
|
72
|
+
```
|
73
|
+
|
74
|
+
**NOTE:** If you want to add sounds to your TikTok, you MUST have the ability to save drafts. If you don't want to add sounds then you don't need this feature.
|
75
|
+
|
76
|
+
|
77
|
+
## 📝 Quick-Start
|
78
|
+
|
79
|
+
**NOTE:** It is highly recommended you read DOCUMENTATION.md before using the library.
|
80
|
+
The first time you run the code for an account, you will be prompted to log-in, this will only occur the first time the function is used for the account. Check documentation for more info.
|
81
|
+
|
82
|
+
## Upload with hashtags
|
83
|
+
|
84
|
+
```python
|
85
|
+
from tiktokautouploader import upload_tiktok
|
86
|
+
|
87
|
+
video_path = 'path/to/your/video.mp4'
|
88
|
+
description = 'Check out my latest TikTok video!'
|
89
|
+
accountname = 'mytiktokaccount'
|
90
|
+
hashtags = ['#fun', '#viral']
|
91
|
+
|
92
|
+
upload_tiktok(video=video_path, description=description, accountname=accountname, hashtags=hashtags)
|
93
|
+
|
94
|
+
```
|
95
|
+
|
96
|
+
### Upload with TikTok Sound
|
97
|
+
|
98
|
+
```python
|
99
|
+
upload_tiktok(video=video_path, description=description, accountname=accountname, sound_name='trending_sound', sound_aud_vol='main')
|
100
|
+
```
|
101
|
+
|
102
|
+
PLEASE READ DOCUMENTATION FOR MORE INFO.
|
103
|
+
|
104
|
+
### Schedule an Upload
|
105
|
+
|
106
|
+
```python
|
107
|
+
upload_tiktok(video=video_path, description=description, accountname=accountname, schedule='03:10', day=11)
|
108
|
+
```
|
109
|
+
|
110
|
+
PLEASE READ DOCUMENTATION FOR MORE INFO
|
111
|
+
|
112
|
+
### Perform Copyright Check Before Uploading
|
113
|
+
|
114
|
+
```python
|
115
|
+
upload_tiktok(video=video_path, description=description, accountname=accountname, hashtags=hashtags, copyrightcheck=True)
|
116
|
+
```
|
117
|
+
|
118
|
+
## 🎯 Why Choose `autotiktokuploader`?
|
119
|
+
|
120
|
+
- **No more captchas:** Fully automated uploads without interruptions, If captchas do show up, no worries, they will be solved. (read documentation for more info)
|
121
|
+
- **Maximize your reach:** Add popular sounds and effective hashtags that work to boost visibility and go viral!
|
122
|
+
- **Stay compliant:** Built-in copyright checks to avoid unforeseen takedowns.
|
123
|
+
- **Convenient scheduling:** Post at the right time, even when you're away!
|
124
|
+
- **Much faster than manually uploading:** Drastically reduce the time you need to upload videos, just click one button and be done much quicker!
|
125
|
+
- **Upload to different account:** Stay on top of all your TikTok accounts with our multi-account functionality!
|
126
|
+
|
127
|
+
## 🛠 Dependencies
|
128
|
+
|
129
|
+
This library requires the following dependencies:
|
130
|
+
|
131
|
+
- `playwright`
|
132
|
+
- `requests`
|
133
|
+
- `Pillow`
|
134
|
+
- `scikit-learn`
|
135
|
+
- `inference`
|
136
|
+
|
137
|
+
These will be automatically installed when you install the package.
|
138
|
+
|
139
|
+
## 👤 Author
|
140
|
+
|
141
|
+
Created by **Haziq**. Feel free to reach out at [haziqmk123@gmail.com](mailto:haziqmk123@gmail.com)
|
142
|
+
|
143
|
+
## 📄 License
|
144
|
+
|
145
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE.md) file for details.
|
146
|
+
|
147
|
+
## 📮 Related Projects
|
148
|
+
|
149
|
+
If you liked this project please check out my use case showcase project that generates TikToks and uploads them using 'tiktokautouploader'
|
150
|
+
|
151
|
+
[TikTokGenerator](https://github.com/haziq-exe/TikTokGenerator)
|
152
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
tiktokautouploader/__init__.py,sha256=u7OWCK_u68ST8dfrkSF4Yw44CJOzV9NXI6ASRuoDfmE,64
|
2
|
+
tiktokautouploader/function.py,sha256=fKS8bm6yzvP9QXO_Y8gAcZufOIhA_G2WsSwM_xH0KmM,46918
|
3
|
+
tiktokautouploader/Js_assets/login.js,sha256=SLhtPYo8ZfTRUnbR7Xqp084lSuAOqIWUxi75FlFH3vs,966
|
4
|
+
tiktokautouploader/Js_assets/package.json,sha256=aNbwSOpEpDUlplSuXugHVeN11riVwV4ofVkRPwHzbLs,273
|
5
|
+
tiktokautouploader-4.0.dist-info/METADATA,sha256=7C6hDX0w_QKgybBMx756B3BqzuVQL1rCeSUP7dsWe9I,6125
|
6
|
+
tiktokautouploader-4.0.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
7
|
+
tiktokautouploader-4.0.dist-info/licenses/LICENSE.md,sha256=hYds_VJIpnS5gC73WhuWk2IY_e9BWjuEJthQCb9ThyU,1073
|
8
|
+
tiktokautouploader-4.0.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) [2024] [HAZIQ KHALID]
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|