Skip to content

Instantly share code, notes, and snippets.

@KumaTea
Last active November 28, 2022 14:18
Show Gist options
  • Select an option

  • Save KumaTea/93506c6a6bec5f2fa0e1cea72e3d09a9 to your computer and use it in GitHub Desktop.

Select an option

Save KumaTea/93506c6a6bec5f2fa0e1cea72e3d09a9 to your computer and use it in GitHub Desktop.
Python - MP4 / GIF to Telegram Video Sticker (VP9 Webm) Convertion Script
import os
import math
import subprocess
FFMPEG = r'D:\Tools\ffmpeg\bin\ffmpeg.exe'
FFPROBE = r'D:\Tools\ffmpeg\bin\ffprobe.exe'
save_to = 'webm'
def ceil(num):
return int(math.ceil(num))
def get_files(path='.'):
files = []
for file in os.listdir(path):
if os.path.isfile(file) and file.split('.')[-1] in ['gif', 'mp4']:
files.append(os.path.join(path, file))
return files
def get_media_info(file):
info = {}
command = [FFPROBE, '-hide_banner', '-loglevel', 'error', '-show_streams', file]
print(' '.join(command))
info_raw = subprocess.run(
command,
stdout=subprocess.PIPE,
text=True
)
for item in info_raw.stdout.splitlines():
if item.count('=') == 1:
info[item.split('=')[0]] = item.split('=')[1]
elif item == '[/STREAM]':
break
return info
def convert(file, slim=False):
info = get_media_info(file)
temp_file = ''
# duration
# if float(info['duration']) > 3.0:
# command.extend('-t 3'.split())
too_long = False
nb_frames = int(info['nb_frames'])
if float(info['duration']) > 3.0:
too_long = True
print(f'{file} too long:', info['duration'])
r = ceil(nb_frames / 3)
# temp_file = '.'.join(file.split('.')[:-1]) + '_temp' + '.mp4'
command = [FFMPEG, '-hide_banner', '-loglevel', 'error', '-r', str(r), '-i', file]
# print(' ' + ' '.join(command))
# subprocess.run(command, stdout=subprocess.DEVNULL)
# file = temp_file
# info['r_frame_rate'] = str(r)
# info = get_media_info(file)
else:
command = [FFMPEG, '-hide_banner', '-loglevel', 'error', '-i', file]
# map
command.extend('-map 0:0'.split())
# codec
command.extend('-c:v libvpx-vp9'.split())
# slim
'''
3 seconds * 680 Kbps
= 3 seconds * 85KB/s
= 255KB
'''
if slim != False:
if too_long:
d = nb_frames / ceil(nb_frames / 3)
else:
d = float(info['duration'])
br = int(255*(8-slim)/d)
command.extend(f'-b:v {br}k'.split())
# video filter
filters = []
# resolution
# w = int(info['width'])
# h = int(info['height'])
# if w >= h:
# filters.append('scale=512:-1')
# else:
# filters.append('scale=-1:512')
filters.append('scale=w=512:h=512:force_original_aspect_ratio=decrease')
# fps
if too_long:
if r > 30:
filters.append('fps=30')
elif eval(info['r_frame_rate']) > 30.0:
filters.append('fps=30')
# duration
if not too_long and float(info['duration']) > 3.0:
command.extend('-t 3'.split())
filters_str = ', '.join(filters)
command.extend(['-vf', filters_str])
# no audio
command.append('-an')
# output
command.append(os.path.join(save_to, file.replace(file.split('.')[-1], 'webm').replace('_temp', '')))
print(' '.join(command))
subprocess.run(command, stdout=subprocess.DEVNULL)
if temp_file:
os.remove(temp_file)
return True
def slim(index=0):
webm_files = os.listdir(save_to)
need = 0
for i in webm_files:
if os.stat(os.path.join(save_to, i)).st_size > 256*1024:
need += 1
os.remove(os.path.join(save_to, i))
try:
convert(i.replace('webm', 'mp4'), index)
except:
convert(i.replace('webm', 'gif'), index)
return need
if __name__ == '__main__':
if not os.path.isdir(save_to):
os.mkdir(save_to)
files = get_files()
if not files:
exit(0)
for file in files:
if not os.path.isfile(os.path.join(save_to, file.replace(file.split('.')[-1], 'webm'))):
print(file)
convert(file)
print('Slimming...')
index = 0
while slim(index):
index += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment