Skip to content

Instantly share code, notes, and snippets.

@KunoiSayami
Last active February 10, 2022 13:15
Show Gist options
  • Save KunoiSayami/1e303ff2faba2011b4007cd0beba1268 to your computer and use it in GitHub Desktop.
Save KunoiSayami/1e303ff2faba2011b4007cd0beba1268 to your computer and use it in GitHub Desktop.
Quick transform mp4 to webm for telegram sticker
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2022 KunoiSayami
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations
import subprocess
import argparse
from dataclasses import dataclass
@dataclass
class Resolution:
length: int
weight: int
@classmethod
def new(cls, ffprobe_output: str) -> Resolution:
return cls(*list(map(int, ffprobe_output.split('x'))))
def scale(self, px: int = 512) -> Resolution:
ratio = px / max(self.length, self.weight)
return Resolution(self.transform(self.length * ratio), self.transform(self.weight * ratio))
@staticmethod
def transform(output: float) -> int:
output = int(output)
if output % 2:
output += 1
return output
def __str__(self) -> str:
return f'{self.length}x{self.weight}'
def main():
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='+')
parser.add_argument('--target', default=512, type=int)
matches = parser.parse_args()
for file in matches.file:
# source: https://superuser.com/a/841379
p = subprocess.Popen(['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries',
'stream=width,height', '-of', 'csv=s=x:p=0', file],
stdout=subprocess.PIPE)
output = p.communicate()[0].decode().strip()
# source: https://superuser.com/a/624564
subprocess.Popen(['ffmpeg', '-y', '-i', file, '-s', str(Resolution.new(output).scale(matches.target)),
'-c:a', 'copy', '.tmp.mp4']).wait()
if p.returncode != 0:
print('Got scale error in file', file)
break
# source: https://stackoverflow.com/a/47512301
p = subprocess.Popen(['ffmpeg', '-y', '-i', '.tmp.mp4', '-c:v', 'libvpx-vp9',
'-crf', '30', '-b:v', '0', '-b:a', '128k', '-c:a',
'libopus', f'{file}.webm'])
p.wait()
if p.returncode != 0:
print('Got transform error in file', file)
break
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment