Skip to content

Commit 4455b69

Browse files
committed
V0.1.0
1 parent 66da618 commit 4455b69

9 files changed

Lines changed: 64 additions & 26 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Customized items
2+
test.py
3+
14
# Byte-compiled / optimized / DLL files
25
__pycache__/
36
*.py[cod]

README.md

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
1-
# TikTok Uploader
1+
# ⬆️ TikTok Uploader
2+
3+
![Downloads](https://img.shields.io/github/downloads/wkaisertexas/tiktok-uploader/total)
4+
25
A selenium-based uploader for TikTok Videos
36

47
## Usage
58

69
While Tik Tok is pretty good about blocking bots (giving "too many requests" with FireFox's default installation"), simply copying your session tokens is enough to bypass this restriction and be able to upload your videos.
710

11+
```bash
12+
$ tiktok_uploader -v video.mp4 -d "this is my description" -c cookies.txt
13+
```
14+
15+
```python
16+
upload_video('video.mp4', description='this is my description', cookies='cookies.txt') # single video
17+
18+
# Multiple Videos
19+
videos = [
20+
{'path': 'video.mp4', 'description': 'this is my description'},
21+
{'path': 'video2.mp4', 'description': 'this is also my description'}
22+
]
23+
auth = AuthBackend(cookies='cookies.txt')
24+
upload_videos(videos=videos, auth=auth)
25+
```
826
### Uploading videos
927

1028
This library revolves around the 'upload_video' function which takes in a list of videos which have **filenames** and **descriptions** and are passed as follows:
@@ -33,7 +51,9 @@ Finally, pass the saved file path to `upload_videos`.
3351
upload_videos(cookies='cookies.txt')
3452
```
3553

36-
> Optionally, if you would like to pass your own cookies you may do as an array of dictionaries with keys `name`, `value`, `domain`, `path` and `expiry` though there really is no need
54+
> Optionally, if you would like to pass your own cookies you may do as an array of dictionaries with keys `name`, `value`, `domain`, `path` and `expiry`
55+
56+
> The login script does have a `login_accounts` function, but this gets detected by the
3757
3858
#### Login-based Authentication
3959

@@ -42,9 +62,7 @@ upload_videos(cookies='cookies.txt')
4262
To use password authentication, pass your **username** and **password** as keyword arguments to `upload_videos`.
4363

4464
```python
45-
upload_videos(username='mytiktokusername', password='*******')
46-
# or
47-
upload_videos(login_info=('mytiktokusername', '*********')
65+
upload_video(username='mytiktokusername', password='*******')
4866
```
4967

5068
> As a side note, try to avoid keeping passwords as values in your code. You can read more about why [here](https://medium.com/twodigits/keep-passwords-out-of-source-code-why-and-how-e84f9004815a).
@@ -68,10 +86,16 @@ options = Options()
6886

6987
options.add_argument('start-maximized')
7088

71-
upload_videos(browser_agent=options)
89+
upload_videos(options=options)
7290
```
7391

74-
> Note: Options are Browser specific
92+
> Note: Make sure to use the right selenium options for your browser
93+
94+
### Headless Browsers
95+
96+
**Headless browsers do not work at this time**
97+
98+
> If more experienced in Webscraping, I would really appreciate helping make this work. [undetected-chromedriver](https://github.com/ultrafunkamsterdam/undetected-chromedriver) was already tried and did not work
7599
76100
## Installation
77101

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
[project]
22
name = "tiktok_uploader"
3-
version = "0.0.1"
3+
version = "0.1.0"
44
authors = [
55
{ name="William Kaiser", email="wkaisertexas@gmail.com" },
66
]
7-
description = "An automatic TikTok video uploader w/ CLI"
7+
description = "An automatic TikTok video uploader w/ CLI. Uses cookies from your browser to manage authentication and upload your videos automatically."
88
readme = "README.md"
99
requires-python = ">=3.11"
1010
keywords = [
@@ -33,8 +33,8 @@ test = [
3333
"pytest",
3434
]
3535

36-
# [tool.hatch.envs.test.matrix]
37-
# python = ["38", "39"]
36+
[tool.hatch.envs.test.matrix]
37+
python = ["38", "39"]
3838

3939
[project.scripts]
4040
tiktok_uploader = "tiktok_uploader.cli:cli"

src/tiktok_uploader/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def main():
66
"""
77
Entry point for TikTok-Uploader, makes a call to CLI
88
"""
9-
cli.main()
9+
cli.cli()
1010

1111
if __name__ == '__main__':
1212
main()

src/tiktok_uploader/auth.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
class AuthBackend:
1515
username: str
1616
password: str
17-
cookies: dict
17+
cookies: list
1818

19-
def __init__(self, username=None, password=None, cookies=[], cookies_path=None):
19+
def __init__(self, username: str = '', password: str = '', cookies=[], cookies_path=None):
2020
"""
2121
Creates the authenticaiton backend
2222
@@ -84,15 +84,15 @@ def get_cookies(self, path: str) -> dict:
8484
]
8585

8686

87-
def login_accounts(driver=None, accounts=[(None, None)]) -> list:
87+
def login_accounts(driver=None, accounts=[(None, None)], *args, **kwargs) -> list:
8888
"""
8989
Authenticates the accounts using the browser backend and saves the required credentials
9090
9191
Keyword arguments:
9292
- driver -> the webdriver to use
9393
- accounts -> a list of tuples of the form (username, password)
9494
"""
95-
driver = driver or get_browser(headless=False)
95+
driver = driver or get_browser(headless=False, *args, **kwargs)
9696

9797
cookies = {}
9898
for account in accounts:

src/tiktok_uploader/browsers.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,15 @@
2222

2323
from tiktok_uploader import config
2424

25-
26-
def get_browser(name: str = 'chrome', *args, **kwargs) -> webdriver:
25+
def get_browser(name: str = 'chrome', options=None, *args, **kwargs) -> webdriver:
2726
"""
2827
Gets a browser based on the name with the ability to pass in additional arguments
2928
"""
3029
# get the web driver for the browser
31-
driver_to_use = get_driver(name=name)
30+
driver_to_use = get_driver(name=name, *args, **kwargs)
3231

3332
# gets the options for the browser
34-
options = get_default_options(name=name, *args, **kwargs)
33+
options = options or get_default_options(name=name, *args, **kwargs)
3534

3635
# combines them together into a completed driver
3736
service = get_service(name=name)
@@ -45,7 +44,7 @@ def get_browser(name: str = 'chrome', *args, **kwargs) -> webdriver:
4544
return driver
4645

4746

48-
def get_driver(name: str = 'chrome') -> webdriver:
47+
def get_driver(name: str = 'chrome', *args, **kwargs) -> webdriver:
4948
"""
5049
Gets the web driver function for the browser
5150
"""
@@ -96,11 +95,19 @@ def get_default_options(name: str, *args, **kwargs):
9695
raise Exception(f'{name} is not a supported browser')
9796

9897

99-
def chrome_defaults(headless: bool = False, *args, **kwargs) -> ChromeOptions:
98+
def chrome_defaults(headless: bool = False, undetectable=False, *args, **kwargs) -> ChromeOptions:
10099
"""
101100
Creates Chrome with Options
102101
"""
103-
options = ChromeOptions()
102+
103+
if undetectable:
104+
options = uc.ChromeOptions()
105+
if headless:
106+
options.headless = True
107+
options.add_argument( '--headless' )
108+
return options # TODO: Maybe customize the undetectable chromedriver
109+
else:
110+
options = ChromeOptions()
104111

105112
# default options
106113

src/tiktok_uploader/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def get_auth_args():
109109

110110
return parser.parse_args()
111111

112-
def validate_auth_args(args: dict):
112+
def validate_auth_args(args):
113113
"""
114114
Preforms validation on each input given
115115
"""

src/tiktok_uploader/upload.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,16 @@ def upload_videos(videos: list = None, auth: AuthBackend = None, browser='chrome
9191
print(e)
9292
if i == n-1: # adds if the last retry
9393
failed.append(video)
94+
95+
if on_complete: # calls the user-specified on-complete function
96+
on_complete(video)
9497

9598
if config['quit_on_end']:
9699
driver.quit()
97100

98101
return failed
99102

103+
100104
def complete_upload_form(driver, path: str, description: str, *args, **kwargs) -> None:
101105
"""
102106
Actually uploades each video

test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
if __name__ == '__main__':
66
# Uploads a video to TikTok
7-
# upload_video('../../Desktop/video.mp4', description='this is a story about why I don', cookies='../../Desktop/cookies.txt', headless=True)
7+
upload_video('../../Desktop/video.mp4', description='this is a story about why I don', cookies='../../Desktop/cookies.txt', headless=True)
88

99
# tests cookies for accounts -> Works except I get too many requests error (really sad)
1010
# tiktok_uploader.auth.login_accounts(accounts=[('server314159@gmail.com', 'asdfse12323dfsd!')])
11-
system('tiktok_uploader -v ../../Desktop/video.mp4 -d "this is a story about why I don\'t like tiktok" -c ../../Desktop/cookies.txt')
11+
# system('tiktok_uploader -v ../../Desktop/video.mp4 -d "this is a story about why I don\'t like tiktok" -c ../../Desktop/cookies.txt')

0 commit comments

Comments
 (0)