Guest User

Untitled

a guest
Nov 24th, 2019
686
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.33 KB | None | 0 0
  1. # Скрипт выводит в консоль содержимое файла в двоичном виде
  2. # Можно использовать перенаправление вывода для сохранения файла
  3. # Использование vkontakte_m3u8_downloader.py ссылка на аудиозапись > имя файла
  4. # Для работы скрипта нужен ffmpeg
  5. import re
  6. import os.path
  7. import sys
  8. import tempfile
  9. import subprocess
  10. import urllib
  11. from urllib.request import urlopen
  12. from Crypto.Cipher import AES
  13. from Crypto.Util.Padding import unpad
  14.  
  15. import requests
  16.  
  17. regex = "https.*key.pub"
  18. regex_2 = '"https.*pub?.*"'
  19. regex_3 = 'ts?.*'
  20.  
  21.  
  22. def parse_m3u8(_url):
  23.     urldir = os.path.dirname(_url)
  24.     playlist = requests.get(_url).text
  25.  
  26.     # парсим секции #EXT-X-KEY, складываем в список [файл, метод шифрования, url к ключу]
  27.     chunks = []
  28.     for match in re.finditer(r'(#EXT-X-KEY:(?:(?!#EXT-X-KEY:).)*)', playlist, re.DOTALL):
  29.         # получили секцию, смотрим метод шифрования и URL к файлу ключа
  30.         section = match.group(0)
  31.         section_match = re.match(r'.*?METHOD=(?P<METHOD>[^,\n\r]+)(?:,URI=(?P<URI>[^\n]+)|)', section, re.IGNORECASE)
  32.         key_method = section_match.group('METHOD')
  33.         key_url = section_match.group('URI')
  34.         if key_url:
  35.             key_url = key_url.strip("'\"")
  36.         # смотрим список файлов в этой секции, создаем список
  37.         for match2 in re.finditer(r'.*?(?P<file>^[^\r\n]+\.ts)(?P<extra>[^\n\r]+)', section, re.IGNORECASE | re.DOTALL | re.MULTILINE):
  38.             file = match2.group('file')
  39.             extra = match2.group('extra')
  40.             file_url = f'{urldir}/{file}{extra}'
  41.             chunks.append({'file_url': file_url, 'key_method': key_method, 'key': key_url, 'file_name': file})
  42.  
  43.     # для созданного списка файлов, достаем содержимое ключей, используя кэширование
  44.     cached_urls = []
  45.     for chunk in chunks:
  46.         key_url = chunk['key']
  47.         if not key_url:
  48.             continue
  49.         value = ''
  50.  
  51.         # если url ключа уже скачивалась, достаём кэшированное значение
  52.         for cached_url in cached_urls:
  53.             if key_url == cached_url[0]:
  54.                 value = cached_url[1]
  55.                 break
  56.         # делаем запрос только если значение не найдено, и кэшируем ответ
  57.         if not value:
  58.             value = requests.get(key_url).text
  59.             cached_urls.append([key_url, value])
  60.         # в общем списке заменяем url ключа на его значение
  61.         chunk['key'] = value
  62.     del cached_urls
  63.     return [chunks, playlist]
  64.  
  65.  
  66. def download_m3u8(job, output='out.ts'):
  67.     chunks = job[0]
  68.     playlist = job[1]
  69.  
  70.     with tempfile.TemporaryDirectory() as _dir:
  71.         os.chdir(_dir)
  72.         print(f'Скачиваем части в каталог {_dir}')
  73.  
  74.         file_num = 1
  75.         for chunk in chunks:
  76.             file_name = str(file_num).zfill(4) + " " + chunk['file_name']
  77.             file_num += 1
  78.  
  79.             if chunk['key']:
  80.                 key = chunk['key']
  81.                 key = key.encode()
  82.                 file_in = urlopen(chunk['file_url'])
  83.                 iv = file_in.read(16) # Read the iv out - this is 16 bytes long
  84.                 ciphered_data = file_in.read() # Read the rest of the data
  85.                 file_in.close()
  86.                 cipher = AES.new(key, AES.MODE_CBC, iv=iv)  # Setup cipher
  87.                 data = unpad(cipher.decrypt(ciphered_data), AES.block_size) # Decrypt and then up-pad the result
  88.             else:
  89.                 data = requests.get(chunk['file_url']).content
  90.  
  91.             if data:
  92.                 with open(file_name, 'wb') as audio:
  93.                     audio.write(data)
  94.                     path = f'{_dir}\\{file_name}'
  95.                     chunk['file_url'] = path
  96.                     print(f'Скачан файл {file_name}')
  97.             else:
  98.                 print(f'Ошибка получения части {chunk["file_name"]}')
  99.  
  100.         # склеиваем файлы
  101.         ffmpeg_queue = '# queue'
  102.         for chunk in chunks:
  103.             ffmpeg_queue += f"\nfile '{chunk['file_url']}'"
  104.  
  105.         queue_lst = 'queue.txt'
  106.         with open(queue_lst, 'w') as file:
  107.             file.write(ffmpeg_queue)
  108.  
  109.         with open('playlist.txt', 'w') as file:
  110.             file.write(playlist)
  111.  
  112.         subprocess.call(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', f'{queue_lst}', '-c', 'copy', f'{output}'])
  113.     return chunks
  114.  
  115.  
  116.  
  117. if __name__ == '__main__':
  118.     url = sys.argv[1]
  119.     result = parse_m3u8(url)
  120.     sys.stdout.buffer.write(download_m3u8(result))
Advertisement
Add Comment
Please, Sign In to add comment