Skip to content

Video & Image uploads #13

@shevernitskiy

Description

@shevernitskiy

Thanks for you api investigation!
I'd like to share video & image uploading methods. It's in typescript, but i suppose you can understand it and adopt into your lib.

Main client methods, request is the main call method with auth headers etc.

async request<T>(method: string, endpoint: string, data?: any): Promise<T> {
  await this.auth();

  const res = await fetch(`https://api.boosty.to${endpoint}`, {
    method,
    headers: this.headers,
    body: data,
  });

  if (!res.ok) {
    throw new Error(`Request failed with status ${res.status} ${res.body ? await res.text() : ""}`);
  }

  return (await res.json()) as T;
}

async uploadImage(file: string): Promise<ImageUpload> {
  let type = "image/jpeg";
  if (file.endsWith(".png")) type = "image/png";
  if (file.endsWith(".webp")) type = "image/webp";
  if (file.endsWith(".gif")) type = "image/gif";
  if (file.endsWith(".jpeg")) type = "image/jpeg";

  const file_data = new File([Deno.readFileSync(file)], basename(file), { type });
  const res = await fetch("https://uploadimg.boosty.to/v1/media_data/image/", {
    method: "POST",
    headers: this.headers,
    body: file_data,
  });

  if (!res.ok) {
    throw new Error(`Image upload failed with status ${res.status} ${res.body ? await res.text() : ""}`);
  }

  const data = await res.json();
  return data;
}

getVideoUploadUrl(file_name: string): Promise<VideoUploadUrl> {
  return this.request("GET", `/v1/media_data/video/upload_url?${new URLSearchParams({ file_name })}`);
}

videoUploadFinish(video_id: string): Promise<VideoUploadFinish> {
  return this.request("POST", `/v1/media_data/video/${video_id}/finish`);
}

async uploadVideo(file: string, preview_file?: string, onProgress?: (progress: number) => void): Promise<Video> {
  const upload_url = await this.getVideoUploadUrl(basename(file));
  const file_size = await uploader(file, upload_url.uploadUrl, onProgress);
  const upload_finish = await this.videoUploadFinish(upload_url.id);

  const image = { } as any;
  if (preview_file) {
    const image_upload = await this.uploadImage(preview_file);
    image.preview = image_upload.url;
    image.previewId = image_upload.id;
  }

  return {
    complete: upload_finish.complete,
    id: upload_url.id,
    size: file_size,
    title: "Video",
    type: "ok_video",
    url: "",
    vid: upload_url.videoId,
    playerUrls: [],
    ...image,
    duration: upload_finish.duration,
    timeCode: 0,
    viewsCounter: 0,
    uploadStatus: "ok",
    showViewsCounter: true,
  };

And uploader method to upload to OK cdn

// 1024 * 1024
const CHUNK_SIZE = 1048576;

export async function uploader(file: string, url: string, onProgress?: (progress: number) => void): Promise<number> {
  const file_size = Deno.statSync(file).size;
  const file_name = basename(file);
  const handle = Deno.openSync(file, { read: true });

  let cur = 0;

  while (true) {
    const range = [cur, Math.min(file_size, cur + CHUNK_SIZE)];

    await handle.seek(range[0], Deno.SeekMode.Start);
    const buf = new Uint8Array(CHUNK_SIZE);
    await handle.read(buf);

    const headers = {
      "Content-Disposition": `attachment; filename=${file_name}`,
      "Content-Length": `${range[1] - range[0]}`,
      "Content-Range": `bytes ${range[0]}-${range[1] - 1}/${file_size}`,
      "Content-Type": "application/octet-stream",
      "Origin": "https://boosty.to",
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
      "X-Uploading-Mode": "parallel",
    };

    const res = await fetch(url, {
      method: "POST",
      headers,
      body: buf,
    });

    if (!res.ok) {
      throw new Error(`Upload failed with status ${res.status} ${res.body ? await res.text() : ""}`);
    }

    if (onProgress) {
      onProgress(Math.round((cur * 100) / file_size) / 100);
    }

    cur = range[1];
    if (range[1] >= file_size - 1) {
      break;
    }
  }

  return file_size;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions