You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从自有APP上传相册视频至YouTube(未列出)?求POST请求方案

Implementing YouTube Video Upload (Unlisted) from Your App

Got it, let's walk through exactly how to implement this—since you already have your OAuth token, the main piece is using YouTube's Resumable Upload flow (the standard for reliable video uploads, especially for larger files) with the YouTube Data API. Here's a step-by-step breakdown with example code:

1. First: Prepare Video Metadata

You need to send JSON metadata defining your video's title, description, and privacy status (set to unlisted). Here's what that looks like:

{
  "snippet": {
    "title": "My App Uploaded Video",
    "description": "This video was uploaded directly from my custom app!",
    "categoryId": "22" // Pick a category ID matching your content (22 = People & Blogs, adjust as needed)
  },
  "status": {
    "privacyStatus": "unlisted",
    "selfDeclaredMadeForKids": false // Set to true if your content is made for kids
  }
}

2. Initialize a Resumable Upload Session

First, send a POST request to YouTube's API to get a dedicated upload URL. This URL will be used to send your actual video file.

Example Code (Android with OkHttp)

OkHttpClient client = new OkHttpClient();

// Replace with your metadata JSON string
String metadataJson = "{\"snippet\":{\"title\":\"My App Uploaded Video\",\"description\":\"Uploaded from my app\",\"categoryId\":\"22\"},\"status\":{\"privacyStatus\":\"unlisted\",\"selfDeclaredMadeForKids\":false}}";

// Calculate your video file's size (replace with your actual file path)
File videoFile = new File("/path/to/your/selected/video.mp4");
long videoFileSize = videoFile.length();

Request initRequest = new Request.Builder()
    .url("https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status")
    .post(RequestBody.create(metadataJson, MediaType.parse("application/json")))
    .addHeader("Authorization", "Bearer " + YOUR_ACCESS_TOKEN) // Replace with your token
    .addHeader("Content-Type", "application/json; charset=UTF-8")
    .addHeader("X-Upload-Content-Type", "video/mp4") // Match your video's MIME type
    .addHeader("X-Upload-Content-Length", String.valueOf(videoFileSize))
    .build();

try (Response response = client.newCall(initRequest).execute()) {
    if (response.isSuccessful()) {
        // Extract the upload URL from the "Location" response header
        String uploadUrl = response.header("Location");
        // Save this URL—you'll need it for the next step
        uploadVideoFile(client, uploadUrl, videoFile);
    } else {
        // Handle errors (e.g., token expired, missing permissions)
        String errorDetails = response.body().string();
        Log.e("YouTubeUpload", "Failed to init session: " + errorDetails);
    }
} catch (IOException e) {
    e.printStackTrace();
}

3. Upload the Video File

Use the upload URL from step 2 to send a PUT request with your video file as the request body.

Example Upload Code (Android)

private void uploadVideoFile(OkHttpClient client, String uploadUrl, File videoFile) {
    RequestBody videoBody = RequestBody.create(videoFile, MediaType.parse("video/mp4"));

    Request uploadRequest = new Request.Builder()
        .url(uploadUrl)
        .put(videoBody)
        .addHeader("Content-Type", "video/mp4")
        .addHeader("Content-Length", String.valueOf(videoFile.length()))
        .build();

    try (Response uploadResponse = client.newCall(uploadRequest).execute()) {
        if (uploadResponse.isSuccessful()) {
            // Upload succeeded! The response body has your video's details (including videoId)
            String responseBody = uploadResponse.body().string();
            Log.d("YouTubeUpload", "Upload complete! Video data: " + responseBody);
            // Parse the response to get the videoId if you need it for future actions
        } else {
            String errorDetails = uploadResponse.body().string();
            Log.e("YouTubeUpload", "Upload failed: " + errorDetails);
            // If you get a 401 error, your token is expired—you'll need to refresh it
        }
    } catch (IOException e) {
        e.printStackTrace();
        // If the upload is interrupted (e.g., network drop), just re-run this method with the same uploadUrl
        // YouTube will automatically resume from where it left off
    }
}

4. Key Things to Remember

  • Permission Check: Make sure your OAuth token includes the https://www.googleapis.com/auth/youtube.upload scope. Without this, YouTube will reject your upload requests with a 403 error.
  • MIME Types: Double-check your video's MIME type (e.g., video/mp4 for MP4, video/quicktime for MOV). Using the wrong type can cause upload failures.
  • Resumable Uploads: If your upload gets interrupted (network issues, app backgrounded), just re-send the PUT request with the same upload URL—no need to re-initialize the session or re-upload the entire file.
  • Error Handling: Common issues include expired tokens (401), missing scopes (403), oversized files (YouTube's limit is 128GB or 12 hours, whichever is smaller), and unsupported video formats.

Bonus: iOS Example Snippet

If you're building for iOS, the flow is identical—here's a quick snippet using URLSession:

func initUploadSession(accessToken: String, videoFileURL: URL) {
    let metadata: [String: Any] = [
        "snippet": [
            "title": "My iOS App Upload",
            "description": "Uploaded from my iOS app",
            "categoryId": "22"
        ],
        "status": [
            "privacyStatus": "unlisted",
            "selfDeclaredMadeForKids": false
        ]
    ]
    
    guard let metadataData = try? JSONSerialization.data(withJSONObject: metadata) else {
        print("Failed to serialize metadata")
        return
    }
    
    let videoFileSize = try? FileManager.default.attributesOfItem(atPath: videoFileURL.path)[.size] as? Int64 ?? 0
    
    var request = URLRequest(url: URL(string: "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status")!)
    request.httpMethod = "POST"
    request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
    request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
    request.setValue("video/mp4", forHTTPHeaderField: "X-Upload-Content-Type")
    request.setValue(String(videoFileSize ?? 0), forHTTPHeaderField: "X-Upload-Content-Length")
    request.httpBody = metadataData
    
    URLSession.shared.dataTask(with: request) { data, response, error in
        guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200,
              let uploadUrl = httpResponse.allHeaderFields["Location"] as? String else {
            print("Session init failed: \(error?.localizedDescription ?? "Unknown error")")
            return
        }
        self.uploadVideo(to: uploadUrl, videoFileURL: videoFileURL)
    }.resume()
}

func uploadVideo(to uploadUrl: String, videoFileURL: URL) {
    var request = URLRequest(url: URL(string: uploadUrl)!)
    request.httpMethod = "PUT"
    request.setValue("video/mp4", forHTTPHeaderField: "Content-Type")
    
    URLSession.shared.uploadTask(with: request, fromFile: videoFileURL) { data, response, error in
        guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
            print("Upload failed: \(error?.localizedDescription ?? "Unknown error")")
            return
        }
        if let data = data, let responseStr = String(data: data, encoding: .utf8) {
            print("Upload success! Response: \(responseStr)")
        }
    }.resume()
}

内容的提问来源于stack exchange,提问作者podgradle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:17:59