Как и у большинства тех, кто занимается изучением какого-либо языка программирования, у меня скопилось довольно много курсов по различным его аспектам. Какие-то я просмотрел, до каких-то еще не дошли руки, так как это все же много часов видео. Так или иначе, объем занимаемый этими видео на диске стал превышать критический. А потому было решено их куда-нибудь убрать. Просто потому, что вроде бы и удалять жалко, и оставлять накладно. Немного подумав, я вспомнил, что ВК позволяет загружать достаточно большие объемы видео. Чем не облачный диск, да еще с удобным плеером? Сначала я грузил видео вручную. А это довольно трудоемкий процесс, который занимает достаточно много времени. Немного помучившись, я решил сделать небольшой скрипт, который будет делать эту задачу за меня – создавать плейлисты, выставлять на них права доступа и загружать видео.
Что потребуется?
Так как мы будем работать с методами ВК API, будет разумно использовать специальную библиотеку предназначенную для этих целей - vk-api. В процессе работы скрипта довольно удобно наблюдать выводимую в терминал информацию в цвете, поэтому, для раскрашивания вывода в терминале установим библиотеку colorama. Для их установки необходимо открыть терминал вашей IDE, если вы пользуетесь IDE, ну или просто открыть терминал и ввести команду:
Также, для того, чтобы работать с ВК API необходимо получить токен. Процесс получения токена я описал в этой статье, в самом ее начале.
Единственное – не забудьте отметить права доступа к видео, так как скрипт именно для этого и предназначен.
После этого я создал файл set_vk.py, куда поместил полученный токен, а также пользовательский ID. Если у вас отображаемое имя не состоит из вашего ID, узнать его можно с помощью этого
После того, как установлены необходимые библиотеки и сделаны приготовления, создадим файл скрипта - vk_video_upload.py и импортируем в него необходимые для его работы библиотеки, а также ID и token.
Затем инициализируем colorama, создадим объект VkApi, в который передадим полученный токен. Данный объект будет нам необходим для авторизации. Также создадим объект VkUpload, куда передадим созданную сессию VkApi. Данный объект нам будет необходим для загрузки видео в плейлист.
Создадим глобальную переменную NAMES, которую определим как словарь. Сюда мы будем складывать полученные названия плейлистов и их ID, если таковые имеются у пользователя, для проверки на существование плейлиста с тем названием, который вы хотите создать. Создадим переменную TITLES, которую определим как множество и которая, также будет глобальной. Сюда мы поместим, при необходимости, названия видео в существующем плейлисте. Как вы уже, наверное, поняли, скрипт будет уметь докачивать недогруженные видео.
Конвертирование размеров. Вспомогательная функция
Создадим функцию def get_size(bts: int, ending='B') -> str, которая будет принимать целове число, а также при необходимости суффикс и конвертировать данное число в удобочитаемый формат. Биты, байты, кило-мега байты и так далее. Итерируемся по списку с величинами и проверяем, является ли переданное в функцию число меньше 1024. Если да, возвращаем его из функции с добавлением значения из списка и суффикса. Если нет, делим на 1024.
Получение списка видеофайлов в директории
Создадим функцию def get_files_dir(path: str) -> (list, bool). На входе она получает путь к директории, список файлов в которой необходимо получить. А возвращает список с путями к найденным файлам или False, в случае неудачи.
Создадим список files_path, в который будем помещать полученные пути к файлам видео. С помощью os.walk рекурсивно обойдем переданную в функцию директорию. Это сделано для того, чтобы проверить на наличие видео все вложенные папки директории, если таковые присутствуют в ней. Ну и после итерируемся по найденным файлам, составляем путь к ним с помощью Path и добавляем в список. Затем, после окончания цикла проверяем, не является ли список с путями пустым и если нет, возвращаем его из функции. Если же список пуст, возвращаем из функции False.
Также проверяем, чтобы расширение найденного файла соответствовало одному из форматов списка с ними. Я добавил только три, но если есть необходимость, сюда можно добавить все форматы, которые поддерживаются ВК.
Получение названия альбомов и ID
Создадим функцию def albums_name() -> None. Она ничего не получает и не возвращает. Её работа заключается в том, чтобы получить список названий плейлистов пользователя и их ID. Названия плейлистов будут необходимы для того, чтобы выполнять проверку, существует ли создаваемый плейлист у пользователя. А если существует, то, так как функция также получает ID и добавляет название плейлиста и ID в словарь, то забирать полученный ID для выполнения последующих операций. Хотя, создание плейлистов с одинаковым названием не является критичным для ВК, так как их идентификация идет по ID, все же, хотелось бы избежать дублирования.
Выводим в терминал информацию для пользователя о том, что получаем список плейлистов. Затем необходимо получить количество плейлистов, чтобы понимать, сколько их всего и составить диапазон для итерации по ним. Поэтому, используем метод ВК API video.getAlbums, куда передаем токен, ID владельца плейлиста (это мы), смещение по которому необходимо получить информацию и количество возвращаемых данных. В ответ мы получаем json-файл, в котором один из ключей – count, в котором и содержится общее количество плейлистов. А так как мы указали параметр count равным 0, то дополнительной информации получено не будет. Да и незачем, в данном случае перегружать запрос.
Затем проверяем, не является ли полученное количество плейлистов 0. Если да, сообщаем об этом пользователю и выходим из функции. В этом случае проверка будет происходить по пустому глобальному словарю NAMES, а так как значений в нем нет, любое название плейлиста будет принято для создания. Если же количество плейлистов не является нулевым, сообщаем пользователю, сколько плейлистов у пользователя. После итерируемся по диапазону с полученным значением. Дело в том, что данный метод за один запрос возвращает не более 100 плейлистов. Поэтому, необходимо в запросе указывать смещение, по которому необходимо получать информацию, чтобы получить названия всех плейлистов пользователя. Выполняем запрос к ВК API, получаем json с данными. Забираем из него по ключу items названия плейлистов, которые содержаться в ключах title, а также их ID, которые содержатся в ключах id и помещаем это в словарь NAMES.
Получаем название видео из плейлиста
Создадим функцию def get_video_title(album_id: int) -> None. На входе она получает id плейлиста, информацию из которого необходимо получить. Если вы помните, то данный id мы получали в предыдущей созданной функции. Эта же функция будет работать только тогда, когда плейлист создаваемый пользователем существует. В этом случае нам будет необходимо получить названия видео в плейлисте, чтобы потом можно было проверять, не существует ли в нем уже загружаемое видео. А если нет, загрузку не производить. Выполняем запрос к методу ВК API video.get, куда передаем токен, ID владельца плейлиста, ID плейлиста информацию из которого необходимо получить. В ответ возвращается json, в котором содержаться все названия видео, которые есть в плейлисте.Итерируемся по ключу items из которого по ключу title забираем название и добавляем в множество TITLES. Но есть видео, у которых названия, как такового нет. А значит нет и ключа title. Поэтому, возникнет исключение, которое необходимо обработать. Заключаем код обращения к ключу title в блок try – except и, если исключение возникает, просто продолжаем работу цикла.
Создание плейлиста
Создадим функцию def album_create_id_get(title: str) -> (int, bool). В нее передается название создаваемого плейлиста, а возвращает она его ID или False в случае неудачи.
Для начала проверяем, существует ли переданное в функцию название в словаре NAMES. Если название существует, значит, плейлист уже есть, а, следовательно, создавать его повторно не нужно. Поэтому, получаем названия видео в плейлисте. Выводим в терминал информацию для пользователя, что плейлист существует и, что мы получаем название видео в нем. После чего возвращаем из функции ID плейлиста полученное из словаря NAMES.
Если же плейлиста нет, необходимо его создать. Поэтому, обращаемся к методу ВК API video.addAlbum, в который передаем токен, название плейлиста, уровень приватности. Подробнее об уровнях приватности можно почитать в документации
Итерация по файлам видео
Созадим функцию def get_upload_url(album_id: int, files_path: list) -> None. Она ничего не возвращает, но принимет ID плейлиста, а также список с путями к видеофайлам, которые были найдены ранее.
Создадим список err, в который будем помещать пути к файлам видео в случае возникновения ошибки загрузки. Итерируемся по списку путей к файлам. Получаем имя файла, которое будет необходимо для передачи в функцию загрузки. Проверяем, существует ли такое имя в файла в множестве TITLES, если да, переходим к следующему файлу. Если нет, получаем его размер (особого функционала не несет; служит больше для вывода информации пользователю). Выводим в терминал информацию для пользователя о номере загружаемого видео из существующих, название видео и его размер. Проверяем, если функция загрузки вернула True, выводим сообщение о том, что видео загружено. Если False, сообщаем, что оно не загружено и добавляем путь к видео в список err. Ждем секунду между итерациями. Это позволит немного снизить нагрузку на сервера ВК. Хотя и такая себе забота )).
После окончания итерации по списку путей проверяем, есть ли что-то в списке err. Если есть, выводим эти данные для пользователя в терминал. Если нет, выводим сообщение, что все видео загружены.
Функция загрузки видео в плейлист
Создадим функцию video_file_upload(file: str, album_id: int) -> bool, в которую передаем путь к файлу видео и ID плейлиста. Получаем из пути к файлу имя загружаемого видео.
Для загрузки видео будем использовать метод video из класса VkUpload. Для того, чтобы загрузить видео ему необходимо передать путь к загружаемому файлу, имя файла, ID плейлиста, в который нужно загрузить видео, а также уровни приватности для видео и комментариев. После чего выполняется загрузка. По окончании загрузки возвращается json, в котором один из ключей size, содержит размер загруженного видео. Проверяем, существует ли такой ключ, если да, возвращаем True, если нет – False. Также обработаем прерывание функции с клавиатуры. Здесь не торопитесь закрывать терминал, если после нажатия комбинации клавиш «Ctrl + C» ничего не произошло. Это лишь значит, что скрипт завершит свою работу после загрузки последнего видео, на котором он был прерван. Ну и в случае с возникновением иных исключений возвращаем False.
Здесь следуем сказать, что реализовать функцию загрузки видео можно несколько иначе. Однако, в этом случае вам придется самостоятельно выполнить получение ссылки на загрузку видео, после чего с помощью requests.post выполнить загрузку по полученной ссылке, где в качестве параметра нужно будет указать путь к видео. Ниже покажу кусочек кода, в котором получается ссылка на загрузку и выполняется загрузка с помощью данного метода. На мой взгляд, различия здесь минимальны, за исключением того, что метод video берет на себя все функции по получению ссылки и загрузке видео.
Запрос пути к директории с видео
Создадим функцию def main() -> None, в которой будем запрашивать путь к директории с видео.
Запрашиваем у пользователя путь к директории. Проверяем, есть ли такой путь и является ли он директорией, а также, не ввел ли пользователь пустое значение. Если проверка на проходит, сообщаем пользователю информацию, чтобы он проверил путь и выходим из скрипта. Если все в порядке, получаем название для плейлиста из имени директории. Я посчитал, так как у меня курсы, что это будет практичнее и быстрее. Вы же можете запросить у пользователя данную информацию с помощью input. Затем получаем список путей к видео в директории. Если список не пуст, получаем названия плейлистов пользователя. Создаем плейлист с полученным названием. После чего запускаем функцию для загрузки найденного в директории видео. Если что-то пошло не так, сообщаем об этом пользователю.
Что ж, такой вот небольшой скрипт получился. Я уже проверил его работу. И в качестве демонстрации создал небольшое видео, в котором его работа показана в самом конце.
А на этом, пожалуй, всё.
Спасибо за внимание. Надеюсь, данная информация будет вам полезна
Что потребуется?
Так как мы будем работать с методами ВК API, будет разумно использовать специальную библиотеку предназначенную для этих целей - vk-api. В процессе работы скрипта довольно удобно наблюдать выводимую в терминал информацию в цвете, поэтому, для раскрашивания вывода в терминале установим библиотеку colorama. Для их установки необходимо открыть терминал вашей IDE, если вы пользуетесь IDE, ну или просто открыть терминал и ввести команду:
pip install vk-api colorama
Также, для того, чтобы работать с ВК API необходимо получить токен. Процесс получения токена я описал в этой статье, в самом ее начале.
Единственное – не забудьте отметить права доступа к видео, так как скрипт именно для этого и предназначен.
После этого я создал файл set_vk.py, куда поместил полученный токен, а также пользовательский ID. Если у вас отображаемое имя не состоит из вашего ID, узнать его можно с помощью этого
Ссылка скрыта от гостей
. Заходите на свою страницу, копируете адрес, вставляете в поле и жмете кнопку «Определить ID». После копируете ID и добавляете в созданный файл. Его структура, в моем случае такова:
Python:
user_vk_id = 'ваш_id'
token_vk = 'ваш_token'
После того, как установлены необходимые библиотеки и сделаны приготовления, создадим файл скрипта - vk_video_upload.py и импортируем в него необходимые для его работы библиотеки, а также ID и token.
Python:
import os
import sys
import time
from pathlib import Path
from colorama import Fore, init
from vk_api import VkApi, VkUpload
from set_vk import token_vk, user_vk_id
Затем инициализируем colorama, создадим объект VkApi, в который передадим полученный токен. Данный объект будет нам необходим для авторизации. Также создадим объект VkUpload, куда передадим созданную сессию VkApi. Данный объект нам будет необходим для загрузки видео в плейлист.
Создадим глобальную переменную NAMES, которую определим как словарь. Сюда мы будем складывать полученные названия плейлистов и их ID, если таковые имеются у пользователя, для проверки на существование плейлиста с тем названием, который вы хотите создать. Создадим переменную TITLES, которую определим как множество и которая, также будет глобальной. Сюда мы поместим, при необходимости, названия видео в существующем плейлисте. Как вы уже, наверное, поняли, скрипт будет уметь докачивать недогруженные видео.
Python:
init()
session = VkApi(token=token_vk)
upload = VkUpload(session)
NAMES = dict()
TITLES = set()
Конвертирование размеров. Вспомогательная функция
Создадим функцию def get_size(bts: int, ending='B') -> str, которая будет принимать целове число, а также при необходимости суффикс и конвертировать данное число в удобочитаемый формат. Биты, байты, кило-мега байты и так далее. Итерируемся по списку с величинами и проверяем, является ли переданное в функцию число меньше 1024. Если да, возвращаем его из функции с добавлением значения из списка и суффикса. Если нет, делим на 1024.
Python:
def get_size(bts: int, ending='B') -> str:
"""
Конвертация размера.
:param bts: Размер.
:param ending: Суффикс.
:return: Конвертированное значение с суффиксом.
"""
for item in ["", "K", "M", "G", "T", "P"]:
if bts < 1024:
return f"{bts:.2f} {item}{ending}"
bts /= 1024
Получение списка видеофайлов в директории
Создадим функцию def get_files_dir(path: str) -> (list, bool). На входе она получает путь к директории, список файлов в которой необходимо получить. А возвращает список с путями к найденным файлам или False, в случае неудачи.
Создадим список files_path, в который будем помещать полученные пути к файлам видео. С помощью os.walk рекурсивно обойдем переданную в функцию директорию. Это сделано для того, чтобы проверить на наличие видео все вложенные папки директории, если таковые присутствуют в ней. Ну и после итерируемся по найденным файлам, составляем путь к ним с помощью Path и добавляем в список. Затем, после окончания цикла проверяем, не является ли список с путями пустым и если нет, возвращаем его из функции. Если же список пуст, возвращаем из функции False.
Также проверяем, чтобы расширение найденного файла соответствовало одному из форматов списка с ними. Я добавил только три, но если есть необходимость, сюда можно добавить все форматы, которые поддерживаются ВК.
Python:
def get_files_dir(path: str) -> (list, bool):
"""
Чтение файлов в директории. Операция выполняется рекурсивно.
Файлы будут прочитаны также из всех субдиректорий.
:param path: Путь к директории для чтения.
:return: Список с путями файлов.
"""
files_path = []
for path, dirs, files in os.walk(path):
for file in files:
if (Path(path) / file).suffix in [".mp4", ".avi", ".mov"]:
files_path.append(str(Path(path) / file))
return files_path if files_path else False
Получение названия альбомов и ID
Создадим функцию def albums_name() -> None. Она ничего не получает и не возвращает. Её работа заключается в том, чтобы получить список названий плейлистов пользователя и их ID. Названия плейлистов будут необходимы для того, чтобы выполнять проверку, существует ли создаваемый плейлист у пользователя. А если существует, то, так как функция также получает ID и добавляет название плейлиста и ID в словарь, то забирать полученный ID для выполнения последующих операций. Хотя, создание плейлистов с одинаковым названием не является критичным для ВК, так как их идентификация идет по ID, все же, хотелось бы избежать дублирования.
Выводим в терминал информацию для пользователя о том, что получаем список плейлистов. Затем необходимо получить количество плейлистов, чтобы понимать, сколько их всего и составить диапазон для итерации по ним. Поэтому, используем метод ВК API video.getAlbums, куда передаем токен, ID владельца плейлиста (это мы), смещение по которому необходимо получить информацию и количество возвращаемых данных. В ответ мы получаем json-файл, в котором один из ключей – count, в котором и содержится общее количество плейлистов. А так как мы указали параметр count равным 0, то дополнительной информации получено не будет. Да и незачем, в данном случае перегружать запрос.
Затем проверяем, не является ли полученное количество плейлистов 0. Если да, сообщаем об этом пользователю и выходим из функции. В этом случае проверка будет происходить по пустому глобальному словарю NAMES, а так как значений в нем нет, любое название плейлиста будет принято для создания. Если же количество плейлистов не является нулевым, сообщаем пользователю, сколько плейлистов у пользователя. После итерируемся по диапазону с полученным значением. Дело в том, что данный метод за один запрос возвращает не более 100 плейлистов. Поэтому, необходимо в запросе указывать смещение, по которому необходимо получать информацию, чтобы получить названия всех плейлистов пользователя. Выполняем запрос к ВК API, получаем json с данными. Забираем из него по ключу items названия плейлистов, которые содержаться в ключах title, а также их ID, которые содержатся в ключах id и помещаем это в словарь NAMES.
Python:
def albums_name() -> None:
"""
Получение названий уже существующих альбомов в ВК.
Добавление названий альбомов в глобальное множество NAMES.
:return: Функция ничего не возвращает.
"""
global NAMES
print(f"\n{Fore.YELLOW}[*] Получаю названия альбомов")
count = session.get_api().video.getAlbums(access_token=token_vk, owner_id=user_vk_id, offset=0, count=0, v=5.131)
if count['count'] == 0:
print(f"{Fore.BLUE}[!] Альбомов не получено: {count['count']}")
return
print(f"{Fore.GREEN}[*] Получено альбомов: {count['count']}")
for offset in range(0, count['count'], 100):
albums = session.get_api().video.getAlbums(access_token=token_vk, owner_id=user_vk_id, offset=offset, count=100,
v=5.131)
for item in albums.get('items'):
NAMES.update({item.get('title').strip(): item.get('id')})
Получаем название видео из плейлиста
Создадим функцию def get_video_title(album_id: int) -> None. На входе она получает id плейлиста, информацию из которого необходимо получить. Если вы помните, то данный id мы получали в предыдущей созданной функции. Эта же функция будет работать только тогда, когда плейлист создаваемый пользователем существует. В этом случае нам будет необходимо получить названия видео в плейлисте, чтобы потом можно было проверять, не существует ли в нем уже загружаемое видео. А если нет, загрузку не производить. Выполняем запрос к методу ВК API video.get, куда передаем токен, ID владельца плейлиста, ID плейлиста информацию из которого необходимо получить. В ответ возвращается json, в котором содержаться все названия видео, которые есть в плейлисте.Итерируемся по ключу items из которого по ключу title забираем название и добавляем в множество TITLES. Но есть видео, у которых названия, как такового нет. А значит нет и ключа title. Поэтому, возникнет исключение, которое необходимо обработать. Заключаем код обращения к ключу title в блок try – except и, если исключение возникает, просто продолжаем работу цикла.
Python:
def get_video_title(album_id: int) -> None:
"""
Получение заголовков видео в альбоме, если альбом существует.
:param album_id: ID альбома с видео.
:return: Функция ничего не возвращает.
"""
global TITLES
title = session.get_api().video.get(access_token=token_vk, owner_id=user_vk_id, album_id=album_id, v=5.131)
for item in title.get("items"):
try:
TITLES.add(item.get('title').strip())
except Exception:
continue
Создание плейлиста
Создадим функцию def album_create_id_get(title: str) -> (int, bool). В нее передается название создаваемого плейлиста, а возвращает она его ID или False в случае неудачи.
Для начала проверяем, существует ли переданное в функцию название в словаре NAMES. Если название существует, значит, плейлист уже есть, а, следовательно, создавать его повторно не нужно. Поэтому, получаем названия видео в плейлисте. Выводим в терминал информацию для пользователя, что плейлист существует и, что мы получаем название видео в нем. После чего возвращаем из функции ID плейлиста полученное из словаря NAMES.
Если же плейлиста нет, необходимо его создать. Поэтому, обращаемся к методу ВК API video.addAlbum, в который передаем токен, название плейлиста, уровень приватности. Подробнее об уровнях приватности можно почитать в документации
Ссылка скрыта от гостей
. После чего выводим информацию для пользователя, что плейлист создан и возвращаем из функции 'album_id', который возвращается в виде json. Если же 'album_id' получен не был, возвращаем False. Если же возникло исключение – также возвращаем False, так как без созданного альбома продолжать дальнейшие действия не имеет смысла.
Python:
def album_create_id_get(title: str) -> (int, bool):
"""
Создание пустого альбома для видео в ВК.
Проверка имени альбома на существование. Если существует, добавляем суффикс.
:param title: Название для альбома.
:return: ID созданного альбома.
"""
global NAMES
if title in NAMES:
get_video_title(NAMES.get(title))
print(f'{Fore.YELLOW}[*] Альбом существует: "{title}"')
print(f'{Fore.YELLOW}[*] Загружаю названия видео из альбома: "{title}"')
return NAMES.get(title)
else:
print(f'\n{Fore.YELLOW}[*] Создаю альбом: "{title}"')
try:
album = session.get_api().video.addAlbum(access_token=token_vk, title=title, privacy='only_me', v=5.131)
print(f'{Fore.GREEN}[*] Альбом: "{title}" создан')
return album.get('album_id') if album.get('album_id') else False
except Exception:
return False
Итерация по файлам видео
Созадим функцию def get_upload_url(album_id: int, files_path: list) -> None. Она ничего не возвращает, но принимет ID плейлиста, а также список с путями к видеофайлам, которые были найдены ранее.
Создадим список err, в который будем помещать пути к файлам видео в случае возникновения ошибки загрузки. Итерируемся по списку путей к файлам. Получаем имя файла, которое будет необходимо для передачи в функцию загрузки. Проверяем, существует ли такое имя в файла в множестве TITLES, если да, переходим к следующему файлу. Если нет, получаем его размер (особого функционала не несет; служит больше для вывода информации пользователю). Выводим в терминал информацию для пользователя о номере загружаемого видео из существующих, название видео и его размер. Проверяем, если функция загрузки вернула True, выводим сообщение о том, что видео загружено. Если False, сообщаем, что оно не загружено и добавляем путь к видео в список err. Ждем секунду между итерациями. Это позволит немного снизить нагрузку на сервера ВК. Хотя и такая себе забота )).
После окончания итерации по списку путей проверяем, есть ли что-то в списке err. Если есть, выводим эти данные для пользователя в терминал. Если нет, выводим сообщение, что все видео загружены.
Python:
def get_upload_url(album_id: int, files_path: list) -> None:
"""
Итерация по файлам из директории для загрузки.
Получение ссылки на загрузку видео в альбом.
Передача данных в функцию загрузки видео.
Если видео не загружено, оно добавляется в список ошибок, и,
после завершения работы скрипта этот список, если он не пуст,
выводиться в терминал.
:param album_id: ID альбома для загрузки.
:param files_path: Список путей к видео для загрузки.
:return: Функция ничего не возвращает.
"""
global TITLES
err = []
for nm, file in enumerate(files_path):
file_name = Path(file).name.split(Path(file).suffix)[0]
if file_name in TITLES:
continue
size = get_size(Path(file).stat().st_size)
print(f'{Fore.YELLOW}Загружаю видео: "{file_name}" | {nm + 1}/{len(files_path)} | {size}')
if video_file_upload(file, album_id):
print(f'{Fore.GREEN} [!] Видео: "{file_name}" загружено')
else:
print(f'{Fore.RED} [~] Видео: "{file_name}" не загружено\n')
err.append(str(file))
time.sleep(1)
if err:
print(f"\n{Fore.BLUE}[-] Не загруженные видео:")
for er in err:
print(f"{Fore.RESET} - {er}")
else:
print(f"\n{Fore.GREEN}{'-'*31}\n[!] Все видео успешно загружены\n{'-'*31}")
Функция загрузки видео в плейлист
Создадим функцию video_file_upload(file: str, album_id: int) -> bool, в которую передаем путь к файлу видео и ID плейлиста. Получаем из пути к файлу имя загружаемого видео.
Для загрузки видео будем использовать метод video из класса VkUpload. Для того, чтобы загрузить видео ему необходимо передать путь к загружаемому файлу, имя файла, ID плейлиста, в который нужно загрузить видео, а также уровни приватности для видео и комментариев. После чего выполняется загрузка. По окончании загрузки возвращается json, в котором один из ключей size, содержит размер загруженного видео. Проверяем, существует ли такой ключ, если да, возвращаем True, если нет – False. Также обработаем прерывание функции с клавиатуры. Здесь не торопитесь закрывать терминал, если после нажатия комбинации клавиш «Ctrl + C» ничего не произошло. Это лишь значит, что скрипт завершит свою работу после загрузки последнего видео, на котором он был прерван. Ну и в случае с возникновением иных исключений возвращаем False.
Python:
def video_file_upload(file: str, album_id: int) -> bool:
"""
:param file: Путь к файлу для загрузки.
:param album_id: ID альбома для загрузки.
:return: True, если загрузка прошла успешно и был получен размер видео.
И False, если загрузка окончилась неудачей.
"""
name = str(Path(file).name.split(Path(file).suffix)[0])
try:
upl = upload.video(video_file=file, name=name, album_id=album_id, privacy_view='only_me',
privacy_comment='only_me')
return True if upl.get('size') else False
except KeyboardInterrupt:
print("До свидания!")
sys.exit(0)
except Exception:
return False
Здесь следуем сказать, что реализовать функцию загрузки видео можно несколько иначе. Однако, в этом случае вам придется самостоятельно выполнить получение ссылки на загрузку видео, после чего с помощью requests.post выполнить загрузку по полученной ссылке, где в качестве параметра нужно будет указать путь к видео. Ниже покажу кусочек кода, в котором получается ссылка на загрузку и выполняется загрузка с помощью данного метода. На мой взгляд, различия здесь минимальны, за исключением того, что метод video берет на себя все функции по получению ссылки и загрузке видео.
Python:
def get_upload_url(album_id: int, files_path: list) -> None:
"""
Итерация по файлам из директории для загрузки.
Получение ссылки на загрузку видео в альбом.
Передача данных в функцию загрузки видео.
Если видео не загружено, оно добавляется в список ошибок, и,
после завершения работы скрипта этот список, если он не пуст,
выводиться в терминал.
:param album_id: ID альбома для загрузки.
:param files_path: Список путей к видео для загрузки.
:return: Функция ничего не возвращает.
"""
err = []
for nm, file in enumerate(files_path):
file_name = Path(file).name.split(Path(file).suffix)[0]
size = get_size(Path(file).stat().st_size)
print(f'\n{Fore.YELLOW}Загружаю видео: "{file_name}" | {nm + 1}/{len(files_path)} | {size}')
upload_data = session.get_api().video.save(access_token=token_vk, name=file_name, album_id=album_id,
privacy_view='only_me', privacy_comment='only_me', v=5.131)
if upload_data.get('upload_url'):
upload = video_file_upload(file, upload_data.get('upload_url'))
if not upload:
print(f'{Fore.RED}[~] Видео: "{file_name}" не загружено\n')
err.append(str(file))
else:
print(f'{Fore.GREEN}[!] Видео: "{file_name}" загружено')
time.sleep(1)
if err:
print(f"\n{Fore.BLUE}Не загруженные видео:")
for er in err:
print(f"{Fore.RESET} - {er}")
else:
print(f"\n{Fore.GREEN}[!] Все видео успешно загружены")
def video_file_upload(file: str, upload_url: str) -> bool:
with open(file, 'rb') as file:
try:
res = requests.post(upload_url, files={'video_file': file})
return True if res.json().get('size') else False
except Exception:
return False
Запрос пути к директории с видео
Создадим функцию def main() -> None, в которой будем запрашивать путь к директории с видео.
Запрашиваем у пользователя путь к директории. Проверяем, есть ли такой путь и является ли он директорией, а также, не ввел ли пользователь пустое значение. Если проверка на проходит, сообщаем пользователю информацию, чтобы он проверил путь и выходим из скрипта. Если все в порядке, получаем название для плейлиста из имени директории. Я посчитал, так как у меня курсы, что это будет практичнее и быстрее. Вы же можете запросить у пользователя данную информацию с помощью input. Затем получаем список путей к видео в директории. Если список не пуст, получаем названия плейлистов пользователя. Создаем плейлист с полученным названием. После чего запускаем функцию для загрузки найденного в директории видео. Если что-то пошло не так, сообщаем об этом пользователю.
Python:
def main() -> None:
"""
Запрос названия альбома и директории с видео для загрузки.
Проверка директории на существование.
Запуск функции получения названия альбомов пользователя.
Запуск функции создания альбома и получения его ID.
Запуск функции загрузки видео.
"""
path = input("Введите директорию для загрузки: ")
if not Path(path).exists() or not Path(path).is_dir() or not path:
print(f"{Fore.RED}[!] Проверьте правильность ввода директории")
sys.exit(0)
title = Path(path).name.strip()
if files_path := get_files_dir(path):
albums_name()
if album_id := album_create_id_get(title):
get_upload_url(album_id, files_path)
else:
print(f'{Fore.RED}[!] Не удалось создать альбом: "{title}".\n - Завершение работы')
sys.exit(0)
else:
print("Не найдено файлов для выгрузки")
sys.exit(0)
if __name__ == "__main__":
main()
Что ж, такой вот небольшой скрипт получился. Я уже проверил его работу. И в качестве демонстрации создал небольшое видео, в котором его работа показана в самом конце.
Python:
# pip install vk-api colorama
import os
import sys
import time
from pathlib import Path
from colorama import Fore, init
from vk_api import VkApi, VkUpload
from set_vk import token_vk, user_vk_id
init()
session = VkApi(token=token_vk)
upload = VkUpload(session)
NAMES = dict()
TITLES = set()
def get_size(bts: int, ending='B') -> str:
"""
Конвертация размера.
:param bts: Размер.
:param ending: Суффикс.
:return: Конвертированное значение с суффиксом.
"""
for item in ["", "K", "M", "G", "T", "P"]:
if bts < 1024:
return f"{bts:.2f} {item}{ending}"
bts /= 1024
def get_files_dir(path: str) -> (list, bool):
"""
Чтение файлов в директории. Операция выполняется рекурсивно.
Файлы будут прочитаны также из всех субдиректорий.
:param path: Путь к директории для чтения.
:return: Список с путями файлов.
"""
files_path = []
for path, dirs, files in os.walk(path):
for file in files:
if (Path(path) / file).suffix in [".mp4", ".avi", ".mov"]:
files_path.append(str(Path(path) / file))
return files_path if files_path else False
def albums_name() -> None:
"""
Получение названий уже существующих альбомов в ВК.
Добавление названий альбомов в глобальное множество NAMES.
:return: Функция ничего не возвращает.
"""
global NAMES
print(f"\n{Fore.YELLOW}[*] Получаю названия альбомов")
count = session.get_api().video.getAlbums(access_token=token_vk, owner_id=user_vk_id, offset=0, count=0, v=5.131)
if count['count'] == 0:
print(f"{Fore.BLUE}[!] Альбомов не получено: {count['count']}")
return
print(f"{Fore.GREEN}[*] Получено альбомов: {count['count']}")
for offset in range(0, count['count'], 100):
albums = session.get_api().video.getAlbums(access_token=token_vk, owner_id=user_vk_id, offset=offset, count=100,
v=5.131)
for item in albums.get('items'):
NAMES.update({item.get('title').strip(): item.get('id')})
def get_video_title(album_id: int) -> None:
"""
Получение заголовков видео в альбоме, если альбом существует.
:param album_id: ID альбома с видео.
:return: Функция ничего не возвращает.
"""
global TITLES
title = session.get_api().video.get(access_token=token_vk, owner_id=user_vk_id, album_id=album_id, v=5.131)
for item in title.get("items"):
try:
TITLES.add(item.get('title').strip())
except Exception:
continue
def album_create_id_get(title: str) -> (int, bool):
"""
Создание пустого альбома для видео в ВК.
Проверка имени альбома на существование. Если существует, добавляем суффикс.
:param title: Название для альбома.
:return: ID созданного альбома.
"""
global NAMES
if title in NAMES:
get_video_title(NAMES.get(title))
print(f'{Fore.YELLOW}[*] Альбом существует: "{title}"')
print(f'{Fore.YELLOW}[*] Загружаю названия видео из альбома: "{title}"')
return NAMES.get(title)
else:
print(f'\n{Fore.YELLOW}[*] Создаю альбом: "{title}"')
try:
album = session.get_api().video.addAlbum(access_token=token_vk, title=title, privacy='only_me', v=5.131)
print(f'{Fore.GREEN}[*] Альбом: "{title}" создан')
return album.get('album_id') if album.get('album_id') else False
except Exception:
return False
def get_upload_url(album_id: int, files_path: list) -> None:
"""
Итерация по файлам из директории для загрузки.
Получение ссылки на загрузку видео в альбом.
Передача данных в функцию загрузки видео.
Если видео не загружено, оно добавляется в список ошибок, и,
после завершения работы скрипта этот список, если он не пуст,
выводиться в терминал.
:param album_id: ID альбома для загрузки.
:param files_path: Список путей к видео для загрузки.
:return: Функция ничего не возвращает.
"""
global TITLES
err = []
for nm, file in enumerate(files_path):
file_name = Path(file).name.split(Path(file).suffix)[0]
if file_name in TITLES:
continue
size = get_size(Path(file).stat().st_size)
print(f'{Fore.YELLOW}Загружаю видео: "{file_name}" | {nm + 1}/{len(files_path)} | {size}')
if video_file_upload(file, album_id):
print(f'{Fore.GREEN} [!] Видео: "{file_name}" загружено')
else:
print(f'{Fore.RED} [~] Видео: "{file_name}" не загружено\n')
err.append(str(file))
time.sleep(1)
if err:
print(f"\n{Fore.BLUE}[-] Не загруженные видео:")
for er in err:
print(f"{Fore.RESET} - {er}")
else:
print(f"\n{Fore.GREEN}{'-'*31}\n[!] Все видео успешно загружены\n{'-'*31}")
def video_file_upload(file: str, album_id: int) -> bool:
"""
:param file: Путь к файлу для загрузки.
:param album_id: ID альбома для загрузки.
:return: True, если загрузка прошла успешно и был получен размер видео.
И False, если загрузка окончилась неудачей.
"""
name = str(Path(file).name.split(Path(file).suffix)[0])
try:
upl = upload.video(video_file=file, name=name, album_id=album_id, privacy_view='only_me',
privacy_comment='only_me')
return True if upl.get('size') else False
except KeyboardInterrupt:
print("До свидания!")
sys.exit(0)
except Exception:
return False
def main() -> None:
"""
Запрос названия альбома и директории с видео для загрузки.
Проверка директории на существование.
Запуск функции получения названия альбомов пользователя.
Запуск функции создания альбома и получения его ID.
Запуск функции загрузки видео.
"""
path = input("Введите директорию для загрузки: ")
if not Path(path).exists() or not Path(path).is_dir() or not path:
print(f"{Fore.RED}[!] Проверьте правильность ввода директории")
sys.exit(0)
title = Path(path).name.strip()
if files_path := get_files_dir(path):
albums_name()
if album_id := album_create_id_get(title):
get_upload_url(album_id, files_path)
else:
print(f'{Fore.RED}[!] Не удалось создать альбом: "{title}".\n - Завершение работы')
sys.exit(0)
else:
print("Не найдено файлов для выгрузки")
sys.exit(0)
if __name__ == "__main__":
main()
А на этом, пожалуй, всё.
Спасибо за внимание. Надеюсь, данная информация будет вам полезна