以编程方式从Android设备上传视频到youtube

时间:2011-06-30 06:55:32

标签: android upload youtube

我试图这样做(来自here的想法):

        Entry entry = new Entry();
        entry.group = new MediaGroup();
        entry.group.title = "test title";
        entry.group.description = "test description";
        entry.group.category = new MediaCategory();
        entry.group.category.Cat = "People\n";

        AtomContent aContent = new AtomContent();
        aContent.entry = entry;
        aContent.namespaceDictionary = NAMESPACE_DICTIONARY;

        Uri uri = Uri.parse(r.uri);
        File file = new File(r.text);
        FileContent bContent = new FileContent(file);
        //  bContent.inputStream = new FileInputStream(r.text);//context.getContentResolver().openInputStream(uri);
        Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
        cursor.moveToFirst();
        bContent.type = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.MIME_TYPE));
        //bContent.length = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE));
        String fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME));

        // Build up the POST request
        MultipartRelatedContent multiContent = new MultipartRelatedContent();
        multiContent.parts.add(aContent);
        multiContent.parts.add(bContent);

        HttpTransport transport = new ApacheHttpTransport();

        HttpRequestFactory requestFactory = transport.createRequestFactory();
        // !
        HttpRequest request = requestFactory.buildPostRequest(YouTubeUrl.uploadUrl(), multiContent);
        GoogleHeaders headers = new GoogleHeaders();
        headers.putAll(request.headers);
        request.headers = headers;
        headers.setSlugFromFileName(fileName);
        headers.setDeveloperId(Consts.youtubeDevKey);
        headers.setGoogleLogin(accountInfo.password);
        // !
        request.headers.contentType = multiContent.getType();
        //  request.headers.contentType = bContent.getType();

        request.connectTimeout = 0;
        request.readTimeout = 0;

        HttpResponse response = request.execute();
        String strResponse = NetworkHelper.readResponse(response.getContent());

使用NetHttpTransport我得到“系统调用期间的I / O错误,断管”

//使用ApacheHttpTransport我得到“org.apache.http.client.NonRepeatableRequestException:无法在5-20秒内使用不可重复的请求实体重试请求”。 PS。我们发现ApacheHttpTransport内部异常也是“Broken Pipe”

我正在尝试使用google-api-client 1.4.1在运行Android 2.3.3的设备上进行此操作

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

http://code.google.com/p/google-api-java-client/issues/attachmentText?id=16&aid=160010000&name=YoutubeService.java&token=aad2f75b58d905ffb4e8e916266904de找到解决方案。

android的工作代码:

import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.http.MultipartRelatedContent;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.http.xml.atom.AtomContent;
import com.google.api.client.util.Key;
import com.google.api.client.xml.XmlNamespaceDictionary;

....

