Загрузка видео в s3

Рекомендации по работе с объектным хранилищем S3 для загрузки видеофайлов цифрового следа

S3 (Simple Storage Service) — это протокол доступа к объектному хранилищу, который позволяет хранить и извлекать данные. В нашем случае хранилище используется для размещения видеофайлов, чтобы в дальнейшем передавать ссылки на них в составе xAPI стейтментов цифрового следа.

Для отправки артефактов (в частности, видеофайлов онлайн-трансляций) используется объектное хранилище CLOUD4Y. Объектное хранилище поддерживает протокол доступа Amazon S3 API. В объектном хранилище данные хранятся без иерархии (каждый объект расположен в пуле данных на одном уровне). Доступ к данным возможен через API.

Доступ к s3 предоставляется вместе с доступом к LRS. Если вы получали доступ к LRS ранее, доступ к s3 можно запросить отдельно.

По запросу на доступ к LRS мы также выдаем доступ к хранилищу S3, если его нет — запросите отдельно на apps@2035.university, указав:
1) Полное название проекта
2) Полное название вашей организации

Вам будет предоставлен логин и пароль. Их необходимо использовать для авторизации в личном кабинете веб-версии по ссылке: https://cmc.objstor.cloud4u.com:8443/Cloudian/
Group Name:
Password:

А также User ID, Access Key ID, Secret Key - эти данные необходимы для загрузки файлов на S3-хранилище. Для отправки по API необходимо использовать эндпоинт: https://s3.objstor.cloud4u.com
User ID: -ИМЯ БАКЕТА-
Access Key ID:
Secret Key:


Способ загрузки видео в s3

Ниже представлен рабочий скрипт на Python с использованием библиотеки boto3. Он загружает файл в указанный бакет с правами доступа private.
Необходимо расположить скрипт с расширением .py в той же папке, где будут находится видео на загрузку.

Редактируемые строки:

При использовании скрипта вам нужно заменить четыре параметра:
1. video_file = указать имя вашего локального видеофайла
2. bucket_name = User ID, указать имя вашего бакета в хранилище
3. aws_access_key_id = Access Key ID, ключ доступа, полученный на apps@2035.university.
4. aws_secret_access_key = Secret Key, ключ доступа, полученный на apps@2035.university.

Остальные строки (конфигурация клиента, endpoint, метод загрузки) изменять не требуется.

Важно! Нельзя создавать сложную структуру хранения. S3 это объектное хранилище, а не файловое. Для организации хранения допустимо создание папок, но недопустимо создание подпапок. Вы можете определить количество папок самостоятельно: равное количеству модулей, по месяцам, др.

Скрипт для загрузки видео:

import sys
import boto3
<<span class="speller-hint" data-toggle="popover" data-hint="4" data-original-title="" title="">span</span> class="<span class="speller-hint" data-toggle="popover" data-hint="5" data-original-title="" title="">speller</span>-hint" data-toggle="popover" data-hint="3" data-original-title="" title="">import</span> urllib3
from botocore.client import Config
from <span class="speller-hint" data-toggle="popover" data-hint="4" data-original-title="" title="">botocore</span>.exceptions import <span class="speller-hint" data-toggle="popover" data-hint="5" data-original-title="" title="">ClientError</span>
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def simple_indicator(bytes_amount):
    sys.stdout.write(".")
    sys.stdout.flush()
def upload_file_with_acl(filename, bucket, object_name=None, acl="private"):
    if object_name is None:
        object_name = filename
    s3_config = Config(signature_version="s3", s3={"addressing_style": "path"})
    s3_client = boto3.client(
        "s3",
        endpoint_url="https://s3.objstor.cloud4u.com",
        region_name="k41",
        aws_access_key_id="-ВАШ Access Key ID- ",
        aws_secret_access_key="-ВАШ Secret Key-",
        verify=False,
        config=s3_config,
    )
    try:
        print(f"Загрузка файла {filename} в бакет {bucket}", end="")
        s3_client.upload_file(
            filename,
            bucket,
            object_name,
            ExtraArgs={"ACL": acl},
            Callback=simple_indicator,
        )
        print(f"загрузка завершена")
    <span class="speller-hint" data-toggle="popover" data-hint="6" data-original-title="" title="">except</span> <span class="speller-hint" data-toggle="popover" data-hint="7" data-original-title="" title="">ClientError</span> <span class="speller-hint" data-toggle="popover" data-hint="8" data-original-title="" title="">as e</span>:
        print(f"Error: {e}")
        return False
    try:
        head = s3_client.head_object(Bucket=bucket_name, Key=filename)
        utc_time = head["LastModified"]
        local_time = utc_time.astimezone()
        print(f"Проверка:")
        print(f"Файл '{filename}' есть в бакете '{bucket}'")
        <span class="speller-hint" data-toggle="popover" data-hint="9" data-original-title="" title="">print</span>(f"Размер: {head['<span class="speller-hint" data-toggle="popover" data-hint="10" data-original-title="" title="">ContentLength</span>']} байт")
        print(f"Дата: {local_time.strftime('%d.%m.%Y %H:%M:%S')}")
        return True
    <span class="speller-hint" data-toggle="popover" data-hint="11" data-original-title="" title="">except</span> <span class="speller-hint" data-toggle="popover" data-hint="12" data-original-title="" title="">ClientError</span> <span class="speller-hint" data-toggle="popover" data-hint="13" data-original-title="" title="">as e</span>:
        error_code = e.response["Error"]["Code"]
        if error_code == "404":
            print(f"Файл {filename} не найден в {bucket}/{object_name}")
            return False
        elif error_code == "403":
            print(f"Доступ к файлу {object_name} запрещен (403 Forbidden).")
            return False
        else:
            print(f"Ошибка при проверке файла: {e}")
            return False
