Guest User

Untitled

a guest
Apr 21st, 2025
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.43 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. import os, re, subprocess, time
  3. import urllib.request
  4.  
  5. # Add valid domains here
  6. VALID_DOMAINS = [
  7.     "files.catbox.moe",
  8. ]
  9.  
  10. # Add valid sound extensions here
  11. VALID_SOUNDEXTS = [
  12.     "mp3",
  13.     "wav",
  14.     "ogg",
  15.     "m4a",
  16.     "webm",
  17.     "mp4",
  18. ]
  19.  
  20. # Wait this number of seconds between each file download, just so catbox doesn't whine because we're
  21. # downloading too much shit too fast. This might no be needed since calling ffmpeg to mix the final
  22. # file takes time on its own anyway so that already throttles our server calls
  23. THROTTLE = 0
  24.  
  25. # The mixed file's extension
  26. OUTPUT_EXTENSION = "mp4"
  27.  
  28. # You can specify the output codec here like  -c:v libvpx-vp9, you can also add things like -crf here or the audio codec
  29. # if it's empty, ffmpeg will choose default values for the output extension I think
  30. # Here we also add a pad filter to make the output divisible by 2 as required by h264. You can also use crop or scale (copy&paste from below)
  31. #OUTPUT_CODEC = '-c:v libvpx-vp9 -vf "fps=25,format=yuv420p, pad=ceil(iw/2)*2:ceil(ih/2)*2"'  # For webm
  32. OUTPUT_CODEC = '-c:v libx264 -vf "fps=25,format=yuv420p, pad=ceil(iw/2)*2:ceil(ih/2)*2"'       # For mp4
  33.  
  34. # crop=trunc(iw/2)*2:trunc(ih/2)*2     # Crop to make it even
  35. # scale=trunc(iw/2)*2:trunc(ih/2)*2    # Scale to make it even
  36.  
  37. # Don't mess with this
  38. VALID_FILENAME = r"(.+)\[sound=((?:https%3A%2F%2F)?(?:" + "|".join(VALID_DOMAINS) + ")%2F(.+\.(?:" + "|".join(VALID_SOUNDEXTS) + ")))\]\.(png|gif|jpeg|webm|mp4|jpg)"
  39.  
  40. def urldecode(text):
  41.     def subfunc(el):
  42.         return chr(int(el[0][1:], 16))
  43.     return re.sub("%[\da-fA-F]{2}", subfunc, text)
  44.  
  45. # Check if we can call a program with os.system()
  46. def program_exists(prog_name):
  47.     if os.name == 'nt': # for Windows
  48.         syscall = f"WHERE {prog_name}"
  49.         ret, err = subprocess.Popen(syscall, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
  50.     if os.name == 'posix':  # for Linux
  51.         syscall = f"which {prog_name}"
  52.         ret, err = subprocess.Popen(syscall, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
  53.     if err or not ret:
  54.         return False
  55.     return True
  56.  
  57. def download_soundfile(url, filename):
  58.     headers = {
  59.         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5756.197 Safari/537.36',
  60.         'Accept-Encoding': 'deflate',
  61.         'Accept-Language': 'en-US,en;q=0.5',
  62.         'Cache-Control' : 'no-cache',
  63.     }
  64.     req = urllib.request.Request(url, headers=headers)
  65.     data = urllib.request.urlopen(req)
  66.     with open(filename,'wb') as output:
  67.         output.write(data.read())
  68.  
  69. def system_call(cmd):
  70.     if os.name == 'nt': # for Windows
  71.         ret, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
  72.     if os.name == 'posix':  # for Linux
  73.         ret, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
  74.     return ret, err
  75.  
  76. def get_song_length(fname):
  77.     cmd = f'ffprobe -hide_banner "{fname}"'
  78.     # For some reason ffprobe returns data in err
  79.     ret, err = system_call(cmd)
  80.     res = re.findall("Duration: (\d+:\d{2}:\d{2}(?:\.\d+))", err.decode('utf-8'))
  81.     if not res:
  82.         return None
  83.     tmp = res[0].split(":")
  84.     hours, minutes, seconds = int(tmp[0]), int(tmp[1]), float(tmp[2])
  85.     return (hours * 3600) + (minutes * 60) + seconds
  86.  
  87. # Check if we have ffmpeg
  88. if not program_exists("ffmpeg"):
  89.     print("ffmpeg couldn't be found")
  90.     exit()
  91.  
  92. for file in os.listdir():
  93.     res = re.match(VALID_FILENAME, file)
  94.     if not res:
  95.         continue
  96.  
  97.     imgname, soundurl, soundfname, ext = res[1], urldecode(res[2]), res[3], res[4]
  98.     if not soundurl.startswith("https://"):
  99.         soundurl = "https://" + soundurl
  100.  
  101.     if not os.path.exists(soundfname):
  102.         print(f"File {soundfname} does not exist, downloading")
  103.         try:
  104.             download_soundfile(soundurl, soundfname)
  105.         except Exception as e:
  106.             print(f"Could not download {soundurl}")
  107.             print(e)
  108.             continue
  109.  
  110.         if THROTTLE > 0:
  111.             print(f"Waiting {THROTTLE} seconds")
  112.             time.sleep(THROTTLE)
  113.  
  114.     song_length = get_song_length(soundfname)
  115.     video_length = 0
  116.     if(ext in ['mp4', 'webm']):
  117.         video_length = get_song_length(file)
  118.  
  119.     # Because we have to use a different ffmpeg command depending on each case
  120.     if(ext in ['jpg', 'png', 'jpeg']):
  121.         # Simple case a static image and an mp3
  122.         ffmpeg_cmd = f'ffmpeg -hide_banner -loop 1 -i "{file}" -i "{soundfname}" -t {song_length} {OUTPUT_CODEC} -map 0:v -map 1:a "out-{imgname}.{OUTPUT_EXTENSION}"'
  123.     elif ext == 'gif':
  124.         # Gif and mp3
  125.         ffmpeg_cmd = f'ffmpeg -ignore_loop 0 -i "{file}" -i "{soundfname}" -t {song_length} {OUTPUT_CODEC} -map 0:v -map 1:a "out-{imgname}.{OUTPUT_EXTENSION}"'
  126.     elif song_length > video_length:
  127.         # Song is longer than video so we will loop video
  128.         ffmpeg_cmd = f'ffmpeg -hide_banner -stream_loop -1 -i "{file}" -i "{soundfname}" -t {song_length} {OUTPUT_CODEC} -map 0:v -map 1:a "out-{imgname}.{OUTPUT_EXTENSION}"'
  129.     else:
  130.         # Else song has the same length as video, presumably
  131.         ffmpeg_cmd = f'ffmpeg -hide_banner -i "{file}" -i "{soundfname}" {OUTPUT_CODEC} -map 0:v -map 1:a "out-{imgname}.{OUTPUT_EXTENSION}"'
  132.  
  133.     os.system(ffmpeg_cmd)
  134.  
  135. print("\n\nPress enter to exit")
  136. input()
Add Comment
Please, Sign In to add comment