• 4 июля стартует курс «Python для Пентестера ©» от команды The Codeby

    Понятные и наглядные учебные материалы с информацией для выполнения ДЗ; Проверка ДЗ вручную – наставник поможет улучшить написанный вами код; Помощь преподавателей при выполнении заданий или в изучении теории; Групповой чат в Telegram с другими учениками, проходящими курс; Опытные разработчики – команда Codeby School, лидер по информационной безопасности в RU-сегменте

    Запись на курс до 15 июля. Подробнее ...

  • 11 июля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

    На последнюю неделю приходится экзамен, где нужно будет показать свои навыки, взломав ряд уязвимых учебных сайтов, и добыть флаги. Успешно сдавшие экзамен получат сертификат.

    Запись на курс до 20 июля. Подробнее ...

Статья Скачиваем видео с Rutube с помощью Python

Рассматривая текущие реалии можно предположить, что вполне возможно, в довольно скором времени начнется миграция видеоблогеров на другие платформы для размещения своего видеоконтента. И вполне возможно, что одной из таких платформ станет Rutube. Тем более не так давно они провели презентацию, из которой стало уже понятно, что движения по платформе, хоть какие-то появились. Ну и если они еще предложат «вкусные» условия по монетизации контента, то, почему бы и нет? Но, все это лирика. И по большей части относится к разряду предсказаний или гадания на кофейной гуще. У меня же здесь немного другая цель. Я решил попробовать скачать видео с данной платформы. И ниже показываю, что у меня получилось.

rutube_title.jpg


Что понадобиться?

Для начала нужно установить библиотеку requests. Здесь все достаточно просто. Пишем в терминале редактора кода или в терминале ОС, которую вы используете, команду:

pip install requests

После того, как данная библиотека установиться, нужно будет скачать ffmpeg и прописать к нему путь в переменной среды path. Собственно скачиваем саму программу. Никакой установки она не требует. Достаточно скопировать ее в то место, где она будет жить в последующем и скопировать к ней путь. Далее идем в «Пуск», «Параметры», «Система», «О программе» и в панели справа выбираем пункт меню «Дополнительные параметры системы».

000.png

В открывшемся окне щелкаем по кнопке «Переменные среды».

001.png

На следующем шаге выделяем переменную Path и щелкаем по кнопке «Изменить».

002.png

Нажимаем кнопку «Создать» и вписываем путь к исполняемому файлу. К примеру: «C:\FFMPEG\ffmpeg.exe». Путь вписывается без кавычек. После чего жмем кнопку «ОК» и закрываем все открытые ранее окна.

003.png

На этом подготовительный этап можно считать завершенным. Приступим к исследованию сайта и написанию кода.

Здесь хотелось бы вставить небольшой дисклеймер. Я только начинаю программировать на питоне, потому прошу меня сильно не пинать. Что получилось, то получилось. Но, оно работает. Хотя, нет пределу для совершенства… )


Исследуем код страницы с видео

Для примера я взял короткое видео по адресу:



Часть этого адреса, а именно идентификатор видео нам понадобиться в дальнейшем. Почему видео небольшое? Ну, тут все просто. Это снизит нагрузку на сервер Rutube с моего адреса. Так как скачивать во время тестов придется меньше. И меньше вероятность того, что сервер меня заблокирует. И чтобы банально долго не ждать скачивания. Ведь при написании кода нужно будет проводить тест работы кода.

Данная платформа пилит видео на сегменты. Примерно по восемь секунд в каждом, а потом, в процессе воспроизведения видео их подгружает. Это не особенно хорошо. Но, думаю, что не критично. Исследуем код страницы. Щелкаем правой кнопкой мыши по странице с видео и выбираем в меню пункт «Исследовать элемент».

screenshot1.png

Скажу сразу, что в коде страницы ничего интересного нет. Ну или того, что привело бы нас к ссылке на сегменты видео. Поэтому даже не буду в нем копаться. Перехожу на вкладку Network, выставляю фильтр для запросов Feth/XHR и обновляю страницу с видео. После обновления страницы в консоль посыпалось большое количество запросов. Я, конечно же, предварительно покопался в них и уже знаю, что нам нужен запрос имя которого начинается с ?no_404… Это GET запрос который возвращает JSON с параметрами видео. Вот собственно он на картинке:

screenshot2.png

