yt2term 0.1.0__tar.gz

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.
yt2term-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Henri Nuortila
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.
yt2term-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.4
2
+ Name: yt2term
3
+ Version: 0.1.0
4
+ Summary: YouTube video playback in terminal as ASCII
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: opencv-python
9
+ Requires-Dist: asciifyy
10
+ Requires-Dist: pillow
11
+ Requires-Dist: yt-dlp
12
+ Dynamic: license-file
13
+
14
+ # yt2term
15
+
16
+ `yt2term` streams YouTube videos (or direct video links) as real-time ASCII art directly inside your terminal.
17
+
18
+ ## Entirely impractical - Weirdly meaningful
19
+
20
+ ---
21
+
22
+ ![example frame](images/cat_ascii.png)
23
+
24
+ ---
25
+
26
+ ## Features
27
+
28
+ - Real-time video → ASCII conversion
29
+ - ~30 FPS rendering loop
30
+ - Optional color rendering
31
+ - Adjustable output width
32
+ - Optional audio playback via `ffplay`
33
+ - Automatic FFmpeg detection
34
+
35
+ ---
36
+
37
+ ## Installation
38
+
39
+ ### Development install (recommended)
40
+
41
+ ```bash
42
+ git clone https://github.com/<your-username>/yt2term.git
43
+ cd yt2term
44
+
45
+ pip install -e .
46
+ ```
47
+
48
+ This installs the CLI command:
49
+
50
+ ```bash
51
+ yt2term
52
+ ```
53
+
54
+ ### Standard install
55
+
56
+ ```bash
57
+ pip install .
58
+ ```
59
+
60
+ Use this if you just want a normal installed package.
61
+
62
+ ---
63
+
64
+ ## Python Version
65
+
66
+ - Requires Python ≥ 3.10
67
+ - Tested on Python 3.10+ / 3.12
68
+
69
+ ---
70
+
71
+ ## Dependencies
72
+
73
+ Installed automatically via `pyproject.toml`:
74
+
75
+ - `opencv-python`
76
+ - `yt-dlp`
77
+ - `pillow`
78
+ - `asciifyy`
79
+
80
+ ---
81
+
82
+ ## Audio Support
83
+
84
+ Audio playback uses `ffplay` from FFmpeg.
85
+
86
+ Audio is disabled by default.
87
+
88
+ Enable it with:
89
+
90
+ ```bash
91
+ yt2term <link> --audio
92
+ ```
93
+
94
+ If FFmpeg is missing, the application will:
95
+
96
+ 1. Detect it automatically
97
+ 2. Explain what is missing
98
+ 3. Prompt installation
99
+ 4. Attempt installation using the system package manager
100
+
101
+ No digging through random forum posts from 2014 required.
102
+
103
+ ---
104
+
105
+ ## Usage
106
+
107
+ ### Basic playback
108
+
109
+ ```bash
110
+ yt2term <youtube-or-video-url>
111
+ ```
112
+
113
+ ### Enable audio
114
+
115
+ ```bash
116
+ yt2term <url> --audio
117
+ ```
118
+
119
+ ### Disable color output
120
+
121
+ ```bash
122
+ yt2term <url> --no-color
123
+ ```
124
+
125
+ ### Set ASCII width
126
+
127
+ ```bash
128
+ yt2term <url> --width 120
129
+ ```
130
+
131
+ ### Combined options
132
+
133
+ ```bash
134
+ yt2term <url> --audio --width 100 --no-color
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Notes
140
+
141
+ - Uses `yt-dlp` to resolve streaming URLs
142
+ - Requires an internet connection during playback
143
+ - Performance depends heavily on terminal rendering speed
144
+ - Audio/video sync is approximate
145
+ - Designed for fun, experimentation, and terminal abuse
146
+
147
+ ---
148
+
149
+ ## Exit
150
+
151
+ Press `Ctrl+C` to stop playback and return to reality.
152
+
153
+ ---
154
+
155
+ ## Project Structure
156
+
157
+ ```text
158
+ yt2term/
159
+ ├── src/
160
+ │ └── yt2term/
161
+ │ ├── main.py
162
+ │ ├── cli.py
163
+ │ ├── video.py
164
+ │ ├── audio.py
165
+ │ ├── render.py
166
+ ```
167
+
168
+ ---
169
+
170
+ ## License
171
+
172
+ MIT
173
+
@@ -0,0 +1,160 @@
1
+ # yt2term
2
+
3
+ `yt2term` streams YouTube videos (or direct video links) as real-time ASCII art directly inside your terminal.
4
+
5
+ ## Entirely impractical - Weirdly meaningful
6
+
7
+ ---
8
+
9
+ ![example frame](images/cat_ascii.png)
10
+
11
+ ---
12
+
13
+ ## Features
14
+
15
+ - Real-time video → ASCII conversion
16
+ - ~30 FPS rendering loop
17
+ - Optional color rendering
18
+ - Adjustable output width
19
+ - Optional audio playback via `ffplay`
20
+ - Automatic FFmpeg detection
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ### Development install (recommended)
27
+
28
+ ```bash
29
+ git clone https://github.com/<your-username>/yt2term.git
30
+ cd yt2term
31
+
32
+ pip install -e .
33
+ ```
34
+
35
+ This installs the CLI command:
36
+
37
+ ```bash
38
+ yt2term
39
+ ```
40
+
41
+ ### Standard install
42
+
43
+ ```bash
44
+ pip install .
45
+ ```
46
+
47
+ Use this if you just want a normal installed package.
48
+
49
+ ---
50
+
51
+ ## Python Version
52
+
53
+ - Requires Python ≥ 3.10
54
+ - Tested on Python 3.10+ / 3.12
55
+
56
+ ---
57
+
58
+ ## Dependencies
59
+
60
+ Installed automatically via `pyproject.toml`:
61
+
62
+ - `opencv-python`
63
+ - `yt-dlp`
64
+ - `pillow`
65
+ - `asciifyy`
66
+
67
+ ---
68
+
69
+ ## Audio Support
70
+
71
+ Audio playback uses `ffplay` from FFmpeg.
72
+
73
+ Audio is disabled by default.
74
+
75
+ Enable it with:
76
+
77
+ ```bash
78
+ yt2term <link> --audio
79
+ ```
80
+
81
+ If FFmpeg is missing, the application will:
82
+
83
+ 1. Detect it automatically
84
+ 2. Explain what is missing
85
+ 3. Prompt installation
86
+ 4. Attempt installation using the system package manager
87
+
88
+ No digging through random forum posts from 2014 required.
89
+
90
+ ---
91
+
92
+ ## Usage
93
+
94
+ ### Basic playback
95
+
96
+ ```bash
97
+ yt2term <youtube-or-video-url>
98
+ ```
99
+
100
+ ### Enable audio
101
+
102
+ ```bash
103
+ yt2term <url> --audio
104
+ ```
105
+
106
+ ### Disable color output
107
+
108
+ ```bash
109
+ yt2term <url> --no-color
110
+ ```
111
+
112
+ ### Set ASCII width
113
+
114
+ ```bash
115
+ yt2term <url> --width 120
116
+ ```
117
+
118
+ ### Combined options
119
+
120
+ ```bash
121
+ yt2term <url> --audio --width 100 --no-color
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Notes
127
+
128
+ - Uses `yt-dlp` to resolve streaming URLs
129
+ - Requires an internet connection during playback
130
+ - Performance depends heavily on terminal rendering speed
131
+ - Audio/video sync is approximate
132
+ - Designed for fun, experimentation, and terminal abuse
133
+
134
+ ---
135
+
136
+ ## Exit
137
+
138
+ Press `Ctrl+C` to stop playback and return to reality.
139
+
140
+ ---
141
+
142
+ ## Project Structure
143
+
144
+ ```text
145
+ yt2term/
146
+ ├── src/
147
+ │ └── yt2term/
148
+ │ ├── main.py
149
+ │ ├── cli.py
150
+ │ ├── video.py
151
+ │ ├── audio.py
152
+ │ ├── render.py
153
+ ```
154
+
155
+ ---
156
+
157
+ ## License
158
+
159
+ MIT
160
+
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "yt2term"
7
+ version = "0.1.0"
8
+ description = "YouTube video playback in terminal as ASCII"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "opencv-python",
13
+ "asciifyy",
14
+ "pillow",
15
+ "yt-dlp",
16
+ ]
17
+
18
+ [project.scripts]
19
+ yt2term = "yt2term.main:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,67 @@
1
+ import platform
2
+ import shutil
3
+ import subprocess
4
+ import time
5
+
6
+
7
+ def ensure_ffplay() -> bool:
8
+ if shutil.which("ffplay") is not None:
9
+ return True
10
+
11
+ print("ffplay not found.")
12
+
13
+ answer: str = input(
14
+ "Would you like to install FFmpeg? (y/n): "
15
+ ).strip().lower()
16
+
17
+ if answer != "y":
18
+ return False
19
+
20
+ system: str = platform.system()
21
+
22
+ try:
23
+ if system == "Windows":
24
+ subprocess.run(
25
+ ["winget", "install", "Gyan.FFmpeg"],
26
+ check=True
27
+ )
28
+
29
+ elif system == "Darwin":
30
+ subprocess.run(
31
+ ["brew", "install", "ffmpeg"],
32
+ check=True
33
+ )
34
+
35
+ elif system == "Linux":
36
+ subprocess.run(
37
+ ["sudo", "apt", "install", "-y", "ffmpeg"],
38
+ check=True
39
+ )
40
+
41
+ else:
42
+ print("Unsupported operating system.")
43
+ return False
44
+
45
+ except Exception as e:
46
+ print(f"Installation failed: {e}")
47
+ return False
48
+
49
+ return shutil.which("ffplay") is not None
50
+
51
+
52
+ def get_audio_process(stream_url: str) -> subprocess.Popen | None:
53
+ if not ensure_ffplay():
54
+ print("Resuming play without audio.")
55
+ time.sleep(2)
56
+ return None
57
+
58
+ return subprocess.Popen(
59
+ [
60
+ "ffplay",
61
+ "-nodisp",
62
+ "-autoexit",
63
+ "-loglevel",
64
+ "quiet",
65
+ stream_url
66
+ ]
67
+ )
@@ -0,0 +1,41 @@
1
+ import argparse
2
+ import shutil
3
+
4
+
5
+ def get_args() -> argparse.Namespace:
6
+ parser = argparse.ArgumentParser()
7
+
8
+ parser.add_argument(
9
+ "link",
10
+ type=str,
11
+ nargs="?",
12
+ default="https://www.youtube.com/watch?v=IxX_QHay02M",
13
+ help="YouTube/video link"
14
+ )
15
+
16
+ parser.add_argument(
17
+ "--no-color",
18
+ action="store_true",
19
+ help="Disable color output"
20
+ )
21
+
22
+ parser.add_argument(
23
+ "--width",
24
+ type=int,
25
+ help="ASCII width"
26
+ )
27
+
28
+ parser.add_argument(
29
+ "--audio",
30
+ action="store_true",
31
+ help="Enable audio playback (requires ffplay)"
32
+ )
33
+
34
+ return parser.parse_args()
35
+
36
+
37
+ def get_width(args: argparse.Namespace) -> int:
38
+ if args.width is not None:
39
+ return args.width
40
+
41
+ return shutil.get_terminal_size().columns
@@ -0,0 +1,47 @@
1
+ import argparse
2
+ import subprocess
3
+
4
+ import cv2
5
+ import numpy as np
6
+
7
+ from yt2term import (
8
+ cli,
9
+ audio,
10
+ video,
11
+ render,
12
+ )
13
+
14
+
15
+ def main() -> None:
16
+ args: argparse.Namespace = cli.get_args()
17
+ color: bool = not args.no_color
18
+
19
+ stream_url: str = video.get_stream_url(link=args.link)
20
+
21
+ cap: cv2.VideoCapture = cv2.VideoCapture(stream_url)
22
+
23
+ audio_process: subprocess.Popen | None = None
24
+ if args.audio:
25
+ audio_process = audio.get_audio_process(stream_url)
26
+
27
+ render.clear_screen()
28
+ try:
29
+ while True:
30
+ width: int = cli.get_width(args)
31
+
32
+ frame: np.ndarray | None = video.read_frame(cap)
33
+
34
+ if not render.process_frame(frame, width, color):
35
+ break
36
+
37
+ except KeyboardInterrupt:
38
+ pass
39
+
40
+ finally:
41
+ cap.release()
42
+ if audio_process is not None:
43
+ audio_process.kill()
44
+
45
+
46
+ if __name__ == "__main__":
47
+ main()
@@ -0,0 +1,73 @@
1
+ import time
2
+ from typing import Callable
3
+
4
+ import cv2
5
+ import asciify
6
+ import numpy as np
7
+ from PIL import Image
8
+
9
+
10
+ # CONSTANTS
11
+ TARGET_HZ: int = 30
12
+ FRAME_DELTA_TIME: float = 1.0 / TARGET_HZ
13
+
14
+
15
+ def clear_screen() -> None:
16
+ print("\033[2J\033[H", end="")
17
+
18
+
19
+ def control_frame_rate(func: Callable) -> Callable:
20
+ def wrapper(*args, **kwargs):
21
+ start: float = time.perf_counter()
22
+
23
+ result = func(*args, **kwargs)
24
+
25
+ elapsed: float = time.perf_counter() - start
26
+ sleep_time: float = FRAME_DELTA_TIME - elapsed
27
+
28
+ if sleep_time > 0:
29
+ time.sleep(sleep_time)
30
+
31
+ return result
32
+
33
+ return wrapper
34
+
35
+
36
+ def frame_to_ascii(
37
+ frame: np.ndarray,
38
+ width: int,
39
+ color: bool
40
+ ) -> str:
41
+
42
+ rgb: np.ndarray = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
43
+
44
+ pil_image: Image.Image = Image.fromarray(rgb)
45
+
46
+ image = asciify.resize_image(pil_image, width)
47
+
48
+ return asciify.pixels_to_colored_ascii(
49
+ image,
50
+ color
51
+ )
52
+
53
+
54
+ def render_frame(art: str) -> None:
55
+ print("\033[H", end="") # Clear
56
+ print(art, end="", flush=True)
57
+
58
+
59
+ @control_frame_rate
60
+ def process_frame(
61
+ frame: np.ndarray | None,
62
+ width: int,
63
+ color: bool
64
+ ) -> bool:
65
+
66
+ if frame is None:
67
+ return False
68
+
69
+ art: str = frame_to_ascii(frame, width, color)
70
+
71
+ render_frame(art)
72
+
73
+ return True
@@ -0,0 +1,27 @@
1
+ import cv2
2
+ import numpy as np
3
+ from yt_dlp import YoutubeDL
4
+
5
+
6
+ def read_frame(cap: cv2.VideoCapture) -> np.ndarray | None:
7
+ ret, frame = cap.read()
8
+
9
+ if not ret:
10
+ return None
11
+
12
+ return frame
13
+
14
+
15
+ def get_stream_url(link: str) -> str:
16
+ ydl_opts = {
17
+ "format": "best[ext=mp4]",
18
+ "quiet": True,
19
+ "no_warnings": True,
20
+ }
21
+
22
+ with YoutubeDL(ydl_opts) as ydl:
23
+ info = ydl.extract_info(link, download=False)
24
+
25
+ stream_url: str = info["url"]
26
+
27
+ return stream_url
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.4
2
+ Name: yt2term
3
+ Version: 0.1.0
4
+ Summary: YouTube video playback in terminal as ASCII
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: opencv-python
9
+ Requires-Dist: asciifyy
10
+ Requires-Dist: pillow
11
+ Requires-Dist: yt-dlp
12
+ Dynamic: license-file
13
+
14
+ # yt2term
15
+
16
+ `yt2term` streams YouTube videos (or direct video links) as real-time ASCII art directly inside your terminal.
17
+
18
+ ## Entirely impractical - Weirdly meaningful
19
+
20
+ ---
21
+
22
+ ![example frame](images/cat_ascii.png)
23
+
24
+ ---
25
+
26
+ ## Features
27
+
28
+ - Real-time video → ASCII conversion
29
+ - ~30 FPS rendering loop
30
+ - Optional color rendering
31
+ - Adjustable output width
32
+ - Optional audio playback via `ffplay`
33
+ - Automatic FFmpeg detection
34
+
35
+ ---
36
+
37
+ ## Installation
38
+
39
+ ### Development install (recommended)
40
+
41
+ ```bash
42
+ git clone https://github.com/<your-username>/yt2term.git
43
+ cd yt2term
44
+
45
+ pip install -e .
46
+ ```
47
+
48
+ This installs the CLI command:
49
+
50
+ ```bash
51
+ yt2term
52
+ ```
53
+
54
+ ### Standard install
55
+
56
+ ```bash
57
+ pip install .
58
+ ```
59
+
60
+ Use this if you just want a normal installed package.
61
+
62
+ ---
63
+
64
+ ## Python Version
65
+
66
+ - Requires Python ≥ 3.10
67
+ - Tested on Python 3.10+ / 3.12
68
+
69
+ ---
70
+
71
+ ## Dependencies
72
+
73
+ Installed automatically via `pyproject.toml`:
74
+
75
+ - `opencv-python`
76
+ - `yt-dlp`
77
+ - `pillow`
78
+ - `asciifyy`
79
+
80
+ ---
81
+
82
+ ## Audio Support
83
+
84
+ Audio playback uses `ffplay` from FFmpeg.
85
+
86
+ Audio is disabled by default.
87
+
88
+ Enable it with:
89
+
90
+ ```bash
91
+ yt2term <link> --audio
92
+ ```
93
+
94
+ If FFmpeg is missing, the application will:
95
+
96
+ 1. Detect it automatically
97
+ 2. Explain what is missing
98
+ 3. Prompt installation
99
+ 4. Attempt installation using the system package manager
100
+
101
+ No digging through random forum posts from 2014 required.
102
+
103
+ ---
104
+
105
+ ## Usage
106
+
107
+ ### Basic playback
108
+
109
+ ```bash
110
+ yt2term <youtube-or-video-url>
111
+ ```
112
+
113
+ ### Enable audio
114
+
115
+ ```bash
116
+ yt2term <url> --audio
117
+ ```
118
+
119
+ ### Disable color output
120
+
121
+ ```bash
122
+ yt2term <url> --no-color
123
+ ```
124
+
125
+ ### Set ASCII width
126
+
127
+ ```bash
128
+ yt2term <url> --width 120
129
+ ```
130
+
131
+ ### Combined options
132
+
133
+ ```bash
134
+ yt2term <url> --audio --width 100 --no-color
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Notes
140
+
141
+ - Uses `yt-dlp` to resolve streaming URLs
142
+ - Requires an internet connection during playback
143
+ - Performance depends heavily on terminal rendering speed
144
+ - Audio/video sync is approximate
145
+ - Designed for fun, experimentation, and terminal abuse
146
+
147
+ ---
148
+
149
+ ## Exit
150
+
151
+ Press `Ctrl+C` to stop playback and return to reality.
152
+
153
+ ---
154
+
155
+ ## Project Structure
156
+
157
+ ```text
158
+ yt2term/
159
+ ├── src/
160
+ │ └── yt2term/
161
+ │ ├── main.py
162
+ │ ├── cli.py
163
+ │ ├── video.py
164
+ │ ├── audio.py
165
+ │ ├── render.py
166
+ ```
167
+
168
+ ---
169
+
170
+ ## License
171
+
172
+ MIT
173
+
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/yt2term/__init__.py
5
+ src/yt2term/audio.py
6
+ src/yt2term/cli.py
7
+ src/yt2term/main.py
8
+ src/yt2term/render.py
9
+ src/yt2term/video.py
10
+ src/yt2term.egg-info/PKG-INFO
11
+ src/yt2term.egg-info/SOURCES.txt
12
+ src/yt2term.egg-info/dependency_links.txt
13
+ src/yt2term.egg-info/entry_points.txt
14
+ src/yt2term.egg-info/requires.txt
15
+ src/yt2term.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ yt2term = yt2term.main:main
@@ -0,0 +1,4 @@
1
+ opencv-python
2
+ asciifyy
3
+ pillow
4
+ yt-dlp
@@ -0,0 +1 @@
1
+ yt2term