yt-dlp-host-api 0.2.0__py3-none-any.whl → 0.2.1__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.
yt_dlp_host_api/client.py CHANGED
@@ -9,43 +9,47 @@ class Client:
9
9
  self.headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
10
10
  self.send_task = self.SendTask(self)
11
11
 
12
- def get_video(self, url, video_format="bestvideo", audio_format="bestaudio", output_format="mp4", start_time=None, end_time=None, force_keyframes=False):
12
+ def get_video(self, url, video_format="bestvideo", audio_format="bestaudio", audio_language=None, output_format="mp4", start_time=None, end_time=None, force_keyframes=False):
13
13
  return self.send_task.get_video(
14
14
  url=url,
15
15
  video_format=video_format,
16
16
  audio_format=audio_format,
17
+ audio_language=audio_language,
17
18
  output_format=output_format,
18
19
  start_time=start_time,
19
20
  end_time=end_time,
20
21
  force_keyframes=force_keyframes
21
22
  ).get_result()
22
23
 
23
- def get_audio(self, url, audio_format="bestaudio", output_format=None, start_time=None, end_time=None, force_keyframes=False):
24
+ def get_audio(self, url, audio_format="bestaudio", audio_language=None, output_format=None, start_time=None, end_time=None, force_keyframes=False):
24
25
  return self.send_task.get_audio(
25
26
  url=url,
26
27
  audio_format=audio_format,
28
+ audio_language=audio_language,
27
29
  output_format=output_format,
28
30
  start_time=start_time,
29
31
  end_time=end_time,
30
32
  force_keyframes=force_keyframes
31
33
  ).get_result()
32
34
 