Жмем мышкой на запрос и видим в правой колонке консоли, что в JSON, который прилетает в ответ на запрос можно получить самую разнообразную информацию о видео. Но, в данный момент, так как мы хотим его скачать, нас интересуют такие параметры как информация о названии канала, информация о названии видео. При желании, тут же доступна информация и о категории, к которой данное видео относиться, но здесь нас интересует только название канала. Находиться оно по пути [“author”][“name”].

screenshot3.png

Прокручиваем запрос немного ниже и видим, что информация о названии видео так же присутствует и находиться в разделе [“title”]. И основное, то, что интересует больше всего, это ссылка на список плейлистов с различным разрешением видео. Это не сам плейлист, а только список со ссылками. Тем не менее, его нужно получить для того, чтобы можно было двигаться дальше.

screenshot4.png


Получаем данные из JSON

Таким образом, из данного JSON мы можем получить информацию о названии канала, информацию о названии видео и ссылку на список плейлистов. Как я писал выше, ссылка на видео в данном случае нам пригодиться, так как содержит его идентификатор. Это будет нужно для того, чтобы в будущем мы могли загрузить любое видео с видеохостинга, а не только видео из теста. Копируем ссылку на GET-запрос. Щелкаем правой кнопкой по нужному нам запросу и выбираем пункт меню «Copy – Copy link address». Вот собственно ссылка, которую я скопировал:



Часть ссылки после options как раз и есть идентификатор видео, который мы будем менять в будущем для загрузки других видео. Ну, а теперь, когда мы знаем, откуда брать данные, напишем код для их получения. На всякий случай мне понадобятся заголовки для запроса. Их я скопирую из самого запроса на вкладке Headers. Для заголовков я возьму user-agent и accept.

Python:
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}

Напишем функцию, которая будет получать JSON и извлекать из него данные: get_m3u8_list(url):

Python:
def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8

Так как в названии канала и в названии видео могут содержаться всяческие символы, которые будут мешать при сохранении видео с нужным названием, а так же создания папки с названием канала, создадим список из наиболее часто встречающихся символов и пробежимся по названию канала и видео в цикле, где эти символы и заменим с помощью replace(). А после пробелы в названии канала и видео заменим на знак «_». Это будет нужно для того, чтобы ffmpeg при конвертации отработал корректно. Иначе он выдает ошибку о том, что видео для конвертации не найдено. Можно эту ошибку обойти. Но, чтобы не усложнять код, проще заменить пробелы. Ну и далее получаем ссылку на список плейлистов. После чего возвращаем из функции полученные значения. Вот код данного этапа:

Python:
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}


def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8


def main():
    url = input('[+] - Введите ссылку на видео для загрузки >>> ').split("/")[-2]
    m3u8_url = get_m3u8_list(f'https://rutube.ru/api/play/options/{url}/?no_404=true&referer=https%3A%2F%2Frutube.ru')
 

if __name__ == "__main__":
    main()

Так как мы получаем список со ссылками на плейлисты, то нужно его исследовать. А вернее, то, что мы получаем. А получаем мы содержимое со ссылками, где последняя ссылка, это ссылка на видео самого высокого качества. Ее мы и будем брать для загрузки сегментов. Таким образом у нас отпадет необходимость в поиске видео самого высокого качества и в случае, если, к примеру, видео с разрешением 720p не окажется в списке, мы получим ссылку на самое максимально возможное качество для данного видео.

screenshot5.png


Получаем ссылку на плейлист

Итак, мы получили список с нужными нам данными. Теперь нужно получить список плейлистов и извлечь из него ссылку на нужный нам. В плейлисте содержится список видеосегментов, которые подгружаются при просмотре видео. И данный список нам будет очень нужен. Позже поймете зачем.

Создадим функцию get_link_from_m3u8(url_m3u8), которая получает на входе ссылку на список ссылок на плейлисты. А на выходе этой функции мы получим ссылку на нужный нам плейлист. Ниже приведен уже модифицированный код с добавленной в него функцией:

Python:
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}


def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8


def get_link_from_m3u8(url_m3u8):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    req = requests.get(url=url_m3u8, headers=headers)
    data_m3u8_dict = []
    with open('seg\\pl_list.txt', 'w', encoding='utf-8') as file:
        file.write(req.text)
    with open('seg\\pl_list.txt', 'r', encoding='utf-8') as file:
        src = file.readlines()

    for item in src:
        data_m3u8_dict.append(item)

    url_playlist = data_m3u8_dict[-1]
    return url_playlist


