MP4MDL 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.
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.1
2
+ Name: MP4MDL
3
+ Version: 0.1.0
4
+ Summary: Un outil pour télécharger et gérer des vidéos MP4
5
+ Home-page: https://git.maddoxserv.com/maddox/MP4MDL
6
+ Author: Maddox
7
+ Author-email: maddoxtes@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Description
15
+
16
+ This project is a library that allows you to download MP4 files with video links.
17
+
18
+ # Website Supported
19
+
20
+ - ✅ video.sibnet.ru
21
+ - ✅ vidmoly.to
22
+ - ✅ oneupload.to
23
+ - ✅ sendvid.com
@@ -0,0 +1,21 @@
1
+ setup.py
2
+ MP4MDL.egg-info/PKG-INFO
3
+ MP4MDL.egg-info/SOURCES.txt
4
+ MP4MDL.egg-info/dependency_links.txt
5
+ MP4MDL.egg-info/entry_points.txt
6
+ MP4MDL.egg-info/requires.txt
7
+ MP4MDL.egg-info/top_level.txt
8
+ mp4mdl/__init__.py
9
+ mp4mdl/mp4mdl.py
10
+ mp4mdl/download/__init__.py
11
+ mp4mdl/download/mp4_downloader.py
12
+ mp4mdl/download/segment_downloader.py
13
+ mp4mdl/lecteur/__init__.py
14
+ mp4mdl/lecteur/oneupload.py
15
+ mp4mdl/lecteur/sendvid.py
16
+ mp4mdl/lecteur/sibnet.py
17
+ mp4mdl/lecteur/vidmoly.py
18
+ mp4mdl/scrap/__init__.py
19
+ mp4mdl/scrap/get_best_qualite_url.py
20
+ mp4mdl/scrap/get_m3u8_url.py
21
+ mp4mdl/scrap/get_mp4_url.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mp4mdl = mp4mdl.main:main
@@ -0,0 +1,3 @@
1
+ requests
2
+ beautifulsoup4
3
+ ffmpeg-python
@@ -0,0 +1 @@
1
+ mp4mdl
MP4MDL-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.1
2
+ Name: MP4MDL
3
+ Version: 0.1.0
4
+ Summary: Un outil pour télécharger et gérer des vidéos MP4
5
+ Home-page: https://git.maddoxserv.com/maddox/MP4MDL
6
+ Author: Maddox
7
+ Author-email: maddoxtes@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Description
15
+
16
+ This project is a library that allows you to download MP4 files with video links.
17
+
18
+ # Website Supported
19
+
20
+ - ✅ video.sibnet.ru
21
+ - ✅ vidmoly.to
22
+ - ✅ oneupload.to
23
+ - ✅ sendvid.com
@@ -0,0 +1,7 @@
1
+ """
2
+ MP4MDL - Un outil pour télécharger et gérer des vidéos MP4
3
+ """
4
+
5
+ __version__ = "0.1.0"
6
+
7
+ from .mp4mdl import mp4mdl
@@ -0,0 +1,2 @@
1
+ from .mp4_downloader import mp4_downloader
2
+ from .segment_downloader import segment_downloader
@@ -0,0 +1,58 @@
1
+ import logging
2
+ import urllib3
3
+ import time
4
+
5
+ class mp4_downloader:
6
+ def __init__(self, headers, url, file_name, logger):
7
+ self.headers = headers
8
+ self.url = url
9
+ self.file_name = file_name
10
+ self.logger = logger
11
+
12
+ def download(self):
13
+ urllib3_logger = logging.getLogger("urllib3")
14
+ urllib3_logger.setLevel(logging.WARNING)
15
+
16
+ try:
17
+ http = urllib3.PoolManager()
18
+ response = http.request('GET', self.url, headers=self.headers, preload_content=False)
19
+
20
+ if response.status == 403:
21
+ self.logger.error(f"Erreur 403 : {self.url} <-- si url est sibnet ses normal tu est banni pendant 2-5 jours")
22
+ return False
23
+ elif response.status != 200:
24
+ self.logger.error(f"Erreur lors du téléchargement: {response.status}")
25
+ return False
26
+
27
+ with open(self.file_name, 'wb') as f:
28
+ chunk_size = 512 * 1024
29
+
30
+ total_downloaded = 0
31
+ start_time = time.time()
32
+
33
+ for data in response.stream(chunk_size):
34
+ f.write(data)
35
+ total_downloaded += len(data)
36
+
37
+ # Ajuster la taille du chunk en fonction de la vitesse
38
+ elapsed = time.time() - start_time
39
+ if elapsed >= 1: # Ajuster toutes les secondes
40
+ speed = total_downloaded / elapsed # octets/seconde
41
+
42
+ # Augmenter/diminuer chunk_size selon la vitesse
43
+ if speed > 1024*1024: # Si > 1 MB/s
44
+ chunk_size = min(chunk_size * 2, 5*1024*1024) # Max 5MB
45
+ elif speed < 512*1024: # Si < 512 KB/s
46
+ chunk_size = max(chunk_size // 2, 4096) # Min 4KB
47
+
48
+ total_downloaded = 0
49
+ start_time = time.time()
50
+
51
+ response.release_conn()
52
+ self.logger.debug(f"Téléchargement réussi : {self.file_name}")
53
+ return True
54
+
55
+ except Exception as e:
56
+ if self.logger:
57
+ self.logger.error(f"Erreur lors du téléchargement: {str(e)}")
58
+ return False
@@ -0,0 +1,41 @@
1
+ import os
2
+ import ffmpeg
3
+
4
+ class segment_downloader:
5
+ def __init__(self, best_qualite_url, headers_dict, file_name, logger):
6
+ self.best_qualite_url = best_qualite_url
7
+ self.file_name = file_name
8
+ self.logger = logger
9
+ self.headers_dict = headers_dict
10
+
11
+ def download_segments(self):
12
+ try:
13
+ if os.path.exists(self.file_name):
14
+ os.remove(self.file_name)
15
+
16
+ # Créer le stream d'entrée avec les headers
17
+ input_stream = ffmpeg.input(
18
+ self.best_qualite_url,
19
+ protocol_whitelist="file,https,http,tls,tcp",
20
+ headers=self.headers_dict
21
+ )
22
+
23
+ # Configurer le stream de sortie
24
+ output_stream = ffmpeg.output(
25
+ input_stream,
26
+ self.file_name,
27
+ c='copy' # Copier les streams sans ré-encoder
28
+ )
29
+
30
+ # Exécuter la commande
31
+ ffmpeg.run(output_stream, capture_stdout=True, capture_stderr=True)
32
+
33
+ self.logger.debug(f"Téléchargement des segments réussi : {self.file_name}")
34
+ return True
35
+
36
+ except ffmpeg.Error as e:
37
+ self.logger.error(f"Erreur ffmpeg : {e.stderr.decode()}")
38
+ return False
39
+ except Exception as e:
40
+ self.logger.error(f"Erreur lors du téléchargement des segments : {e}")
41
+ return False
@@ -0,0 +1,4 @@
1
+ from .sibnet import sibnet as sibnet
2
+ from .vidmoly import vidmoly as vidmoly
3
+ from .oneupload import oneupload as oneupload
4
+ from .sendvid import sendvid as sendvid
@@ -0,0 +1,21 @@
1
+ from ..scrap import get_m3u8_url, get_best_qualite_url
2
+ from ..download import segment_downloader
3
+
4
+ def oneupload(url, file_name, logger):
5
+ headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',"Referer": "https://oneupload.net/", "Origin": "https://oneupload.net"}
6
+ headers_dict = {
7
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
8
+ 'Referer': 'https://oneupload.net/',
9
+ 'Origin': 'https://oneupload.net'
10
+ }
11
+ match = r'file:"(https?://[^"]+\.m3u8[^"]*)"'
12
+ m3u8_url = get_m3u8_url(url=url, headers=headers, match=match, logger=logger)
13
+ if not m3u8_url:
14
+ return False
15
+
16
+ best_qualite_url = get_best_qualite_url(m3u8_url=m3u8_url, headers=headers, logger=logger)
17
+
18
+ downloader = segment_downloader(best_qualite_url=best_qualite_url, headers_dict=headers_dict, file_name=file_name, logger=logger)
19
+ status = downloader.download_segments()
20
+ return status
21
+
@@ -0,0 +1,18 @@
1
+ from ..scrap import get_mp4_url
2
+ from ..download import mp4_downloader
3
+
4
+
5
+ def sendvid(url, file_name, logger):
6
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1"}
7
+ meta = 'og:video'
8
+ video_url = get_mp4_url(url, headers, meta=meta, logger=logger)
9
+ if not video_url:
10
+ return False
11
+
12
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36", "Referer": f"https://video.sibnet.ru"}
13
+ downloader = mp4_downloader(headers, video_url, file_name, logger)
14
+ status = downloader.download()
15
+ return status
16
+
17
+
18
+
@@ -0,0 +1,16 @@
1
+ from ..scrap import get_mp4_url
2
+ from ..download import mp4_downloader
3
+
4
+ def sibnet(url, file_name, logger):
5
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1"}
6
+ match = r'player\.src\(\[\{src: "(.*?)"'
7
+ video_url = get_mp4_url(url, headers, match=match, logger=logger)
8
+ if not video_url:
9
+ return False
10
+
11
+ mp4_url = f"https://video.sibnet.ru{video_url}"
12
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36", "Referer": f"https://video.sibnet.ru"}
13
+ downloader = mp4_downloader(headers, mp4_url, file_name, logger)
14
+ status = downloader.download()
15
+ return status
16
+
@@ -0,0 +1,25 @@
1
+ from ..scrap import get_m3u8_url, get_best_qualite_url
2
+ from ..download import segment_downloader
3
+
4
+
5
+ def vidmoly(url, file_name, logger):
6
+ headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',"Referer": "https://vidmoly.to/","Origin": "https://vidmoly.to"}
7
+ headers_dict = {
8
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
9
+ 'Referer': 'https://vidmoly.to/',
10
+ 'Origin': 'https://vidmoly.to'
11
+ }
12
+
13
+ match = [r'(https?://[^\s]+/master\.m3u8\?[^\s"]+)', r'(https?://[^\s]+/master\.m3u8)']
14
+
15
+ m3u8_url = get_m3u8_url(url=url, headers=headers, match= match, list_match=True, logger=logger)
16
+ if not m3u8_url:
17
+ return False
18
+
19
+ best_qualite_url = get_best_qualite_url(m3u8_url=m3u8_url, headers=headers, logger=logger)
20
+
21
+ downloader = segment_downloader(best_qualite_url=best_qualite_url, headers_dict=headers_dict,file_name=file_name, logger=logger)
22
+ status = downloader.download_segments()
23
+ return status
24
+
25
+
@@ -0,0 +1,89 @@
1
+ import logging
2
+ import os
3
+ import uuid
4
+ from urllib.parse import urlparse
5
+ import shutil
6
+
7
+ from .lecteur import *
8
+
9
+ class mp4mdl:
10
+ """
11
+ Classe pour télécharger des vidéos depuis différents sites.
12
+
13
+ Args:
14
+ download_path (str): Chemin où télécharger temporairement les fichiers
15
+ final_path (str): Chemin final où déplacer les fichiers
16
+ url (str): URL de la vidéo à télécharger
17
+ logger (logging.Logger, optional): Logger personnalisé (par défaut, "MP4mdl" avec le titre "MP4mdl-{title})
18
+ title (str, optional): Titre pour le logger seulement si logger est None
19
+ """
20
+
21
+ SUPPORTED_SITES = {
22
+ "video.sibnet.ru": (sibnet, ["url", "file_name", "logger"]),
23
+ "vidmoly.to": (vidmoly, ["url", "file_name", "logger"]),
24
+ "oneupload.to": (oneupload, ["url", "file_name", "logger"]),
25
+ "sendvid.com": (sendvid, ["url", "file_name", "logger"])
26
+ }
27
+
28
+ def __init__(self, download_path, final_path, url, logger=None, title=None):
29
+ # Validation des entrées
30
+ if not all([download_path, final_path, url]):
31
+ raise ValueError("Tous les paramètres sont requis")
32
+
33
+ # Initialisation du logger
34
+ if title:
35
+ self.logger = logger or logging.getLogger(f"MP4mdl-{title}")
36
+ else:
37
+ self.logger = logger or logging.getLogger(f"MP4mdl")
38
+
39
+ # Normalisation des chemins
40
+ self.download_path = os.path.normpath(download_path)
41
+ self.final_path = os.path.normpath(final_path)
42
+ self.url = url
43
+
44
+ # Création du dossier temporaire
45
+ self._setup_temp_directory()
46
+
47
+ def download(self):
48
+ site = self.SUPPORTED_SITES
49
+ parsed_url = urlparse(self.url)
50
+ base_name = parsed_url.netloc
51
+
52
+ downloaded = False
53
+ if base_name in site:
54
+ # Préparer les arguments pour la fonction
55
+ handler, param_names = site[base_name]
56
+ args = {param: getattr(self, param) for param in param_names}
57
+
58
+ self.logger.debug(f"call de la function {handler.__name__} avec les arguments {args}")
59
+ # Appeler la fonction avec les bons arguments
60
+ status = handler(**args)
61
+ self.logger.debug(f"status: {status}")
62
+ if status:
63
+ try:
64
+ if os.path.exists(self.file_name):
65
+ shutil.move(self.file_name, self.final_path)
66
+ downloaded = True
67
+ else:
68
+ self.logger.error(f"Le fichier source n'existe pas: {self.file_name}")
69
+ downloaded = False
70
+ except Exception as e:
71
+ self.logger.error(f"Erreur lors du déplacement du fichier: {e}")
72
+ downloaded = False
73
+ else:
74
+ self.logger.error(f"Le site {base_name} n'est pas supporté")
75
+ downloaded = False
76
+ try:
77
+ if os.path.exists(self.temp_path):
78
+ shutil.rmtree(self.temp_path)
79
+ except Exception as e:
80
+ self.logger.error(f"Erreur lors de la suppression du dossier temporaire: {e}")
81
+ return downloaded
82
+
83
+ def _setup_temp_directory(self):
84
+ self.temp_name = str(uuid.uuid5(uuid.NAMESPACE_URL, self.url))
85
+ self.temp_path = os.path.join(self.download_path, self.temp_name)
86
+ os.makedirs(self.temp_path, exist_ok=True)
87
+ self.file_name = os.path.join(self.temp_path, f"{self.temp_name}.mp4")
88
+
89
+
@@ -0,0 +1,4 @@
1
+ from .get_mp4_url import get_mp4_url
2
+ from .get_best_qualite_url import get_best_qualite_url
3
+ from .get_m3u8_url import get_m3u8_url
4
+
@@ -0,0 +1,34 @@
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+
4
+
5
+ def get_best_qualite_url(m3u8_url, headers, logger):
6
+ try:
7
+ response = requests.get(m3u8_url, headers=headers)
8
+ response.raise_for_status()
9
+ soup = BeautifulSoup(response.content, 'html.parser')
10
+ except Exception as e:
11
+ logger.error(f"Erreur lors de la récupération de l'URL m3u8: {e}")
12
+ return None
13
+
14
+ lines = response.text.splitlines()
15
+ best_url = None
16
+ best_resolution = (0, 0)
17
+
18
+ for i, line in enumerate(lines):
19
+ if line.startswith("#EXT-X-STREAM-INF"):
20
+ # Extraire les informations de la ligne
21
+ parts = line.split(",")
22
+
23
+ # Récupérer la résolution
24
+ resolution_str = next((part.split("=")[1] for part in parts
25
+ if part.startswith("RESOLUTION=")), None)
26
+
27
+ if resolution_str and i + 1 < len(lines):
28
+ width, height = map(int, resolution_str.split("x"))
29
+
30
+ # Mettre à jour si meilleure résolution trouvée
31
+ if (width, height) > best_resolution:
32
+ best_url = lines[i + 1]
33
+
34
+ return best_url
@@ -0,0 +1,41 @@
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+ import re
4
+
5
+ def get_m3u8_url(url, headers, match, logger, list_match=False):
6
+ if not match:
7
+ logger.error("match non definis")
8
+ return None
9
+
10
+ try:
11
+ response = requests.get(url, headers=headers)
12
+ response.raise_for_status()
13
+ soup = BeautifulSoup(response.content, 'html.parser')
14
+ except Exception as e:
15
+ logger.error(f"Erreur lors de la récupération de l'URL m3u8: {e}")
16
+ return None
17
+
18
+ if list_match:
19
+ for m in match:
20
+ m3u8_url = find_match(soup, m, logger)
21
+ if m3u8_url:
22
+ return m3u8_url
23
+ return None
24
+ else:
25
+ return find_match(soup, match, logger)
26
+
27
+
28
+ def find_match(soup, match, logger):
29
+ if match:
30
+ scripts = soup.find_all('script')
31
+ for script in scripts:
32
+ script_content = script.string
33
+ if script_content:
34
+ matchs = re.search(match, script_content)
35
+ if matchs:
36
+ m3u8_url = matchs.group(1)
37
+ if not m3u8_url:
38
+ logger.error("m3u8 URL non trouvée dans le script")
39
+ return None
40
+ else:
41
+ return m3u8_url
@@ -0,0 +1,57 @@
1
+ import requests
2
+ import logging
3
+ from bs4 import BeautifulSoup
4
+ import re
5
+
6
+
7
+ def get_mp4_url(url, headers, logger, match=None, meta=None):
8
+ if not match and not meta:
9
+ logger.error("match ou meta non definis")
10
+ return None
11
+
12
+ try:
13
+ response = requests.get(url, headers=headers)
14
+ response.raise_for_status()
15
+ soup = BeautifulSoup(response.content, 'html.parser')
16
+ except requests.RequestException as e:
17
+ logger.error(f"Erreur lors de la requête HTTP: {e}")
18
+ return None
19
+ except Exception as e:
20
+ logger.error(f"Erreur inattendue: {e}")
21
+ return None
22
+
23
+ if match:
24
+ scripts = soup.find_all('script', type="text/javascript")
25
+
26
+ if not scripts:
27
+ logger.error("Aucun script JavaScript trouvé dans la page")
28
+ return None
29
+
30
+ for script in scripts:
31
+ script_content = script.string
32
+ if script_content:
33
+ matchs = re.search(match, script_content)
34
+ if matchs:
35
+ video_url = matchs.group(1)
36
+ if not video_url:
37
+ logger.error("URL de la vidéo non trouvée dans le script")
38
+ return None
39
+ else:
40
+ return video_url
41
+ elif meta:
42
+ meta_tag = soup.find("meta", property=meta)
43
+
44
+ if not meta_tag:
45
+ logger.error("Aucune vidéo trouvée dans la page")
46
+ return None
47
+
48
+ video_url = meta_tag['content']
49
+ if not video_url:
50
+ logger.error("URL de la vidéo non trouvée")
51
+ return None
52
+
53
+ return video_url
54
+ else:
55
+ logger.error("Aucun match ou meta trouvé")
56
+ return None
57
+
MP4MDL-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
MP4MDL-0.1.0/setup.py ADDED
@@ -0,0 +1,29 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="MP4MDL",
5
+ version="0.1.0",
6
+ packages=find_packages(),
7
+ install_requires=[
8
+ "requests",
9
+ "beautifulsoup4",
10
+ "ffmpeg-python",
11
+ ],
12
+ author="Maddox",
13
+ author_email="maddoxtes@gmail.com",
14
+ description="Un outil pour télécharger et gérer des vidéos MP4",
15
+ long_description=open("readme.md").read(),
16
+ long_description_content_type="text/markdown",
17
+ url="https://git.maddoxserv.com/maddox/MP4MDL",
18
+ classifiers=[
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ ],
23
+ python_requires=">=3.11",
24
+ entry_points={
25
+ "console_scripts": [
26
+ "mp4mdl=mp4mdl.main:main",
27
+ ],
28
+ },
29
+ )