media-downloader 1.0.11__tar.gz → 2.0.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.
Potentially problematic release.
This version of media-downloader might be problematic. Click here for more details.
- {media_downloader-1.0.11/media_downloader.egg-info → media_downloader-2.0.0}/PKG-INFO +2 -2
- {media_downloader-1.0.11 → media_downloader-2.0.0}/README.md +1 -1
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader/__init__.py +9 -2
- media_downloader-2.0.0/media_downloader/__main__.py +8 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader/media_downloader.py +39 -37
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader/media_downloader_mcp.py +39 -47
- {media_downloader-1.0.11 → media_downloader-2.0.0/media_downloader.egg-info}/PKG-INFO +2 -2
- media_downloader-2.0.0/media_downloader.egg-info/entry_points.txt +3 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/pyproject.toml +4 -4
- media_downloader-1.0.11/media_downloader/__main__.py +0 -6
- media_downloader-1.0.11/media_downloader.egg-info/entry_points.txt +0 -3
- {media_downloader-1.0.11 → media_downloader-2.0.0}/LICENSE +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/MANIFEST.in +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader.egg-info/SOURCES.txt +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader.egg-info/dependency_links.txt +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader.egg-info/requires.txt +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader.egg-info/top_level.txt +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/requirements.txt +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/setup.cfg +0 -0
- {media_downloader-1.0.11 → media_downloader-2.0.0}/tests/test_mcp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: media-downloader
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Download audio/videos from the internet!
|
|
5
5
|
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -38,7 +38,7 @@ Dynamic: license-file
|
|
|
38
38
|

|
|
39
39
|