def main():
    url = input('[+] - Введите ссылку на видео для загрузки >>> ').split("/")[-2]
    m3u8_url = get_m3u8_list(f'https://rutube.ru/api/play/options/{url}/?no_404=true&referer=https%3A%2F%2Frutube.ru')
    m3u8_link = get_link_from_m3u8(m3u8_url[2])


if __name__ == "__main__":
    main()

Ну, а теперь небольшие пояснения. Сохраняем полученные значения в текстовый файл, после, открываем его и загоняем построчно в список. Ну, а затем уже извлекаем из списка последний элемент. Возвращаем полученное значение для дальнейшего использования.


Получаем количество сегментов видео

Что же, теперь у нас есть ссылка на плейлист, в котором содержаться все имена сегментов, которые подгружаются в процессе воспроизведения. Нам нужно получить имя самого последнего сегмента и вычленить из него порядковый номер, для того, чтобы понимать, сколько сегментов для загрузки нужно будет всего. Создаем функцию get_segment_count(m3u8_link). На входе она получает ссылку на плейлист, а на выходе возвращает количество сегментов. Вот код с добавленной функцией:

Python:
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}


def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8


def get_link_from_m3u8(url_m3u8):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    req = requests.get(url=url_m3u8, headers=headers)
    data_m3u8_dict = []
    with open('seg\\pl_list.txt', 'w', encoding='utf-8') as file:
        file.write(req.text)
    with open('seg\\pl_list.txt', 'r', encoding='utf-8') as file:
        src = file.readlines()

    for item in src:
        data_m3u8_dict.append(item)

    url_playlist = data_m3u8_dict[-1]
    return url_playlist


def get_segment_count(m3u8_link):
    req = requests.get(url=m3u8_link, headers=headers)
    data_seg_dict = []
    for seg in req:
        data_seg_dict.append(seg)
    seg_count = str(data_seg_dict[-2]).split("/")[-1].split("-")[1]
    return seg_count


def main():
    url = input('[+] - Введите ссылку на видео для загрузки >>> ').split("/")[-2]
    m3u8_url = get_m3u8_list(f'https://rutube.ru/api/play/options/{url}/?no_404=true&referer=https%3A%2F%2Frutube.ru')
    m3u8_link = get_link_from_m3u8(m3u8_url[2])
    seg_count = int(get_segment_count(m3u8_link))


if __name__ == "__main__":
    main()

Ну, а теперь пояснения. Тут все достаточно просто. Делаем запрос и получаем плейлист. Создаем словарь для того, чтобы в него добавлять полученные значения с именами видеосегментов. Заполняем в цикле список из запроса. После чего получаем -2 элемент. В -1 элементе содержится служебная информация. Далее разбиваем полученную строку и очищаем от ненужных нам символов. Ну, а далее получаем цифру из названия последнего сегмента. Это и будет искомое значение. Его мы и возвращаем из функции.


Получаем ссылку для загрузки видео

Теперь нужно получить ссылку для загрузки видео, в которую мы будем подставлять нужные значения и скачивать сегменты. Данная ссылка у нас уже есть. Она содержится в ссылке на плейлист. Нужно ее только очистить от всего лишнего. Поэтому создадим функцию, в которой это и сделаем. Назовем ее, к примеру, get_download_link(m3u8_link). На входе в нее будет передаваться ссылка на плейлист, очищаться и на выходе возвращаться уже очищенной. Вот код с данной функцией:

Python:
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}


def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8


def get_link_from_m3u8(url_m3u8):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    req = requests.get(url=url_m3u8, headers=headers)
    data_m3u8_dict = []
    with open('seg\\pl_list.txt', 'w', encoding='utf-8') as file:
        file.write(req.text)
    with open('seg\\pl_list.txt', 'r', encoding='utf-8') as file:
        src = file.readlines()

    for item in src:
        data_m3u8_dict.append(item)

    url_playlist = data_m3u8_dict[-1]
    return url_playlist


def get_segment_count(m3u8_link):
    req = requests.get(url=m3u8_link, headers=headers)
    data_seg_dict = []
    for seg in req:
        data_seg_dict.append(seg)
    seg_count = str(data_seg_dict[-2]).split("/")[-1].split("-")[1]
    return seg_count


def get_download_link(m3u8_link):
    link = f'{m3u8_link.split(".m3u8")[0]}/'
    return link


