Guest User

Untitled

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