33
- def get_live_video(self, url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", output_format="mp4"):
35
+ def get_live_video(self, url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", audio_language=None, output_format="mp4"):
34
36
  return self.send_task.get_live_video(
35
37
  url=url,
36
38
  start=start,
37
39
  duration=duration,
38
40
  video_format=video_format,
39
41
  audio_format=audio_format,
42
+ audio_language=audio_language,
40
43
  output_format=output_format
41
44
  ).get_result()
42
45
 
43
- def get_live_audio(self, url, duration, start=0, audio_format="bestaudio", output_format=None):
46
+ def get_live_audio(self, url, duration, start=0, audio_format="bestaudio", audio_language=None, output_format=None):
44
47
  return self.send_task.get_live_audio(
45
48
  url=url,
46
49
  start=start,
47
50
  duration=duration,
48
51
  audio_format=audio_format,
52
+ audio_language=audio_language,
49
53
  output_format=output_format
50
54
  ).get_result()
51
55
 
@@ -90,7 +94,7 @@ class Client:
90
94
  def __init__(self, client):
91
95
  self.client = client
92
96
 
93
- def get_video(self, url, video_format="bestvideo", audio_format="bestaudio", output_format="mp4", start_time=None, end_time=None, force_keyframes=False):
97
+ def get_video(self, url, video_format="bestvideo", audio_format="bestaudio", audio_language=None, output_format="mp4", start_time=None, end_time=None, force_keyframes=False):
94
98
  data = {
95
99
  "url": url,
96
100
  "video_format": video_format,
@@ -98,6 +102,7 @@ class Client:
98
102
  "output_format": output_format,
99
103
  "force_keyframes": force_keyframes
100
104
  }
105
+ if audio_language is not None: data["audio_language"] = audio_language
101
106
  if start_time is not None: data["start_time"] = start_time
102
107
  if end_time is not None: data["end_time"] = end_time
103
108
 
@@ -106,12 +111,13 @@ class Client:
106
111
  raise APIError(response.json().get('error', 'Unknown error'))
107
112
  return Task(self.client, response.json()['task_id'], 'get_video')
108
113
 
109
- def get_audio(self, url, audio_format="bestaudio", output_format=None, start_time=None, end_time=None, force_keyframes=False):
114
+ def get_audio(self, url, audio_format="bestaudio", audio_language=None, output_format=None, start_time=None, end_time=None, force_keyframes=False):
110
115
  data = {
111
116
  "url": url,
112
117
  "audio_format": audio_format,
113
118
  "force_keyframes": force_keyframes
114
119
  }
120
+ if audio_language is not None: data["audio_language"] = audio_language
115
121
  if output_format is not None: data["output_format"] = output_format
116
122
  if start_time is not None: data["start_time"] = start_time
117
123
  if end_time is not None: data["end_time"] = end_time
@@ -121,7 +127,7 @@ class Client:
121
127
  raise APIError(response.json().get('error', 'Unknown error'))
122
128
  return Task(self.client, response.json()['task_id'], 'get_audio')
123
129
 
124
- def get_live_video(self, url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", output_format="mp4"):
130
+ def get_live_video(self, url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", audio_language=None, output_format="mp4"):
125
131
  data = {
126
132
  "url": url,
127
133
  "start": start,
@@ -130,18 +136,21 @@ class Client:
130
136
  "audio_format": audio_format,
131
137
  "output_format": output_format
132
138
  }
139
+ if audio_language is not None: data["audio_language"] = audio_language
140
+
133
141
  response = requests.post(f"{self.client.host_url}/get_live_video", json=data, headers=self.client.headers)
134
142
  if response.status_code != 200:
135
143
  raise APIError(response.json().get('error', 'Unknown error'))
136
144
  return Task(self.client, response.json()['task_id'], 'get_video')
137
145
 
138
- def get_live_audio(self, url, duration, start=0, audio_format="bestaudio", output_format=None):
146
+ def get_live_audio(self, url, duration, start=0, audio_format="bestaudio", audio_language=None, output_format=None):
139
147
  data = {
140
148
  "url": url,
141
149
  "start": start,
142
150
  "duration": duration,
143
151
  "audio_format": audio_format
144
152
  }
153
+ if audio_language is not None: data["audio_language"] = audio_language
145
154
  if output_format is not None: data["output_format"] = output_format
146
155
 
147
156
  response = requests.post(f"{self.client.host_url}/get_live_audio", json=data, headers=self.client.headers)
yt_dlp_host_api/task.py CHANGED
@@ -58,11 +58,25 @@ class TaskResult:
58
58
  raise APIError("This method is only available for get_info tasks")
59
59
  url = self.get_file_url()
60
60
  if fields:
61
- url += "?"
62
- for field in fields:
63
- url += f'{field}&'
61
+ if isinstance(fields, str):
62
+ url += f"?{fields}"
63
+ else:
64
+ url += "?"
65
+ for field in fields:
66
+ url += f'{field}&'
67
+ url = url.rstrip('&')
64
68
  response = requests.get(url, headers=self.client.headers)
65
69
  if response.status_code != 200:
66
70
  raise APIError(response.json().get('error', 'Unknown error'))
67
71
  data = json.loads(response.text)
68
72
  return data
73
+
74
+ def get_qualities(self):
75
+ if self.status['task_type'] != 'get_info':
76
+ raise APIError("This method is only available for get_info tasks")
77
+ return self.get_json('qualities')
78
+
79
+ def get_languages(self):
80
+ if self.status['task_type'] != 'get_info':
81
+ raise APIError("This method is only available for get_info tasks")
82
+ return self.get_json('languages')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yt_dlp_host_api
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: A Python library for interacting with the yt-dlp-host API
5
5
  Author-email: "Amadeus (Wasys)" <tubik.corp@gmail.com>
6
6
  License-Expression: MIT
@@ -73,8 +73,20 @@ print("Audio saved to test_audio.mp3")
73
73
  client.get_audio(url='https://youtu.be/1FPdtR_5KFo', output_format='flac').save_file("test_audio.flac")
74
74
  print("Audio saved to test_audio.flac")
75
75
 
76
- # Get info
77
- info_json = client.get_info(url='https://youtu.be/1FPdtR_5KFo').get_json(['qualities', 'title'])
76
+ # Get info with available qualities and languages
77
+ info_result = client.get_info(url='https://youtu.be/1FPdtR_5KFo')
78
+
79
+ # Get available qualities
80
+ qualities = info_result.get_qualities()
81
+ print("Available qualities:", qualities)
82
+
83
+ # Get available languages
84
+ languages = info_result.get_languages()
85
+ print("Available audio languages:", languages['languages']['audio'])
86
+ print("Available subtitle languages:", languages['languages']['subtitles'])
87
+
88
+ # Get specific fields from info
89
+ info_json = info_result.get_json(['title', 'duration', 'upload_date'])
78
90
  print("Video info:", info_json)
79
91
 
80
92
  # Admin operations (requires admin API key)
@@ -93,13 +105,18 @@ client.delete_key("user_key")
93
105
  - Fast cutting at keyframes
94
106
  - Choose video and audio quality
95
107
  - Choose output format (MP4, MKV, WebM, AVI, MOV, FLV, 3GP)
108
+ - Select specific audio language or download all audio tracks
96
109
  - Download YouTube audio
97
110
  - Download complete audio
98
111
  - Download specific time segments
99
112
  - Choose audio quality
100
113
  - Choose output format (MP3, M4A, Opus, FLAC, WAV, AAC, OGG)
114
+ - Select specific audio language
101
115
  - Extract live stream segments
102
116
  - Retrieve video information
117
+ - Get available video and audio qualities
118
+ - Get available audio and subtitle languages
119
+ - Filter specific fields from video metadata
103
120
  - Checking client permissions
104
121
  - Admin operations:
105
122
  - Create new API keys
@@ -111,15 +128,15 @@ client.delete_key("user_key")
111
128
 
112
129
  ### Client
113
130
 
114
- - `client.get_video(url, video_format="bestvideo", audio_format="bestaudio", output_format="mp4", start_time=None, end_time=None, force_keyframes=False)`: Get video with optional time segment selection
115
- - `client.get_audio(url, audio_format="bestaudio", output_format=None, start_time=None, end_time=None, force_keyframes=False)`: Get audio with optional time segment selection
116
- - `client.get_live_video(url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", output_format="mp4")`: Get live video segment
117
- - `client.get_live_audio(url, duration, start=0, audio_format="bestaudio", output_format=None)`: Get live audio segment
131
+ - `client.get_video(url, video_format="bestvideo", audio_format="bestaudio", audio_language=None, output_format="mp4", start_time=None, end_time=None, force_keyframes=False)`: Get video with optional time segment selection and language preference
132
+ - `client.get_audio(url, audio_format="bestaudio", audio_language=None, output_format=None, start_time=None, end_time=None, force_keyframes=False)`: Get audio with optional time segment selection and language preference
133
+ - `client.get_live_video(url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", audio_language=None, output_format="mp4")`: Get live video segment with language preference
134
+ - `client.get_live_audio(url, duration, start=0, audio_format="bestaudio", audio_language=None, output_format=None)`: Get live audio segment with language preference
118
135
  - `client.get_info(url)`: Get video information
119
- - `client.send_task.get_video(url, video_format="bestvideo", audio_format="bestaudio", output_format="mp4", start_time=None, end_time=None, force_keyframes=False)`: Initiate a video download task
120
- - `client.send_task.get_audio(url, audio_format="bestaudio", output_format=None, start_time=None, end_time=None, force_keyframes=False)`: Initiate an audio download task
121
- - `client.send_task.get_live_video(url, duration, start=0, video_format="bestvideo", audio_format="bestaudio", output_format="mp4")`: Initiate a live video download task
122
- - `client.send_task.get_live_audio(url, duration, start=0, audio_format="bestaudio", output_format=None)`: Initiate a live audio download task
136
+ - `client.send_task.get_video(...)`: Initiate a video download task
137
+ - `client.send_task.get_audio(...)`: Initiate an audio download task
138
+ - `client.send_task.get_live_video(...)`: Initiate a live video download task
139
+ - `client.send_task.get_live_audio(...)`: Initiate a live audio download task
123
140
  - `client.send_task.get_info(url)`: Initiate an info retrieval task
124
141
  - `client.check_permissions(permissions)`: Check for all permissions in the list
125
142
 
@@ -127,7 +144,7 @@ client.delete_key("user_key")
127
144
 
128
145
  #### Video Formats
129
146
  - **mp4** - MPEG-4 Part 14 (recommended)
130
- - **mkv** - Matroska
147
+ - **mkv** - Matroska (supports multiple audio tracks)
131
148
  - **webm** - WebM
132
149
  - **avi** - Audio Video Interleave
133
150
  - **mov** - QuickTime File Format
@@ -145,10 +162,30 @@ client.delete_key("user_key")
145
162
 
146
163
  Note: If `output_format` is not specified for audio, the original format will be used.
147
164
 
165
+ ### Audio Language Support
166
+
167
+ The `audio_language` parameter allows you to specify which audio track to download:
168
+ - **None** (default): yt-dlp automatically selects the best available audio track
169
+ - **ISO Language Code** (e.g., "en", "ru", "es", "de", "fr", "ja"): Downloads the specific language audio track
170
+ - **"all"**: Downloads all available audio tracks (video will be saved in MKV format with multiple audio streams)
171
+
172
+ Examples:
173
+ ```python
174
+ # Default audio track (auto-selected by yt-dlp)
175
+ client.get_video(url='...', output_format='mp4')
176
+
177
+ # Specific language
178
+ client.get_video(url='...', audio_language='ru', output_format='mp4')
179
+
180
+ # All audio tracks
181
+ client.get_video(url='...', audio_language='all', output_format='mkv')
182
+ ```
183
+
148
184
  ### Time Format
149
185
 
150
186
  Time parameters (`start_time` and `end_time`) should be provided in the following format:
151
187
  - "HH:MM:SS" (hours:minutes:seconds)
188
+
152
189
  Examples:
153
190
  - "00:05:00" - 5 minutes
154
191
  - "01:30:45" - 1 hour, 30 minutes, and 45 seconds
@@ -166,10 +203,12 @@ The `force_keyframes` parameter determines how video/audio segments are cut:
166
203
 
167
204
  ### TaskResult
168
205
 
169
- - `result.get_file()`: Get the file
206
+ - `result.get_file()`: Get the file content
170
207
  - `result.get_file_url()`: Get the URL of the downloaded file
171
208
  - `result.save_file(path)`: Save the downloaded file to the specified path
172
209
  - `result.get_json(fields=None)`: Get the JSON data for info tasks (optionally filtered by fields)
210
+ - `result.get_qualities()`: Get available video and audio qualities (info tasks only)
211
+ - `result.get_languages()`: Get available audio and subtitle languages (info tasks only)
173
212
 
174
213
  ### Admin
175
214
 
@@ -178,10 +217,90 @@ The `force_keyframes` parameter determines how video/audio segments are cut:
178
217
  - `client.get_key(name)`: Get API key by key name
179
218
  - `client.delete_key(name)`: Delete an API key
180
219
 
220
+ ## Advanced Examples
221
+
222
+ ### Checking available languages before downloading
223
+
224
+ ```python
225
+ import yt_dlp_host_api
226
+
227
+ api = yt_dlp_host_api.api('http://your-api-url.com')
228
+ client = api.get_client('YOUR_API_KEY')
229
+
230
+ # First, get video info to check available languages
231
+ info_result = client.get_info(url='https://youtu.be/1FPdtR_5KFo')
232
+ languages = info_result.get_languages()
233
+
234
+ print(f"Available audio languages: {languages['languages']['audio']}")
235
+ print(f"Available subtitle languages: {languages['languages']['subtitles']}")
236
+
237
+ # Download with a specific language if available
238
+ if 'ru' in languages['languages']['audio']:
239
+ client.get_video(
240
+ url='https://youtu.be/1FPdtR_5KFo',
241
+ audio_language='ru',
242
+ output_format='mp4'
243
+ ).save_file("video_russian.mp4")
244
+ print("Downloaded video with Russian audio")
245
+ ```
246
+
247
+ ### Getting video qualities information
248
+
249
+ ```python
250
+ import yt_dlp_host_api
251
+
252
+ api = yt_dlp_host_api.api('http://your-api-url.com')
253
+ client = api.get_client('YOUR_API_KEY')
254
+
255
+ info_result = client.get_info(url='https://youtu.be/1FPdtR_5KFo')
256
+ qualities = info_result.get_qualities()
257
+
258
+ # Display available video qualities
259
+ print("Available video qualities:")
260
+ for format_id, details in qualities['qualities']['video'].items():
261
+ print(f" Format {format_id}: {details['height']}p, {details['fps']}fps, {details['vcodec']}")
262
+
263
+ # Display available audio qualities
264
+ print("\nAvailable audio qualities:")
265
+ for format_id, details in qualities['qualities']['audio'].items():
266
+ print(f" Format {format_id}: {details['abr']}kbps, {details['acodec']}, language: {details.get('language', 'unknown')}")
267
+ ```
268
+
269
+ ### Downloading with specific quality selection
270
+
271
+ ```python
272
+ import yt_dlp_host_api
273
+
274
+ api = yt_dlp_host_api.api('http://your-api-url.com')
275
+ client = api.get_client('YOUR_API_KEY')
276
+
277
+ # Download 720p video with 128kbps audio
278
+ client.get_video(
279
+ url='https://youtu.be/1FPdtR_5KFo',
280
+ video_format='bestvideo[height<=720]',
281
+ audio_format='bestaudio[abr<=128]',
282
+ output_format='mp4'
283
+ ).save_file("video_720p_128k.mp4")
284
+ ```
285
+
181
286
  ## Error Handling
182
287
 
183
288
  The library uses exceptions to handle errors. Catch `yt_dlp_host_api.exceptions.APIError` to handle API-related errors.
184
289
 
290
+ ```python
291
+ import yt_dlp_host_api
292
+ from yt_dlp_host_api.exceptions import APIError
293
+
294
+ api = yt_dlp_host_api.api('http://your-api-url.com')
295
+ client = api.get_client('YOUR_API_KEY')
296
+
297
+ try:
298
+ result = client.get_video(url='https://youtu.be/invalid-url')
299
+ result.save_file("video.mp4")
300
+ except APIError as e:
301
+ print(f"API Error: {e}")
302
+ ```
303
+
185
304
  ## Contributing
186
305
 
187
306
  Contributions to yt-dlp-host-api are welcome! If you have any suggestions, bug reports, or feature requests, please open an issue on the GitHub repository. Pull requests are also encouraged.
@@ -0,0 +1,10 @@
1
+ yt_dlp_host_api/__init__.py,sha256=RHx1BvH2Cy_dweEKo5sA-hdBOfBdY_2ds7srPuKGzWQ,41
2
+ yt_dlp_host_api/api.py,sha256=iLzWKoyiXeu0Y1Uky8PzpxxHTSMcTGzxlCRT121AKcM,196
3
+ yt_dlp_host_api/client.py,sha256=d0EUMGS-k4ndKG_xATDkg6hQgSUsSH_z_aDFkz95dp0,8126
4
+ yt_dlp_host_api/exceptions.py,sha256=U_70W1R_ZcUfKptUShGB5VPWQXwc5M29_sNC8pwwq8g,38
5
+ yt_dlp_host_api/task.py,sha256=pn0KcEfCDrSuE0DUnAF1YGpMnJL6vc3sXN2im1jBdeI,3244
6
+ yt_dlp_host_api-0.2.1.dist-info/licenses/LICENSE,sha256=-_Ad_xue4UymJ8jO-ZsSg0vmZ6SUm8WYdoEwHLyBUlc,1078
7
+ yt_dlp_host_api-0.2.1.dist-info/METADATA,sha256=6t-5ua00ltERunJqjlO1EaTOq_DPJtKEwNgBp5nbtu4,11261
8
+ yt_dlp_host_api-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ yt_dlp_host_api-0.2.1.dist-info/top_level.txt,sha256=Mn3FZuqLCHr47sRjhtEOz7lDl4lpsHkymWANORYp72s,16
10
+ yt_dlp_host_api-0.2.1.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- yt_dlp_host_api/__init__.py,sha256=RHx1BvH2Cy_dweEKo5sA-hdBOfBdY_2ds7srPuKGzWQ,41
2
- yt_dlp_host_api/api.py,sha256=iLzWKoyiXeu0Y1Uky8PzpxxHTSMcTGzxlCRT121AKcM,196
3
- yt_dlp_host_api/client.py,sha256=5Wf7Ue0A1HQX2EuaBk_TndOpWoDlb6t5NBslB0EljGI,7432
4
- yt_dlp_host_api/exceptions.py,sha256=U_70W1R_ZcUfKptUShGB5VPWQXwc5M29_sNC8pwwq8g,38
5
- yt_dlp_host_api/task.py,sha256=llgBAO_L1CajklMsbICdRpLdOV05Wi0oUh9NKj0bD0w,2674
6
- yt_dlp_host_api-0.2.0.dist-info/licenses/LICENSE,sha256=-_Ad_xue4UymJ8jO-ZsSg0vmZ6SUm8WYdoEwHLyBUlc,1078
7
- yt_dlp_host_api-0.2.0.dist-info/METADATA,sha256=NBsJNdGgaSDD3z5Q-S7Sd1ZdjuXbQm8k_064IfMVBf0,7368
8
- yt_dlp_host_api-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- yt_dlp_host_api-0.2.0.dist-info/top_level.txt,sha256=Mn3FZuqLCHr47sRjhtEOz7lDl4lpsHkymWANORYp72s,16
10
- yt_dlp_host_api-0.2.0.dist-info/RECORD,,