|
|
40
40
|
|
|
41
|
-
*Version:
|
|
41
|
+
*Version: 2.0.0*
|
|
42
42
|
|
|
43
43
|
Download videos and audio from the internet!
|
|
44
44
|
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
from media_downloader.media_downloader import (
|
|
5
5
|
media_downloader,
|
|
6
|
-
main,
|
|
7
6
|
setup_logging,
|
|
8
7
|
MediaDownloader,
|
|
9
8
|
)
|
|
9
|
+
from media_downloader.media_downloader_mcp import (
|
|
10
|
+
media_downloader_mcp,
|
|
11
|
+
)
|
|
10
12
|
|
|
11
13
|
"""
|
|
12
14
|
media-downloader
|
|
@@ -14,4 +16,9 @@ media-downloader
|
|
|
14
16
|
Download videos and audio from the internet!
|
|
15
17
|
"""
|
|
16
18
|
|
|
17
|
-
__all__ = [
|
|
19
|
+
__all__ = [
|
|
20
|
+
"media_downloader",
|
|
21
|
+
"media_downloader_mcp",
|
|
22
|
+
"setup_logging",
|
|
23
|
+
"MediaDownloader",
|
|
24
|
+
]
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
6
|
import re
|
|
7
|
-
import
|
|
7
|
+
import argparse
|
|
8
8
|
import logging
|
|
9
9
|
import requests
|
|
10
10
|
import yt_dlp
|
|
@@ -65,6 +65,12 @@ class MediaDownloader:
|
|
|
65
65
|
def set_progress_callback(self, callback):
|
|
66
66
|
self.progress_callback = callback
|
|
67
67
|
|
|
68
|
+
def open_file(self, file):
|
|
69
|
+
youtube_urls = open(file, "r")
|
|
70
|
+
for url in youtube_urls:
|
|
71
|
+
self.links.append(url)
|
|
72
|
+
self.links = list(dict.fromkeys(self.links))
|
|
73
|
+
|
|
68
74
|
def download_video(self, link):
|
|
69
75
|
self.logger.debug(f"Downloading video: {link}")
|
|
70
76
|
outtmpl = f"{self.download_directory}/%(uploader)s - %(title)s.%(ext)s"
|
|
@@ -189,39 +195,6 @@ class MediaDownloader:
|
|
|
189
195
|
pool.join()
|
|
190
196
|
|
|
191
197
|
|
|
192
|
-
def media_downloader(argv):
|
|
193
|
-
logger = setup_logging(is_mcp_server=False)
|
|
194
|
-
video_downloader_instance = MediaDownloader()
|
|
195
|
-
try:
|
|
196
|
-
opts, args = getopt.getopt(
|
|
197
|
-
argv,
|
|
198
|
-
"hac:d:f:l:",
|
|
199
|
-
["help", "audio", "channel=", "directory=", "file=", "links="],
|
|
200
|
-
)
|
|
201
|
-
except getopt.GetoptError:
|
|
202
|
-
usage()
|
|
203
|
-
logger.error("Incorrect arguments")
|
|
204
|
-
sys.exit(2)
|
|
205
|
-
for opt, arg in opts:
|
|
206
|
-
if opt in ("-h", "--help"):
|
|
207
|
-
usage()
|
|
208
|
-
sys.exit()
|
|
209
|
-
elif opt in ("-a", "--audio"):
|
|
210
|
-
video_downloader_instance.audio = True
|
|
211
|
-
elif opt in ("-c", "--channel"):
|
|
212
|
-
video_downloader_instance.get_channel_videos(arg)
|
|
213
|
-
elif opt in ("-d", "--directory"):
|
|
214
|
-
video_downloader_instance.download_directory = arg
|
|
215
|
-
elif opt in ("-f", "--file"):
|
|
216
|
-
video_downloader_instance.open_file(arg)
|
|
217
|
-
elif opt in ("-l", "--links"):
|
|
218
|
-
url_list = arg.replace(" ", "").split(",")
|
|
219
|
-
for url in url_list:
|
|
220
|
-
video_downloader_instance.links.extend(url_list)
|
|
221
|
-
|
|
222
|
-
video_downloader_instance.download_all()
|
|
223
|
-
|
|
224
|
-
|
|
225
198
|
def usage():
|
|
226
199
|
print(
|
|
227
200
|
"Media-Downloader: A tool to download any video off the internet!\n"
|
|
@@ -237,9 +210,38 @@ def usage():
|
|
|
237
210
|
)
|
|
238
211
|
|
|
239
212
|
|
|
240
|
-
def
|
|
241
|
-
|
|
213
|
+
def media_downloader():
|
|
214
|
+
parser = argparse.ArgumentParser(description="Download media from various sources.")
|
|
215
|
+
parser.add_argument(
|
|
216
|
+
"-a", "--audio", action="store_true", help="Download audio only"
|
|
217
|
+
)
|
|
218
|
+
parser.add_argument("-c", "--channel", help="Download videos from a channel URL")
|
|
219
|
+
parser.add_argument("-d", "--directory", help="Specify download directory")
|
|
220
|
+
parser.add_argument("-f", "--file", help="Read URLs from a file")
|
|
221
|
+
parser.add_argument(
|
|
222
|
+
"-l", "--links", help="Comma-separated list of URLs to download"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
args = parser.parse_args()
|
|
226
|
+
|
|
227
|
+
logger = setup_logging(is_mcp_server=False)
|
|
228
|
+
video_downloader_instance = MediaDownloader()
|
|
229
|
+
|
|
230
|
+
if args.audio:
|
|
231
|
+
video_downloader_instance.audio = True
|
|
232
|
+
if args.channel:
|
|
233
|
+
video_downloader_instance.get_channel_videos(args.channel)
|
|
234
|
+
if args.directory:
|
|
235
|
+
video_downloader_instance.download_directory = args.directory
|
|
236
|
+
if args.file:
|
|
237
|
+
video_downloader_instance.open_file(args.file)
|
|
238
|
+
if args.links:
|
|
239
|
+
url_list = args.links.replace(" ", "").split(",")
|
|
240
|
+
video_downloader_instance.links.extend(url_list)
|
|
241
|
+
|
|
242
|
+
logger.info("Kicking off downloads...")
|
|
243
|
+
video_downloader_instance.download_all()
|
|
242
244
|
|
|
243
245
|
|
|
244
246
|
if __name__ == "__main__":
|
|
245
|
-
media_downloader(
|
|
247
|
+
media_downloader()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/python
|
|
2
2
|
# coding: utf-8
|
|
3
|
-
import
|
|
3
|
+
import argparse
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
6
|
import logging
|
|
@@ -14,13 +14,14 @@ setup_logging(is_mcp_server=True, log_file="media_downloader_mcp.log")
|
|
|
14
14
|
|
|
15
15
|
mcp = FastMCP(name="MediaDownloaderServer")
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
def to_boolean(string):
|
|
18
19
|
# Normalize the string: strip whitespace and convert to lowercase
|
|
19
20
|
normalized = str(string).strip().lower()
|
|
20
21
|
|
|
21
22
|
# Define valid true/false values
|
|
22
|
-
true_values = {
|
|
23
|
-
false_values = {
|
|
23
|
+
true_values = {"t", "true", "y", "yes", "1"}
|
|
24
|
+
false_values = {"f", "false", "n", "no", "0"}
|
|
24
25
|
|
|
25
26
|
if normalized in true_values:
|
|
26
27
|
return True
|
|
@@ -29,11 +30,6 @@ def to_boolean(string):
|
|
|
29
30
|
else:
|
|
30
31
|
raise ValueError(f"Cannot convert '{string}' to boolean")
|
|
31
32
|
|
|
32
|
-
environment_download_directory = os.environ.get("DOWNLOAD_DIRECTORY", None)
|
|
33
|
-
environment_audio_only = os.environ.get("AUDIO_ONLY", False)
|
|
34
|
-
|
|
35
|
-
if environment_audio_only:
|
|
36
|
-
environment_audio_only = to_boolean(environment_audio_only)
|
|
37
33
|
|
|
38
34
|
@mcp.tool(
|
|
39
35
|
annotations={
|
|
@@ -49,9 +45,15 @@ async def download_media(
|
|
|
49
45
|
video_url: str = Field(description="Video URL to Download", default=None),
|
|
50
46
|
download_directory: Optional[str] = Field(
|
|
51
47
|
description="The directory where the media will be saved. If None, uses default directory.",
|
|
52
|
-
default=
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
default=os.environ.get("DOWNLOAD_DIRECTORY", None),
|
|
49
|
+
),
|
|
50
|
+
audio_only: Optional[bool] = Field(
|
|
51
|
+
description="Downloads only the audio",
|
|
52
|
+
default=to_boolean(os.environ.get("AUDIO_ONLY", False)),
|
|
53
|
+
),
|
|
54
|
+
ctx: Context = Field(
|
|
55
|
+
description="MCP context for progress reporting.", default=None
|
|
56
|
+
),
|
|
55
57
|
) -> str:
|
|
56
58
|
"""Downloads media from a given URL to the specified directory."""
|
|
57
59
|
logger = logging.getLogger("MediaDownloader")
|
|
@@ -101,47 +103,37 @@ async def download_media(
|
|
|
101
103
|
raise RuntimeError(f"Failed to download media: {str(e)}")
|
|
102
104
|
|
|
103
105
|
|
|
104
|
-
def media_downloader_mcp(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
print(f"Error: Port {arg} is out of valid range (0-65535).")
|
|
128
|
-
sys.exit(1)
|
|
129
|
-
except ValueError:
|
|
130
|
-
print(f"Error: Port {arg} is not a valid integer.")
|
|
131
|
-
sys.exit(1)
|
|
132
|
-
if transport == "stdio":
|
|
106
|
+
def media_downloader_mcp():
|
|
107
|
+
parser = argparse.ArgumentParser(description="Run media downloader MCP server.")
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"-t",
|
|
110
|
+
"--transport",
|
|
111
|
+
default="stdio",
|
|
112
|
+
choices=["stdio", "http"],
|
|
113
|
+
help="Transport method (stdio or http, default: stdio)",
|
|
114
|
+
)
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"-s", "--host", default="0.0.0.0", help="Host address (default: 0.0.0.0)"
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"-p", "--port", type=int, default=8000, help="Port number (default: 8000)"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
args = parser.parse_args()
|
|
123
|
+
|
|
124
|
+
if args.port < 0 or args.port > 65535:
|
|
125
|
+
print(f"Error: Port {args.port} is out of valid range (0-65535).")
|
|
126
|
+
sys.exit(1)
|
|
127
|
+
|
|
128
|
+
if args.transport == "stdio":
|
|
133
129
|
mcp.run(transport="stdio")
|
|
134
|
-
elif transport == "http":
|
|
135
|
-
mcp.run(transport="http", host=host, port=port)
|
|
130
|
+
elif args.transport == "http":
|
|
131
|
+
mcp.run(transport="http", host=args.host, port=args.port)
|
|
136
132
|
else:
|
|
137
133
|
logger = logging.getLogger("MediaDownloader")
|
|
138
134
|
logger.error("Transport not supported")
|
|
139
135
|
sys.exit(1)
|
|
140
136
|
|
|
141
137
|
|
|
142
|
-
def main():
|
|
143
|
-
media_downloader_mcp(sys.argv[1:])
|
|
144
|
-
|
|
145
|
-
|
|
146
138
|
if __name__ == "__main__":
|
|
147
|
-
media_downloader_mcp(
|
|
139
|
+
media_downloader_mcp()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: media-downloader
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Download audio/videos from the internet!
|
|
5
5
|
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -38,7 +38,7 @@ Dynamic: license-file
|
|
|
38
38
|

|
|
39
39
|

|
|
40
40
|
|
|
41
|
-
*Version:
|
|
41
|
+
*Version: 2.0.0*
|
|
42
42
|
|
|
43
43
|
Download videos and audio from the internet!
|
|
44
44
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "media-downloader"
|
|
7
|
-
version = "
|
|
7
|
+
version = "2.0.0"
|
|
8
8
|
description = "Download audio/videos from the internet!\nHost an MCP Server for Agentic AI to download videos!"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Audel Rouhi", email = "knucklessg1@gmail.com" }]
|
|
@@ -23,12 +23,12 @@ dependencies = [
|
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
[project.scripts]
|
|
26
|
-
media-downloader = "media_downloader.media_downloader:
|
|
27
|
-
media-downloader-mcp = "media_downloader.media_downloader_mcp:
|
|
26
|
+
media-downloader = "media_downloader.media_downloader:media_downloader"
|
|
27
|
+
media-downloader-mcp = "media_downloader.media_downloader_mcp:media_downloader_mcp"
|
|
28
28
|
|
|
29
29
|
[tool.setuptools.packages.find]
|
|
30
30
|
where = ["."]
|
|
31
31
|
|
|
32
32
|
[tool.setuptools]
|
|
33
33
|
include-package-data = true
|
|
34
|
-
package-data = { "media_downloader" = ["media_downloader"] }
|
|
34
|
+
package-data = { "media_downloader" = ["media_downloader"] }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{media_downloader-1.0.11 → media_downloader-2.0.0}/media_downloader.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|