vid_utils.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import os
  2. import logging
  3. from glob import glob, escape
  4. from subprocess import Popen, PIPE
  5. from contextlib import contextmanager
  6. from telegram import InlineKeyboardButton
  7. from db import VidDatabase
  8. logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
  9. logger = logging.getLogger(__name__)
  10. class BadLink(Exception):
  11. pass
  12. class Video:
  13. def __init__(self, link=None, vid=None, init_keyboard=False):
  14. self.db = VidDatabase(os.path.join(os.environ['CONF_FOLDER'], "viddb.sqlite3"))
  15. if not self.db.is_valid:
  16. # Database file not present
  17. # Create a new database
  18. self.db.create()
  19. if vid is None and link is not None:
  20. self.link = link
  21. self.file_name = None
  22. elif vid is not None and link is None:
  23. self.link, self.code = self.db.select_vid(vid)
  24. else:
  25. raise Exception('what is going on?')
  26. if init_keyboard:
  27. self.formats = self.get_formats()
  28. self.keyboard = self.generate_keyboard()
  29. def get_formats(self):
  30. formats = {}
  31. p = Popen(["youtube-dl", "-F", self.link], stdout=PIPE, stderr=PIPE).communicate()
  32. it = iter(str(p[0], 'utf-8').split('\n')) # iterator of output lines
  33. try:
  34. while "code extension" not in next(it):
  35. pass # Remove garbage lines
  36. except StopIteration:
  37. raise BadLink("youtube-dl couldn't download the link you provided") # Isn't a valid youtube link
  38. while True:
  39. try:
  40. line = next(it)
  41. if not line:
  42. raise StopIteration # Usually the last line is empty
  43. if "video only" in line:
  44. continue # I don't need video without audio
  45. except StopIteration:
  46. break
  47. else:
  48. format_code, extension, resolution, *_ = line.strip().split()
  49. key = '{},{}'.format(extension, resolution)
  50. index = self.db.insert_vid(self.link, format_code)
  51. formats[key] = index
  52. logger.info("Fromats: {}".format(formats))
  53. return formats
  54. def generate_keyboard(self):
  55. """ Generate a list of InlineKeyboardButton of resolutions """
  56. kb = []
  57. for key in self.formats.keys():
  58. cb = "{}".format(self.formats[key])
  59. kb.append([InlineKeyboardButton(key, callback_data=cb)])
  60. return kb
  61. def download(self):
  62. logger.info("Downloading {}".format(self.link))
  63. p = Popen(["youtube-dl", "-o", "/bot/out/%(title)s-%(id)s.%(ext)s", "-f", self.code, self.link], stdout=PIPE, stderr=PIPE).communicate()
  64. for line in str(p[0], 'utf-8').split('\n'):
  65. logger.info(line)
  66. if "[download] Destination:" in line:
  67. self.file_name = line[24:] # name of the file
  68. def check_dimension(self):
  69. try:
  70. if os.path.getsize(self.file_name) > 50 * 1024 * 1023:
  71. Popen(["split", "-b", "49M", self.file_name, self.file_name])
  72. os.remove(self.file_name)
  73. return glob(escape(self.file_name) + '*')
  74. except AttributeError as e:
  75. logger.error(e)
  76. return None
  77. @contextmanager
  78. def send(self):
  79. files = self.check_dimension() # split if size >= 50MB
  80. yield files
  81. for f in files: # removing old files
  82. os.remove(f)
  83. #__________________________OLD STUFFS, TOUCH CAREFULLY__________________________
  84. # this is the soft-split version, require avconv, but the audio isn't synchronized, avconv's problems :(
  85. '''
  86. def get_duration(filepath): # get duration in seconds
  87. cmd = "avconv -i %s" % filepath
  88. p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
  89. di = p.communicate()
  90. for line in di:
  91. if line.rfind(b"Duration") > 0:
  92. duration = str(re.findall(b"Duration: (\d+:\d+:[\d.]+)", line)[0])
  93. return 3600 * int(duration[2: 4]) + 60 * int(duration[5: 7]) + int(duration[8: 10])
  94. def check_dimension(f): # if f is bigger than 50MB split it in subvideos
  95. if os.path.getsize(f) > 50 * 1024 * 1023:
  96. duration = get_duration(f)
  97. for i in range(0, duration, 180):
  98. start = strftime("%H:%M:%S", strptime('{0} {1} {2}'.format(i // 3600, (i // 60) % 60, i % 60), "%H %M %S")) # TODO this is not pythonic code!
  99. os.system("""avconv -i '{0}' -vcodec copy -acodec copy -ss {1} -t {2} 'part_{3}.mp4'""".format(f, start, 180, (i // 180) % 180))
  100. os.remove(f) # delete original file
  101. '''