В процессе работы с Youtube, через ихний API v3, упёрся я в загрузку видео.
Я принципиально не юзаю их родные библиотеки для питона, потому что считаю их уродливыми.
Справедливо считаю, что раз API у них типа REST, с примесями JSON, то для работы мне вполне хватит классического python-requests. И вполне хватает, что характерно.
Интересное случилось на пункте videos/insert (загрузка видео).
Как правило, во всех примерах в документации есть пример для cURL. Кривой, но дающий представление, что интернет жив, протоколы соблюдаются, а для работы вполне себе хватит тривиальных утилит.
Но нет, для videos/insert про cURL сказано, цитирую,
curl samples are currently only supported for GET requests.
Вау. cURL неспособен к чему-то большему, чем GET? Чё-то новое в интернетах.
Пошел разбираться.
Влоб, как и ожидалось, ничего не работает. Самое вменяемое, что возвращает google при аплоаде файлов - "Entity too large".
Пришлось лазить в потроха googleapiclient.
Оказалось, что загрузка файлов делается в два присеста.
Присест первый - шлём метаданные видео и ждём адрес, куда лить само видео:
curl -i -X POST '
https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&alt=json&part=status%2Csnippet' --data-binary '{"status": {"privacyStatus": "private"}, "snippet": {"tags": null, "categoryId": "22", "description": "Test Description", "title": "Test Title"}}' -H "Authorization: Bearer %классический-токен" -H "content-length: 145" -H "accept-encoding: gzip, deflate" -H "accept: application/json" -H "X-Upload-Content-Length: <размер, чё мы будем потом аплоадить>" -H "X-Upload-Content-Type: <тип будущего файла>" -H "content-type: application/json"
Ответ гугля оооочень интересный:
HTTP/1.1 200 OK
X-GUploader-UploadID: AEnB2UrPv3elzZh0lab4kESHKQNblablablav_tWGa8ly_-pY4nDgyfpUDyGx7kFRRqhrcqdZjjrCdECKyvwnHqw
Location:
https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&alt=json&part=status%2Csnippet&upload_id=AEnB2UrPv3elzZh0lab4kESHKQNblablablav_tWGa8ly_-pY4nDgyfpUDyGx7kFRRqhrcqdZjjrCdECKyvwnHqwETag: "XI7nbFXulYBIbububuR_gDh3eu1k/TObjzCHMsvnC6T38palOVn6VX7c"
Vary: Origin
Vary: X-Origin
X-Goog-Correlation-Id: JRwDbebe3zi0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Date: Tue, 30 Oct 2018 17:07:02 GMT
Content-Length: 0
Server: UploadServer
Content-Type: text/html; charset=UTF-8
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
Что мы видим:
1. Гугль возвращает урл, куда надо сделать PUT-запрос. PUT-запрос делается без приключений - просто PUT, content-type, content-length. Детали тут -
https://developers.google.com/drive/api/v3/manage-uploads (google-drive api, дада, а не youtube api)
2. Гугль возвращает урл, куда надо делать PUT-запрос в хедере, а не в теле ответа. Название поля - Location.
3. Нет, у нас не редирект, как показалось по полю Location, а вполне себе "HTTP/1.1 200 OK"
Как бы, я допускаю, что загружать BLOB'ы и метаданные можно на разные адреса, поэтому, типа, урл для загрузки получаем отдельным запросом. Но, как видно, адрес у нас один и тот же. Смысл тогда в этих манипуляциях? Ну и какого хера там данные отдаются так криво? Вроде редирект (судя по Location), но нифига не редирект, ни по статус-коду, ни по логике процесса.
Гугль, блин! Протоколы писаны и для вас тоже! Блюдите их, мать вашу.