video_file = "ИМЯ ВАШЕГО ФАЙЛА В ФОРМАТЕ .mp4"  
bucket_name = "User ID -ИМЯ ВАШЕГО <span class="speller-hint" data-toggle="popover" data-hint="14" data-original-title="" title="">БАКЕТА</span>-"  
upload_file_with_acl(video_file, bucket_name)

Формирование ссылки на конкретное, положенное в s3, видео

После успешной загрузки файла, ссылка на него формируется по следующему шаблону:

Ссылка на видео:

https://s3.objstor.cloud4u.com/ИМЯ БАКЕТА (User ID)/НАЗВАНИЕ ВИДЕО.mp4 
Максимальное усложнение: 
https://s3.objstor.cloud4u.com/ИМЯ БАКЕТА (User ID)/НАЗВАНИЕ ПАПКИ/НАЗВАНИЕ ВИДЕО.mp4 
Недопустимая ссылка: 
https://s3.objstor.cloud4u.com/ИМЯ БАКЕТА (User ID)/НАЗВАНИЕ ПАПКИ/НАЗВАНИЕ ПАПКИ/НАЗВАНИЕ ПАПКИ/НАЗВАНИЕ ВИДЕО.mp4


Прикрепление ссылки на видеоматериал в шаблон "ЦС_Получателя_поддержки_просмотр_видеоконтента"

Шаблон: https://www.postman.com/gold-comet-924936/cs-kb/request/hfcjunp/

Ссылка на видео вставляется в цифровой след, в блок attachments.

Ссылка на объект в S3 пишется в поле fileUrl. Это обязательное условие для корректной обработки xAPI стейтмента.

Пример заполненного блока attachments:

"attachments": [
    {
        "usageType": "http://id.tincanapi.com/attachment/supporting_media",
        "display": {
            "ru-RU": "Записанная онлайн трансляция"
        },
        "description": {
            "ru-RU": "Ссылка на запись онлайн трансляции"
        },
        "contentType": "text/html",
        "length": 123456,
        "fileUrl": "https://s3.objstor.cloud4u.com/ИМЯБАКЕТА(User ID)/НАЗВАНИЕ_ВИДЕО.mp4", 
        "sha2": "a914802032ce28709ccf566d33cb4c5460a3976a16dcd7e4beb5bfb68191020e"
    }
]


Вопросы и ответы

Вопрос: Как проверить, что видео точно лежит в S3 и доступно?
1) Перейдите в web-версию хранилища с помощью логина и пароля, которые вы получили вместе с ключами: https://cmc.objstor.cloud4u.com:8443/Cloudian/
Затем воспользуйтесь поиском по бакету. Если видео было расположено в папку, в поиске нужно указать путь: ПАПКА/НАЗВАНИЕ ВИДЕО, формат видео для поиска не нужен.
2) Используйте следующий скрипт для программной проверки наличия файла в бакете.

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

import boto3
from botocore.client import Config
<span class="speller-hint" data-toggle="popover" data-hint="20" data-original-title="" title="">import</span> urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def check_file_in_bucket(filename, bucket):
    s3_config = Config(
        signature_version='s3',
        s3={'addressing_style': 'path'}
    )
    s3_client = boto3.client(
        's3',
        endpoint_url='https://s3.objstor.cloud4u.com',
        region_name='k41',
        aws_access_key_id='-ВАШ Access Key ID-  ',
        aws_secret_access_key=''ВАШ Secret Key-',
        verify=False,
        config=Config(signature_version='s3v4')
    )
    try:
        response = s3_client.list_objects_v2(Bucket=bucket)
        if 'Contents' in response:
            for obj in response['Contents']:
                if obj['Key'] == filename:
                    print(f" Файл '{filename}' найден в бакете '{bucket}'")
                    print(f"  Размер: {obj['Size']} байт")
                    print(f"  Дата: {obj['LastModified']}")
                    return True
        print(f"✗ Файл '{filename}' не найден в бакете '{bucket}'")
        return False
    except Exception as e:
        print(f"Ошибка: {e}")
        return False
check_file_in_bucket('ИМЯ ВАШЕГО ФАЙЛА В ФОРМАТЕ .mp4', 'ИМЯ ВАШЕГО БАКЕТА')

Вопрос: Что проверить, если видео грузится медленно?

Ответ: В первую очередь необходимо проверить скорость интернет-соединения на стороне того, кто выполняет загрузку.

Рекомендуется:

  1. Использовать проводное подключение вместо Wi-Fi для большей стабильности, а также проверьте, что в вашем регионе временно не снижается скорость
  2. Временно отключить другие программы и устройства, которые могут потреблять много трафика.
  3. Проверить скорость на speed-test сервисах. Если скорость исходящего соединения низкая, проблема на вашей стороне.

Вопрос: Какая скорость загрузки считается приемлемой?

Ответ: Приемлемой считается скорость, позволяющая загрузить файл за время, не превышающее длительность видео более чем в 1.5-2,5 раза. Для файла размером 1 Гб (примерно 1 час видео в среднем качестве) при скорости интернета 10 Мбит/с загрузка займет около 12-20 минут, что является нормальным показателем. Ориентируйтесь на стабильность соединения и разумное время ожидания.