Skip to content

Video & Image uploads #13

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;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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