public static final XmlNamespaceDictionary NAMESPACE_DICTIONARY = new XmlNamespaceDictionary();
    static
    {
        NAMESPACE_DICTIONARY.set("", "http://www.w3.org/2005/Atom")
            .set("atom", "http://www.w3.org/2005/Atom")
            .set("exif", "http://schemas.google.com/photos/exif/2007")
            .set("gd", "http://schemas.google.com/g/2005")
            .set("geo", "http://www.w3.org/2003/01/geo/wgs84_pos#")
            .set("georss", "http://www.georss.org/georss")
            .set("gml", "http://www.opengis.net/gml")
            .set("gphoto", "http://schemas.google.com/photos/2007")
            .set("media", "http://search.yahoo.com/mrss/")
            .set("openSearch", "http://a9.com/-/spec/opensearch/1.1/")
            .set("xml", "http://www.w3.org/XML/1998/namespace");
    }

    /**
     * Represents an Atom formatted upload request for YouTube
     * 
     * @see http 
     *      ://code.google.com/intl/en/apis/youtube/2.0/developers_guide_protocol_direct_uploading.html#Sending_a_Direct_Upload_API_Request
     * 
     *      <entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"
     *      xmlns:yt="http://gdata.youtube.com/schemas/2007"> <media:group> <media:title type="plain">Bad Wedding Toast</media:title>
     *      <media:description type="plain"> I gave a bad toast at my friend's wedding. </media:description> <media:category
     *      scheme="http://gdata.youtube.com/schemas/2007/categories.cat">People </media:category> <media:keywords>toast,
     *      wedding</media:keywords> </media:group> </entry>
     * @author fhackenberger
     */
    public static class UploadEntry
    {
        @Key("media:group")
        MediaGroup group = new MediaGroup();
    }

    /**
     * @see UploadEntry
     * @author fhackenberger
     */
    public static class MediaGroup
    {
        @Key("media:title")
        MediaAttribute title = new MediaAttribute();
        @Key("media:description")
        MediaAttribute description = new MediaAttribute();
        @Key("media:category")
        MediaCategory category = new MediaCategory();
        @Key("media:keywords")
        String keywords;
    }

    /**
     * @see UploadEntry
     * @author fhackenberger
     */
    public static class MediaAttribute
    {
        @Key("@type")
        String type = "plain";
        @Key("text()")
        String value;
    }

    /**
     * @see UploadEntry
     * @author fhackenberger
     */
    public static class MediaCategory
    {
        @Key("@scheme")
        String scheme = "http://gdata.youtube.com/schemas/2007/categories.cat";
        @Key("text()")
        String category;
    }

    /**
     * Represents an error response from Youtube
     * 
     * @see http://code.google.com/intl/en/apis/youtube/2.0/developers_guide_protocol_error_responses.html <errors> <error>
     *      <domain>yt:validation</domain> <code>invalid_value</code> <location
     *      type='xpath'>media:group/media:category[@scheme='http://gdata.youtube.com/schemas/2007/categories.cat']/text() </location>
     *      </error> </errors>
     * @author fhackenberger
     * 
     */
    public static class YoutubeErrors
    {
        @Key("error")
        List<YoutubeError> errors;
    }

    /**
     * @see YoutubeErrors
     * @author fhackenberger
     */
    public static class YoutubeError
    {
        @Key
        String domain;
        @Key
        String code;
        @Key
        YoutubeErrorLocation location;

        @Override
        public String toString()
        {
            return "domain: " + domain + "; code: " + code + "; location: (" + location + ")";
        }
    }

    /**
     * @see YoutubeError
     * @author fhackenberger
     */
    public static class YoutubeErrorLocation
    {
        @Key("@type")
        String type;
        @Key("text()")
        String location;

        @Override
        public String toString()
        {
            return "type: " + type + "; location: " + location;
        }
    }

    /**
     * Represents a YouTube video feed
     * 
     * @see http://code.google.com/intl/en/apis/youtube/2.0/developers_guide_protocol_understanding_video_feeds.html
     * @author fhackenberger
     */
    public static class VideoFeed
    {
        @Key
        List<Video> items;

        @Override
        public String toString()
        {
            return "Items: " + items;
        }
    }

    /**
     * A single video entry
     * 
     * @see VideoFeed
     * @author fhackenberger
     */
    public static class Video
    {
        @Key
        String id;
        @Key
        String title;
        @Key
        String description;
        @Key
        Player player;
        @Key("link")
        List<Link> links;

        @Override
        public String toString()
        {
            return "Id: " + id + " Title: " + title + " Description: " + description + " Player: " + player + " Links: " + links;
        }
    }

    /**
     * A related link for a {@link Video}
     * 
     * @see VideoFeed
     * @author fhackenberger
     */
    public static class Link
    {
        @Key("@rel")
        String rel;
        @Key("@href")
        String href;
        @Key("@type")
        String type;

        @Override
        public String toString()
        {
            return href;
        }
    }

    /**
     * The URL for the YouTube video player for a {@link Video}
     * 
     * @see VideoFeed
     * @author fhackenberger
     */
    public static class Player
    {
        @Key("default")
        String defaultUrl;

        @Override
        public String toString()
        {
            return "DefaultURL: " + defaultUrl;
        }
    }

    public YouTubeUploader(Context context, AccountInfo accountInfo)
    {
        this.context = context;
        this.accountInfo = accountInfo;
    }

    @Override
    public void upload(Record r)
    {
        HttpRequest request = null;
        try
        {
            HttpTransport transport = new NetHttpTransport();
            HttpRequestFactory requestFactory = transport.createRequestFactory();
            request = requestFactory.buildPostRequest(YouTubeUrl.uploadUrl(), null);

            File file = new File(fileName);
            InputStreamContent videoContent = new InputStreamContent();
            videoContent.inputStream = new FileInputStream(file);
            videoContent.type = "application/octet-stream";

            // Describes the video
            AtomContent atomContent = new AtomContent();
            atomContent.namespaceDictionary = NAMESPACE_DICTIONARY;
            UploadEntry uploadEntry = new UploadEntry();
            uploadEntry.group.title.value = videoTitle;
            uploadEntry.group.description.value = "";
            uploadEntry.group.category.category = "People\n";
            uploadEntry.group.keywords = "";
            atomContent.entry = uploadEntry;

            MultipartRelatedContent multiPartContent = MultipartRelatedContent.forRequest(request);
            multiPartContent.parts.add(atomContent);
            multiPartContent.parts.add(videoContent);

            request.content = multiPartContent;

            GoogleHeaders headers = new GoogleHeaders();
            headers.setApplicationName(Consts.youtubeAppName);
            headers.acceptEncoding = "gzip";
            headers.mimeVersion = "1.0";
            headers.gdataVersion = "2";
            headers.setDeveloperId(Consts.youtubeDevKey);
            headers.setGoogleLogin(accountInfo.token);
            headers.slug = GoogleHeaders.SLUG_ESCAPER.escape(videoTitle);

            request.headers = headers;
            request.unsuccessfulResponseHandler = new YoutubeUnsuccessfulResponseHandler();

            // HttpParser parser = new AtomParser();
            // ((AtomParser)parser).namespaceDictionary = NAMESPACE_DICTIONARY;
            // request.addParser(parser);

            HttpResponse response = request.execute();
            String responseStr = NetworkHelper.readResponse(response.getContent());
            videoUrl = getContentLink(responseStr);
        }
        catch (HttpResponseException e)
        {
            YoutubeError error = ((YoutubeUnsuccessfulResponseHandler) request.unsuccessfulResponseHandler).errors.errors.get(0);
            errorMessage = error + "";
        }
        catch (IOException e)
        {
            errorMessage = e.getMessage();
        }
    }

    class YoutubeUnsuccessfulResponseHandler implements
        HttpUnsuccessfulResponseHandler
    {
        YoutubeErrors errors = null;

        @Override
        public boolean handleResponse(HttpRequest request, HttpResponse response, boolean retrySupported) throws IOException
        {
            errors = response.parseAs(YoutubeErrors.class);
            return false;
        }
    }


public class YouTubeUrl extends GoogleUrl
{
    private static final boolean PRETTY_PRINT = true;

    private static final String UPLOAD_URL = "https://uploads.gdata.youtube.com/feeds/api/users/default/uploads";

    @Key
    String author;

    @Key("max-results")
    Integer maxResults = 2;

    YouTubeUrl(String encodedUrl, boolean json)
    {
        super(encodedUrl);
        if (json)
            this.alt = "jsonc";
        this.prettyprint = PRETTY_PRINT;
    }

    public static GenericUrl uploadUrl()
    {
        return new YouTubeUrl(UPLOAD_URL, false);
    }
}