vid_utils.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import os
  2. import logging
  3. from json import loads
  4. from json.decoder import JSONDecodeError
  5. from glob import glob, escape
  6. from subprocess import Popen, PIPE
  7. from contextlib import contextmanager
  8. from telegram import InlineKeyboardButton
  9. from db import VidDatabase
  10. logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
  11. logger = logging.getLogger(__name__)
  12. class BadLink(Exception):
  13. pass
  14. class Video:
  15. def __init__(self, link=None, vid=None, init_keyboard=False):
  16. self.db = VidDatabase(os.path.join(os.environ['CONF_FOLDER'], 'viddb.sqlite3'))
  17. if not self.db.is_valid:
  18. # Database file not present
  19. # Create a new database
  20. self.db.create()
  21. if vid is None and link is not None:
  22. self.link = link
  23. self.file_name = None
  24. elif vid is not None and link is None:
  25. self.link, self.code = self.db.select_vid(vid)
  26. self.code, self.audio_only = self.code.split('|')
  27. else:
  28. raise Exception('what is going on?')
  29. if init_keyboard:
  30. try:
  31. self.formats = self.get_formats()
  32. self.keyboard = self.generate_keyboard()
  33. except Exception:
  34. raise
  35. def get_formats(self):
  36. formats = {}
  37. p = Popen(['youtube-dl', '-J', self.link], stdout=PIPE, stderr=PIPE).communicate()
  38. if b'ERROR' in p[1]:
  39. raise Exception('video URL not supported')
  40. video_info = loads(str(p[0], 'utf-8'))
  41. if video_info.get('_type', None) == 'playlist':
  42. video_info = video_info.get('entries')[0]
  43. if video_info.get('formats') is not None:
  44. for vid in video_info.get('formats'):
  45. self.add_format(formats, vid)
  46. else:
  47. self.add_format(formats, video_info)
  48. logger.info('Formats: {}'.format(formats))
  49. return formats
  50. def add_format(self, formats, vid):
  51. format_code = vid.get('format_id')
  52. extension = vid.get('ext')
  53. name = vid.get('format')
  54. key = '{},{}'.format(extension, name)
  55. code = '{}|{}'.format(format_code, 'audio only' in name)
  56. index = self.db.insert_vid(self.link, code)
  57. formats[key] = index
  58. def generate_keyboard(self):
  59. ''' Generate a list of InlineKeyboardButton of resolutions '''
  60. kb = []
  61. for key in self.formats.keys():
  62. cb = '{}'.format(self.formats[key])
  63. kb.append([InlineKeyboardButton(key, callback_data=cb)])
  64. return kb
  65. def download(self):
  66. logger.info('Downloading {}'.format(self.link))
  67. cmd = ['youtube-dl', '-o', '/bot/out/%(title)s-%(id)s.%(ext)s']
  68. if self.audio_only in [False, "False"]:
  69. self.code = self.code + '+bestaudio'
  70. cmd.extend(['-f', self.code, self.link])
  71. logger.info(cmd)
  72. p = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
  73. for line in str(p[0], 'utf-8').split('\n'):
  74. logger.info(line)
  75. if '[download] Destination:' in line:
  76. self.file_name = line[24:] # name of the file
  77. if '[ffmpeg] Merging formats into' in line:
  78. self.file_name = line[31:-1] # name of the file
  79. def check_dimension(self):
  80. try:
  81. if os.path.getsize(self.file_name) > 50 * 1024 * 1023:
  82. Popen(['split', '-b', '49M', self.file_name, self.file_name])
  83. os.remove(self.file_name)
  84. return glob(escape(self.file_name) + '*')
  85. except AttributeError as e:
  86. logger.error(e)
  87. return None
  88. @contextmanager
  89. def send(self):
  90. files = self.check_dimension() # split if size >= 50MB
  91. yield files
  92. for f in files: # removing old files
  93. os.remove(f)