def main():
    url = input('[+] - Введите ссылку на видео для загрузки >>> ').split("/")[-2]
    m3u8_url = get_m3u8_list(f'https://rutube.ru/api/play/options/{url}/?no_404=true&referer=https%3A%2F%2Frutube.ru')
    m3u8_link = get_link_from_m3u8(m3u8_url[2])
    seg_count = int(get_segment_count(m3u8_link))
    dwnl_link = get_download_link(m3u8_link)


if __name__ == "__main__":
    main()


Загружаем сегменты видео

Теперь, когда у нас есть вся нужная информация, можно приступать к загрузке сегментов. Для этого я создам функцию get_download_segment(link, count), в которую на входе будет подаваться очищенная в предыдущей функции ссылка, и количество сегментов для загрузки. Возвращать данная функция ничего не будет. Она будет просто загружать сегменты видео. И код еще раз, уже с функцией загрузки сегментов:

Python:
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}


def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8


def get_link_from_m3u8(url_m3u8):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    req = requests.get(url=url_m3u8, headers=headers)
    data_m3u8_dict = []
    with open('seg\\pl_list.txt', 'w', encoding='utf-8') as file:
        file.write(req.text)
    with open('seg\\pl_list.txt', 'r', encoding='utf-8') as file:
        src = file.readlines()

    for item in src:
        data_m3u8_dict.append(item)

    url_playlist = data_m3u8_dict[-1]
    return url_playlist


def get_segment_count(m3u8_link):
    req = requests.get(url=m3u8_link, headers=headers)
    data_seg_dict = []
    for seg in req:
        data_seg_dict.append(seg)
    seg_count = str(data_seg_dict[-2]).split("/")[-1].split("-")[1]
    return seg_count


def get_download_link(m3u8_link):
    link = f'{m3u8_link.split(".m3u8")[0]}/'
    return link


def get_download_segment(link, count):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    for item in range(1, count+1):
        print(f'[+] - Загружаю сегмент {item}/{count}')
        req = requests.get(f'{link}segment-{item}-v1-a1.ts')
        with open(f'seg\\segment-{item}-v1-a1.ts', 'wb') as file:
            file.write(req.content)
    print('[INFO] - Все сегменты загружены')


def main():
    url = input('[+] - Введите ссылку на видео для загрузки >>> ').split("/")[-2]
    m3u8_url = get_m3u8_list(f'https://rutube.ru/api/play/options/{url}/?no_404=true&referer=https%3A%2F%2Frutube.ru')
    m3u8_link = get_link_from_m3u8(m3u8_url[2])
    seg_count = int(get_segment_count(m3u8_link))
    dwnl_link = get_download_link(m3u8_link)
    get_download_segment(dwnl_link, seg_count)


if __name__ == "__main__":
    main()

Для того, чтобы не мусорить сегментами в той папке, где работает наш скрипт, создадим временную папку для загрузки в нее сегментов. Проверяем ее наличие, а если нет – создаем. Далее создаем цикл, который пробегается по диапазону с количеством сегментов. В этом цикле мы формируем нужную нам ссылку и загружаем сегмент на диск, в только что созданную папку. Чтобы не было скучно во время этого процесса, выведем принты в терминал о загрузке каждого сегмента и об полном ее окончании, когда уже все сегменты будут загружены.


Объединяем сегменты в одно видео формата ts и конвертируем в mp4

Чисто практически, да и в теории, можно оставить объединенное видео в формате ts. Оно вполне себе проигрывается с помощью проигрывателя. Но, мне не понравился небольшой глюк при проигрывании. Если я хочу видео перемотать, у него начинается рассинхронизация между звуком и видео. Можно подобрать, конечно, плеер, который будет это все корректно воспроизводить. Но проще видео конвертировать в нужный формат, а именно mp4. Создаем функцию merge_ts(author, title, count), на вход которой подаем название канала, название видео и количество сегментов загруженного видео для объединения. Далее уже будет представлен полный код загрузки и конвертации видео, а пояснения по последней функции я дам немного ниже:

Python:
import os.path
import shutil

import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/98.0.4758.132 YaBrowser/22.3.1.892 Yowser/2.5 Safari/537.36',
    'accept': '*/*'
}


def get_m3u8_list(url):
    req = requests.get(url=url, headers=headers)
    video_data = req.json()
    video_author = video_data['author']['name']
    video_title = video_data['title']
    dict_repl = ["/", "\\", "[", "]", "?", "'", '"', ":", "."]
    for repl in dict_repl:
        if repl in video_title:
            video_title = video_title.replace(repl, "")
        if repl in video_author:
            video_author = video_author.replace(repl, "")
    video_title = video_title.replace(" ", "_")
    video_author = video_author.replace(" ", "_")

    video_m3u8 = video_data['video_balancer']['m3u8']
    return video_author, video_title, video_m3u8


