TikPipe 1.0.0__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.
tikpipe/__init__.py ADDED
File without changes
tikpipe/cli.py ADDED
@@ -0,0 +1,218 @@
1
+ import os
2
+ import sys
3
+ import time
4
+ import json
5
+ from concurrent.futures import ThreadPoolExecutor, as_completed
6
+ from playwright.sync_api import sync_playwright
7
+ import yt_dlp
8
+
9
+ # Ubicación global de la sesión (para que funcione desde cualquier carpeta de Windows)
10
+ GLOBAL_DIR = os.path.expanduser("~/.tikpipe")
11
+ SESSION_FOLDER = os.path.join(GLOBAL_DIR, "perfil_navegador")
12
+ CONFIG_FILE = os.path.join(GLOBAL_DIR, "config.json")
13
+ LINKS_FILE = os.path.join(GLOBAL_DIR, "videos.txt")
14
+
15
+ os.makedirs(GLOBAL_DIR, exist_ok=True)
16
+ os.makedirs(SESSION_FOLDER, exist_ok=True)
17
+
18
+
19
+ def load_configuration():
20
+ default_config = {
21
+ "download_path": os.path.abspath("./TikTok_Downloads"),
22
+ "video_count": 10,
23
+ "concurrent_downloads": 6
24
+ }
25
+
26
+ if not os.path.exists(CONFIG_FILE):
27
+ with open(CONFIG_FILE, "w", encoding="utf-8") as f:
28
+ json.dump(default_config, f, indent=4)
29
+ return default_config
30
+
31
+ try:
32
+ with open(CONFIG_FILE, "r", encoding="utf-8") as f:
33
+ config = json.load(f)
34
+ path = config.get("download_path", default_config["download_path"])
35
+ count = config.get("video_count", default_config["video_count"])
36
+ concurrency = config.get("concurrent_downloads", default_config["concurrent_downloads"])
37
+ return {
38
+ "download_path": os.path.abspath(path),
39
+ "video_count": int(count),
40
+ "concurrent_downloads": int(concurrency)
41
+ }
42
+ except Exception:
43
+ return default_config
44
+
45
+
46
+ def parse_arguments():
47
+ config = load_configuration()
48
+
49
+ # Si el usuario pide ayuda
50
+ if len(sys.argv) > 1 and sys.argv[1] in ("-h", "--help"):
51
+ print("\nTikPipe - TikTok Feed Harvester & Fast Downloader")
52
+ print("Usage: TikPipe [video_count] [concurrent_downloads] \"[download_path]\"")
53
+ print("Example: TikPipe 20 6 \"D:\\My Videos\\TikTok\"\n")
54
+ sys.exit(0)
55
+
56
+ # Argumento 1: Cantidad de videos
57
+ if len(sys.argv) >= 2:
58
+ try:
59
+ config["video_count"] = int(sys.argv[1])
60
+ except ValueError:
61
+ print(f"[Warning] Invalid video count '{sys.argv[1]}'. Using: {config['video_count']}")
62
+
63
+ # Argumento 2: Descargas simultáneas
64
+ if len(sys.argv) >= 3:
65
+ try:
66
+ config["concurrent_downloads"] = int(sys.argv[2])
67
+ except ValueError:
68
+ print(f"[Warning] Invalid concurrency '{sys.argv[2]}'. Using: {config['concurrent_downloads']}")
69
+
70
+ # Argumento 3: Ruta de descarga entre comillas
71
+ if len(sys.argv) >= 4:
72
+ config["download_path"] = os.path.abspath(sys.argv[3])
73
+
74
+ return config
75
+
76
+
77
+ def download_single_video(url, ydl_opts):
78
+ try:
79
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
80
+ ydl.download([url])
81
+ return True, url
82
+ except Exception:
83
+ return False, url
84
+
85
+
86
+ def main():
87
+ config = parse_arguments()
88
+ download_folder = config["download_path"]
89
+ target_count = config["video_count"]
90
+ concurrency = config["concurrent_downloads"]
91
+
92
+ os.makedirs(download_folder, exist_ok=True)
93
+
94
+ ydl_opts = {
95
+ 'format': (
96
+ 'bestvideo[vcodec^=avc]+bestaudio[acodec=mp4a.40.2]/'
97
+ 'best[acodec=mp4a.40.2]/'
98
+ 'bestvideo[vcodec^=avc]+bestaudio[acodec^=mp4a]/'
99
+ 'best[vcodec^=avc]/'
100
+ 'best'
101
+ ),
102
+ 'merge_output_format': 'mp4',
103
+ 'outtmpl': os.path.join(download_folder, '%(uploader)s_%(id)s.%(ext)s'),
104
+ 'ignoreerrors': True,
105
+ 'nooverwrites': True,
106
+ 'quiet': True,
107
+ 'buffersize': 1024 * 1024 * 4,
108
+ }
109
+
110
+ intercepted_videos = set()
111
+ download_futures = []
112
+ executor = ThreadPoolExecutor(max_workers=concurrency)
113
+
114
+ if os.path.exists(LINKS_FILE):
115
+ with open(LINKS_FILE, "w", encoding="utf-8") as f:
116
+ pass
117
+
118
+ print("\n" + "="*65)
119
+ print("TikPipe: STARTING PIPELINE MODE")
120
+ print(f"Target: {target_count} videos | Parallel Threads: {concurrency}")
121
+ print(f"Destination: {download_folder}")
122
+ print("="*65 + "\n")
123
+
124
+ with sync_playwright() as p:
125
+ print("Launching optimized browser...")
126
+
127
+ context = p.chromium.launch_persistent_context(
128
+ user_data_dir=SESSION_FOLDER,
129
+ channel="chrome",
130
+ headless=False,
131
+ args=[
132
+ "--disable-blink-features=AutomationControlled",
133
+ "--start-maximized"
134
+ ],
135
+ ignore_default_args=["--enable-automation"],
136
+ no_viewport=True
137
+ )
138
+
139
+ page = context.pages[0] if context.pages else context.new_page()
140
+
141
+ def block_heavy_resources(route):
142
+ if route.request.resource_type in ["image", "media", "font"]:
143
+ route.abort()
144
+ else:
145
+ route.continue_()
146
+
147
+ page.route("**/*", block_heavy_resources)
148
+
149
+ def intercept_and_download(response):
150
+ url = response.url
151
+ if ("item_list" in url or "feed" in url) and response.status == 200:
152
+ try:
153
+ data = response.json()
154
+ items = data.get("itemList", [])
155
+ for item in items:
156
+ if len(intercepted_videos) >= target_count:
157
+ break
158
+ video_id = item.get("id")
159
+ author = item.get("author", {}).get("uniqueId")
160
+ if video_id and author:
161
+ link = f"https://www.tiktok.com/@{author}/video/{video_id}"
162
+ if link not in intercepted_videos:
163
+ intercepted_videos.add(link)
164
+ num = len(intercepted_videos)
165
+ print(f"-> [{num}/{target_count}] Intercepted and queued: @{author}")
166
+
167
+ with open(LINKS_FILE, "a", encoding="utf-8") as f:
168
+ f.write(f"{link}\n")
169
+
170
+ fut = executor.submit(download_single_video, link, ydl_opts)
171
+ download_futures.append(fut)
172
+ except Exception:
173
+ pass
174
+
175
+ page.on("response", intercept_and_download)
176
+
177
+ print("Navigating to 'For You' feed...")
178
+ page.goto("https://www.tiktok.com/foryou")
179
+
180
+ elapsed_seconds = 0
181
+ while len(intercepted_videos) < target_count and elapsed_seconds < 40:
182
+ if len(intercepted_videos) >= target_count:
183
+ break
184
+ page.keyboard.press("ArrowDown")
185
+ page.mouse.wheel(0, 500)
186
+ time.sleep(0.8)
187
+ elapsed_seconds += 0.8
188
+
189
+ print(f"\nAll {len(intercepted_videos)} videos intercepted! Closing browser...")
190
+ context.close()
191
+
192
+ print("\nWaiting for active downloads to finish...")
193
+ completed = 0
194
+ total = len(download_futures)
195
+
196
+ for f in as_completed(download_futures):
197
+ ok, link = f.result()
198
+ completed += 1
199
+ if ok:
200
+ print(f"[{completed}/{total}] Download finished: {link}")
201
+ else:
202
+ print(f"[{completed}/{total}] Failed: {link}")
203
+
204
+ executor.shutdown(wait=True)
205
+
206
+ if os.path.exists(LINKS_FILE):
207
+ with open(LINKS_FILE, "w", encoding="utf-8") as f:
208
+ pass
209
+ print(f"\n-> '{LINKS_FILE}' cleared successfully.")
210
+
211
+ print("\n" + "="*65)
212
+ print("TikPipe: PROCESS COMPLETED SUCCESSFULLY!")
213
+ print(f"Videos saved to: {download_folder}")
214
+ print("="*65 + "\n")
215
+
216
+
217
+ if __name__ == "__main__":
218
+ main()
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: TikPipe
3
+ Version: 1.0.0
4
+ Summary: High-performance real-time TikTok feed harvester and concurrent downloader
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: playwright
8
+ Requires-Dist: yt-dlp
9
+ Requires-Dist: curl_cffi
10
+
11
+ # TikTok Feed Harvester & Fast Downloader
12
+
13
+ A high-performance automated script for Windows designed to intercept and download videos from your TikTok **"For You" Page (FYP)** in original quality, watermark-free, utilizing your active session, and in the universally compatible **H.264 (AVC) + AAC** format.
14
+
15
+ ---
16
+
17
+ ## Prerequisites
18
+
19
+ Before getting started, make sure your computer meets the following requirements:
20
+
21
+ 1. **Windows 10 or 11 (64-bit)**.
22
+ 2. **Python 3.10 or higher** (compatible with Python 3.11, 3.12, and 3.13).
23
+ * When installing Python, make sure to check the box that says **"Add python.exe to PATH"** on the first setup screen.
24
+ 3. **Google Chrome** installed officially on your system.
25
+
26
+ ---
27
+
28
+ ## Project Structure
29
+
30
+ Your project directory (e.g., `D:\tiktok extractor\`) should be organized as follows:
31
+
32
+ ```text
33
+ tiktok extractor/
34
+ │
35
+ ├── user.py # Main capture and download script
36
+ ├── requirements.txt # Python dependencies list
37
+ ├── update_dependencies.bat # 1-click dependency installer/updater
38
+ ├── setup_login.py # One-time login helper script
39
+ ├── config.json # Configuration file (auto-generated on first run)
40
+ ├── videos.txt # Temporary file storing extracted URLs
41
+ └── perfil_navegador/ # Persistent folder storing your Chrome session
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Step 1: Install Dependencies
47
+
48
+ 1. Open the project folder.
49
+ 2. **Double-click** the file **`update_dependencies.bat`**.
50
+ 3. A command prompt window will open and automatically execute:
51
+ * Upgrading the `pip` package manager.
52
+ * Installing `yt-dlp`, `playwright`, and `curl_cffi`.
53
+ * Downloading the Chromium browser binaries for Playwright.
54
+ 4. When it completes and displays `ALL DEPENDENCIES INSTALLED AND UPDATED SUCCESSFULLY!`, press any key to close the window.
55
+
56
+ ---
57
+
58
+ ## Step 2: One-Time Session Setup (Login)
59
+
60
+ To allow the program to access your personalized "For You" feed, it must use your active account. To prevent Google from blocking your login with the *"This browser or app may not be secure"* error, a native launch setup is used:
61
+
62
+ 1. Create a file named **`setup_login.py`** in the project folder with the following content:
63
+
64
+ ```python
65
+ import os
66
+ import subprocess
67
+ import sys
68
+
69
+ CARPETA_SESION = os.path.abspath("./perfil_navegador")
70
+ os.makedirs(CARPETA_SESION, exist_ok=True)
71
+
72
+ chrome_paths = [
73
+ os.path.expandvars(r"%ProgramFiles%\Google\Chrome\Application\chrome.exe"),
74
+ os.path.expandvars(r"%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe"),
75
+ os.path.expandvars(r"%LocalAppData%\Google\Chrome\Application\chrome.exe"),
76
+ ]
77
+
78
+ chrome_exe = next((p for p in chrome_paths if os.path.exists(p)), None)
79
+
80
+ if not chrome_exe:
81
+ print("Error: Google Chrome was not found on your system.")
82
+ sys.exit(1)
83
+
84
+ print("Launching Google Chrome for session setup...")
85
+ print("1. Log in to Google and TikTok in the browser tabs that will open.")
86
+ print("2. Once your TikTok account is visible and active, simply CLOSE the Chrome window.")
87
+
88
+ process = subprocess.Popen([
89
+ chrome_exe,
90
+ f"--user-data-dir={CARPETA_SESION}",
91
+ "--no-first-run",
92
+ "https://accounts.google.com",
93
+ "https://www.tiktok.com/login"
94
+ ])
95
+ process.wait()
96
+ print("Session successfully saved to ./perfil_navegador!")
97
+ ```
98
+
99
+ 2. Close all existing Google Chrome windows running on your PC.
100
+ 3. Open a terminal in the project directory and run:
101
+ ```cmd
102
+ python setup_login.py
103
+ ```
104
+ 4. A fresh Chrome window will launch:
105
+ * In the first tab, sign in to your Google account.
106
+ * In the second tab, click **"Continue with Google"** on TikTok (it will sign in automatically).
107
+ 5. **Close the Chrome window using the red "X" button.**
108
+ 6. Your session is now securely saved in `perfil_navegador`, and you will not need to sign in again.
109
+
110
+ ---
111
+
112
+ ## Step 3: Configuration (`config.json`)
113
+
114
+ The first time you run `user.py`, it will automatically create `config.json`. You can open it in **Notepad** to customize your settings:
115
+
116
+ ```json
117
+ {
118
+ "download_path": "D:\\tiktok extractor\\TikTok_Downloads",
119
+ "video_count": 10,
120
+ "concurrent_downloads": 6
121
+ }
122
+ ```
123
+
124
+ * **`download_path`**: The folder where downloaded videos will be stored (you can set any valid directory path).
125
+ * **`video_count`**: The number of videos you want to harvest from your feed per execution.
126
+ * **`concurrent_downloads`**: How many videos are downloaded simultaneously in parallel (recommended range: 4 to 8).
127
+
128
+ ---
129
+
130
+ ## Step 4: Running the Program
131
+
132
+ Whenever you want to download videos:
133
+
134
+ 1. Open your terminal in the project folder.
135
+ 2. Run:
136
+ ```cmd
137
+ python user.py
138
+ ```
139
+ 3. The program will:
140
+ * Launch Chrome in the background with your saved session.
141
+ * Block on-screen images and video playback to save network bandwidth.
142
+ * Intercept your "For You" network feed packets.
143
+ * **Download videos concurrently in real time** while it continues to scroll.
144
+ * Automatically truncate `videos.txt` upon completion and notify you in the console.
145
+
146
+ ---
147
+
148
+ ## FAQ & Troubleshooting
149
+
150
+ #### 1. Why do I see a "Database is locked" error or Chrome fails to open?
151
+ Make sure you do not have another Google Chrome window open using the same profile folder (`perfil_navegador`) before launching the script.
152
+
153
+ #### 2. Do the downloaded videos have watermarks?
154
+ No. `yt-dlp` extracts the clean, original-quality media streams directly from ByteDance/TikTok content delivery networks.
155
+
156
+ #### 3. How do I download from a specific creator profile instead of my "For You" feed?
157
+ In `user.py`, find the following line:
158
+ ```python
159
+ page.goto("https://www.tiktok.com/foryou")
160
+ ```
161
+ And replace it with the desired profile URL:
162
+ ```python
163
+ page.goto("https://www.tiktok.com/@username")
164
+ ```
@@ -0,0 +1,7 @@
1
+ tikpipe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ tikpipe/cli.py,sha256=ODKosuj5Cylt3VZYSXIoW-R5NMSPq0_utkLXt72Wnbk,7688
3
+ tikpipe-1.0.0.dist-info/METADATA,sha256=kUduYtgcDi1kqbrpNLuL6iFpdSeM2VIgb0Vj5JRkOH4,6154
4
+ tikpipe-1.0.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
5
+ tikpipe-1.0.0.dist-info/entry_points.txt,sha256=pf2socPtNMpFhAMd7zf7sjwLvvkb64r-1nfaxqDe2x8,72
6
+ tikpipe-1.0.0.dist-info/top_level.txt,sha256=vHP2mq1VF2eLGF-yGVFK2h9rzgpFbffmATkF6XdozvQ,8
7
+ tikpipe-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ TikPipe = tikpipe.cli:main
3
+ tikpipe = tikpipe.cli:main
@@ -0,0 +1 @@
1
+ tikpipe