saveapi.org

Скачивание видео из соцсетей на Go

Клиент на Go — запрос с одним заголовком и типизированный decode. Руководство добавляет дисциплину вокруг: дедлайн через context, чтобы медленный источник не повесил горутину, структуру, которая делает код ошибки полем, а не поиском по строке, и потоковую запись файла через io.Copy вместо чтения в память.

Обновлено

Сначала типы

Структура с Success, Medias и указателем Error делает код ошибки полем, а не поиском по строке. Держите тип локальным и маленьким — новое необязательное поле в ответе не сломает decode, который его игнорирует.

Go
type Media struct {
	Type string `json:"type"`
	URL  string `json:"url"`
}

type Resolved struct {
	Success bool    `json:"success"`
	Medias  []Media `json:"medias"`
	Error   *struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"error"`
}

Запрос

http.NewRequestWithContext несёт дедлайн; url.QueryEscape кодирует ссылку. Один заголовок, один decode. Больше ничего с вашей стороны — ни cookie, ни сессии, ни браузера.

Go
func resolve(ctx context.Context, link string) (*Resolved, error) {
	u := "https://api.saveapi.org/v1/download?url=" + url.QueryEscape(link)
	req, _ := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
	req.Header.Set("Authorization", "Bearer sk_live_xxxx")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var out Resolved
	return &out, json.NewDecoder(res.Body).Decode(&out)
}

Пишите файл через io.Copy

URL медиа указывает прямо на CDN платформы. io.Copy из тела ответа в файл держит память ровной при любом размере; API никогда не проксирует байты.

Go
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

data, err := resolve(ctx, "https://www.instagram.com/reel/ABC123/")
if err != nil || !data.Success {
	log.Fatal(err, data.Error.Code)
}

res, _ := http.Get(data.Medias[0].URL)   // to'g'ridan-to'g'ri CDN
defer res.Body.Close()
f, _ := os.Create("video.mp4")
defer f.Close()
io.Copy(f, res.Body)                      // oqim, xotiraga emas

Повторяйте только то, что повтор исправляет

UPSTREAM_TIMEOUT и UPSTREAM_ERROR заслуживают второй попытки и ничего не стоят. PRIVATE_CONTENT и MEDIA_NOT_FOUND финальны и стоят 0.1 кредита каждый раз — цикл повторов на них лишь тратит кредиты на тот же ответ. Держите набор повторяемых в одном месте.

Читайте заголовки, которые уже есть

Каждый ответ несёт X-RateLimit-Limit, X-RateLimit-Remaining и на платных ключах X-Credits-Remaining. Этого достаточно, чтобы притормозить до троттлинга без отдельного запроса баланса.

Вопросы перед началом

Есть официальный Go SDK?
Нет. Типизированная структура и запрос из этого руководства и есть SDK; пакет добавил бы зависимость ради восьми строк.
Как обрабатывать formats[]?
Добавьте поле Formats []Format в структуру для VK и Rutube; на других платформах поле просто отсутствует и остаётся пустым.
Можно разрешать много ссылок параллельно?
Да, в пределах поминутного лимита ключа. Семафор размером с лимит и заголовок X-RateLimit-Remaining уберегут от троттлинга.

Платформы, использованные здесь

Другие руководства

Запустите это руководство со своим ключом

Ключ за минуту. 1 000 бесплатных кредитов, без карты и без срока.

Получить ключ и попробоватьПолный справочник API