algorembrant commited on
Commit
e204e4c
·
verified ·
1 Parent(s): 2918292

Upload 5 files

Browse files
Files changed (5) hide show
  1. .gitattributes +11 -35
  2. .gitignore +22 -0
  3. README.md +59 -0
  4. requirements.txt +1 -0
  5. x_downloader.py +91 -0
.gitattributes CHANGED
@@ -1,35 +1,11 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ # Default behavior
2
+ * text=auto
3
+
4
+ # Python and Markdown
5
+ *.py text eol=lf
6
+ *.md text eol=lf
7
+
8
+ # Hugging Face / GitHub Large File Storage (LFS) rules
9
+ *.mp4 filter=lfs diff=lfs merge=lfs -text
10
+ *.mkv filter=lfs diff=lfs merge=lfs -text
11
+ *.webm filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python artifacts
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Environments
7
+ .env
8
+ .venv
9
+ env/
10
+ venv/
11
+ ENV/
12
+
13
+ # Output videos (prevents accidental commits of large files)
14
+ *.mp4
15
+ *.mkv
16
+ *.webm
17
+ *.part
18
+ *.ytdl
19
+
20
+ # OS generated files
21
+ .DS_Store
22
+ Thumbs.db
README.md ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: X Video Downloader
3
+ colorFrom: blue
4
+ colorTo: indigo
5
+ sdk: docker
6
+ pinned: false
7
+ ---
8
+
9
+ # X.com Video Downloader
10
+
11
+ ![Python](https://img.shields.io/badge/python-3.8+-blue.svg)
12
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
13
+ ![Maintenance](https://img.shields.io/badge/maintained-yes-brightgreen.svg)
14
+
15
+ A robust, fast-processing Python tool to download high-quality video content from X.com (Twitter) links.
16
+
17
+ **Author:** algorembrant
18
+
19
+ ## Architecture and Flow
20
+
21
+ ```mermaid
22
+ sequenceDiagram
23
+ participant User
24
+ participant CLI as x_downloader.py
25
+ participant YTDLP as yt-dlp Core
26
+ participant X as X.com Servers
27
+ participant Local as Local Storage
28
+
29
+ User->>CLI: python x_downloader.py "url"
30
+ CLI->>YTDLP: Pass URL and Configuration
31
+ YTDLP->>X: Request Metadata & Media Streams
32
+ X-->>YTDLP: Return Video Stream & Audio Stream
33
+ YTDLP->>Local: Download Streams
34
+ YTDLP->>Local: Merge via FFmpeg (mp4)
35
+ Local-->>CLI: Success Status
36
+ CLI-->>User: "Download completed successfully."
37
+
38
+ ```
39
+ .
40
+ ## File Structure
41
+ ├── .gitattributes
42
+ ├── .gitignore
43
+ ├── README.md
44
+ ├── requirements.txt
45
+ └── x_downloader.py
46
+
47
+
48
+ - 1 Install Python Ensure Python 3.8+ is installed on your system.
49
+ - 2 Install FFmpeg
50
+ - Windows: Download from gyan.dev, extract, and add the bin folder to your System PATH.
51
+ - macOS: brew install ffmpeg
52
+ - Linux (Debian/Ubuntu): sudo apt update && sudo apt install ffmpeg
53
+ - 3 Create Directory Create a folder for your project and navigate into it.
54
+ - 4 Set up Virtual Env python -m venv venv (then activate it: venv\Scripts\activate on Windows or source venv/bin/activate on Mac/Linux).
55
+ - 5 Save Files Save the provided .py, requirements.txt, .gitignore, .gitattributes, and README.md files in your directory.
56
+ - 6 Install Libraries pip install -r requirements.txt
57
+ - 7 Run the Script Execute the script using the commands listed at the top of the Python file.
58
+
59
+ **Note**: FFmpeg is strictly required. X.com often serves video and audio as separate streams to optimize bandwidth; FFmpeg allows the script to rapidly merge them back into a single MP4 file without quality loss.
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ yt-dlp>=2023.11.16
x_downloader.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ X.com Video Downloader
3
+ Author: algorembrant
4
+
5
+ Usage Commands:
6
+ 1. Basic usage (download to current directory with default title):
7
+ python x_downloader.py "https://x.com/user/status/123456789"
8
+
9
+ 2. Specify output directory:
10
+ python x_downloader.py "https://x.com/user/status/123456789" -o "./downloads"
11
+
12
+ 3. Specify custom filename (must include extension, e.g., .mp4):
13
+ python x_downloader.py "https://x.com/user/status/123456789" -f "my_video.mp4"
14
+ """
15
+
16
+ import argparse
17
+ import sys
18
+ import os
19
+ import yt_dlp
20
+
21
+ def download_x_video(url: str, output_dir: str = None, filename: str = None) -> None:
22
+ """
23
+ Downloads a video from an X.com link using yt-dlp.
24
+ """
25
+ print(f"Initializing download for: {url}")
26
+
27
+ # Base configuration for optimal processing
28
+ ydl_opts = {
29
+ 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
30
+ 'merge_output_format': 'mp4',
31
+ 'quiet': False,
32
+ 'no_warnings': True,
33
+ 'updatetime': False,
34
+ }
35
+
36
+ # Handle output paths
37
+ if filename:
38
+ if output_dir:
39
+ ydl_opts['outtmpl'] = os.path.join(output_dir, filename)
40
+ else:
41
+ ydl_opts['outtmpl'] = filename
42
+ else:
43
+ if output_dir:
44
+ ydl_opts['outtmpl'] = os.path.join(output_dir, '%(title)s_%(id)s.%(ext)s')
45
+ else:
46
+ ydl_opts['outtmpl'] = '%(title)s_%(id)s.%(ext)s'
47
+
48
+ try:
49
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
50
+ print("Extracting video metadata and downloading...")
51
+ error_code = ydl.download([url])
52
+
53
+ if error_code == 0:
54
+ print("Download completed successfully.")
55
+ else:
56
+ print(f"Download finished with non-zero exit code: {error_code}")
57
+ sys.exit(1)
58
+
59
+ except yt_dlp.utils.DownloadError as e:
60
+ print(f"Error during download: {str(e)}")
61
+ sys.exit(1)
62
+ except Exception as e:
63
+ print(f"An unexpected error occurred: {str(e)}")
64
+ sys.exit(1)
65
+
66
+ def main():
67
+ parser = argparse.ArgumentParser(description="Download videos from X.com links.")
68
+ parser.add_argument("url", help="The full X.com (or Twitter) status URL.")
69
+ parser.add_argument("-o", "--output-dir", type=str, help="Directory to save the video.")
70
+ parser.add_argument("-f", "--filename", type=str, help="Custom filename (e.g., video.mp4).")
71
+
72
+ args = parser.parse_args()
73
+
74
+ # Validate URL structure loosely
75
+ if "x.com" not in args.url and "twitter.com" not in args.url:
76
+ print("Error: The provided URL does not appear to be a valid X.com or Twitter link.")
77
+ sys.exit(1)
78
+
79
+ # Ensure output directory exists if provided
80
+ if args.output_dir and not os.path.exists(args.output_dir):
81
+ try:
82
+ os.makedirs(args.output_dir)
83
+ print(f"Created output directory: {args.output_dir}")
84
+ except OSError as e:
85
+ print(f"Error creating output directory: {e}")
86
+ sys.exit(1)
87
+
88
+ download_x_video(args.url, args.output_dir, args.filename)
89
+
90
+ if __name__ == "__main__":
91
+ main()