def get_link_from_m3u8(url_m3u8):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    req = requests.get(url=url_m3u8, headers=headers)
    data_m3u8_dict = []
    with open('seg\\pl_list.txt', 'w', encoding='utf-8') as file:
        file.write(req.text)
    with open('seg\\pl_list.txt', 'r', encoding='utf-8') as file:
        src = file.readlines()

    for item in src:
        data_m3u8_dict.append(item)

    url_playlist = data_m3u8_dict[-1]
    return url_playlist


def get_segment_count(m3u8_link):
    req = requests.get(url=m3u8_link, headers=headers)
    data_seg_dict = []
    for seg in req:
        data_seg_dict.append(seg)
    seg_count = str(data_seg_dict[-2]).split("/")[-1].split("-")[1]
    return seg_count


def get_download_link(m3u8_link):
    link = f'{m3u8_link.split(".m3u8")[0]}/'
    return link


def get_download_segment(link, count):
    if not os.path.isdir('seg'):
        os.mkdir('seg')
    for item in range(1, count+1):
        print(f'[+] - Загружаю сегмент {item}/{count}')
        req = requests.get(f'{link}segment-{item}-v1-a1.ts')
        with open(f'seg\\segment-{item}-v1-a1.ts', 'wb') as file:
            file.write(req.content)
    print('[INFO] - Все сегменты загружены')


def merge_ts(author, title, count):
    if not os.path.isdir(author):
        os.mkdir(author)
    with open(f'seg\\{title}.ts', 'wb') as merged:
        for ts in range(1, count+1):
            with open(f'seg\\segment-{ts}-v1-a1.ts', 'rb') as mergefile:
                shutil.copyfileobj(mergefile, merged)
    os.system(f"ffmpeg -i seg\\{title}.ts {author}\\{title}.mp4")
    print('[+] - Конвертирование завершено')

    file_dir = os.listdir('seg')
    for file in file_dir:
        os.remove(f'seg\\{file}')
    os.removedirs('seg')


def main():
    url = input('[+] - Введите ссылку на видео для загрузки >>> ').split("/")[-2]
    m3u8_url = get_m3u8_list(f'https://rutube.ru/api/play/options/{url}/?no_404=true&referer=https%3A%2F%2Frutube.ru')
    m3u8_link = get_link_from_m3u8(m3u8_url[2])
    seg_count = int(get_segment_count(m3u8_link))
    dwnl_link = get_download_link(m3u8_link)
    get_download_segment(dwnl_link, seg_count)
    merge_ts(m3u8_url[0], m3u8_url[1], seg_count)


if __name__ == "__main__":
    main()

А теперь пояснения. Открываем файл для записи в побайтовом режиме. После чего создаем цикл, в котором по очереди открываем и читаем все загруженные сегменты побайтово для добавления их с помощью shutil.copyfileobj в один файл для последующей записи. Ну и сохраняем файл в папке с сегментами, но с именем, которое уже было получено из JSON файла в самом начале.

Ну, а далее создаем папку с названием канала и запускаем конвертацию видео с помощью os.system, которая позволяет выполнять консольные команды. Нужно сказать, что я использую в данный момент Windows. В ОС Linux нужно будет воспользоваться функцией subprocess.

Теперь, после того, как файл конвертирован и сохранен, остается только прибраться в директории. Для этого сканируем папку с сегментами. Получаем список файлов и в цикле их все удаляем. После чего удаляем и саму папку.

В принципе все. Способ достаточно простой. Я думал, что будет сложнее. Кто знает, может быть с течением времени они что-то поменяют в коде и написанный мной скрипт перестанет работать. Но в данное время, все работает. Конечно же, те кто уже давно программирует на питоне, могут значительно улучшить данный код. Но, снова прошу вас меня сильно не пинать. Я только учусь программировать. А для новичков, вроде меня, для понимания общих принципов работы, данный код, думаю, будет полезен.

Сюда же, для большей универсальности кода, чтобы он мог работать под разными ОС, можно добавить определение платформы, на которой он запущен и в зависимости от этого менять разделители в путях к папкам и файлам. Так же, в зависимости от ОС вызывать терминал разными способами...

Спасибо за внимание! Надеюсь, что эта статься кому-то смогла помочь )
 
Последнее редактирование:
Мы в соцсетях: