001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *      Nelson Silva
018 */
019
020package org.nuxeo.ecm.media.publishing.youtube;
021
022import com.google.api.client.auth.oauth2.Credential;
023import com.google.api.client.googleapis.media.MediaHttpUploader;
024import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener;
025import com.google.api.services.youtube.model.Video;
026import com.google.api.services.youtube.model.VideoListResponse;
027import com.google.api.services.youtube.model.VideoSnippet;
028import com.google.api.services.youtube.model.VideoStatistics;
029import com.google.api.services.youtube.model.VideoStatus;
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.nuxeo.ecm.core.api.Blob;
033import org.nuxeo.ecm.media.publishing.OAuth2MediaPublishingProvider;
034import org.nuxeo.ecm.media.publishing.adapter.PublishableMedia;
035import org.nuxeo.ecm.media.publishing.upload.MediaPublishingProgressListener;
036
037import java.io.IOException;
038import java.util.ArrayList;
039import java.util.Arrays;
040import java.util.Collections;
041import java.util.HashMap;
042import java.util.List;
043import java.util.Map;
044
045/**
046 * Youtube Media Publishing Provider Service
047 *
048 * @since 7.3
049 */
050public class YouTubeService extends OAuth2MediaPublishingProvider {
051    private static final Log log = LogFactory.getLog(YouTubeService.class);
052
053    public static final String PROVIDER = "YouTube";
054
055    public YouTubeService() {
056        super(PROVIDER);
057    }
058
059    public YouTubeClient getYouTubeClient(String account) {
060        Credential credential = getCredential(account);
061        return (credential != null && credential.getAccessToken() != null) ? new YouTubeClient(credential) : null;
062    }
063
064    @Override
065    public String upload(PublishableMedia media, MediaPublishingProgressListener progressListener, String account, Map<String, String> options) throws IOException {
066
067        MediaHttpUploaderProgressListener mediaUploaderListener = new MediaHttpUploaderProgressListener() {
068            @Override
069            public void progressChanged(MediaHttpUploader uploader) throws IOException {
070                switch (uploader.getUploadState()) {
071                case INITIATION_STARTED:
072                case INITIATION_COMPLETE:
073                    progressListener.onStart();
074                    break;
075                case MEDIA_IN_PROGRESS:
076                    progressListener.onProgress(uploader.getProgress());
077                    break;
078                case MEDIA_COMPLETE:
079                    progressListener.onComplete();
080                    break;
081                case NOT_STARTED:
082                    log.info("Upload Not Started!");
083                    break;
084                }
085            }
086        };
087
088        Video youtubeVideo = new Video();
089
090        VideoStatus status = new VideoStatus();
091        String privacyStatus = options.get("privacyStatus");
092        if (privacyStatus != null) {
093            status.setPrivacyStatus(privacyStatus);
094        } else {
095            status.setPrivacyStatus("unlisted");
096        }
097        youtubeVideo.setStatus(status);
098
099        VideoSnippet snippet = new VideoSnippet();
100        snippet.setTitle(media.getTitle());
101        snippet.setDescription(media.getDescription());
102
103        List<String> tags = new ArrayList<>();
104        String inputTags = options.get("tags");
105        if (inputTags != null) {
106            tags.addAll(Arrays.asList(inputTags.split("\\s*,\\s*")));
107        }
108        snippet.setTags(tags);
109
110        youtubeVideo.setSnippet(snippet);
111
112        // upload original video
113        Blob blob = media.getBlob();
114
115        String mimeType = blob.getMimeType();
116        long length = blob.getLength();
117        youtubeVideo = getYouTubeClient(account).upload(youtubeVideo, blob.getStream(), mimeType, length, mediaUploaderListener);
118
119        return youtubeVideo.getId();
120    }
121
122    @Override
123    public boolean unpublish(PublishableMedia media) throws IOException {
124        String account = media.getAccount(PROVIDER);
125        String mediaId = media.getId(PROVIDER);
126        return getYouTubeClient(account).delete(mediaId);
127    }
128
129    @Override
130    public String getPublishedUrl(String mediaId, String account) {
131        return "https://www.youtube.com/watch?v=" + mediaId;
132    }
133
134    @Override
135    public String getEmbedCode(String mediaId, String account) {
136        return (mediaId == null) ? null : "https://www.youtube.com/embed/" + mediaId;
137    }
138
139    @Override
140    public Map<String, String> getStats(String mediaId, String account) {
141        YouTubeClient client = getYouTubeClient(account);
142        if (client == null) {
143            return Collections.emptyMap();
144        }
145
146        try {
147            VideoStatistics stats = client.getStatistics(mediaId);
148            if (stats == null) {
149                return null;
150            }
151
152            Map<String, String> map = new HashMap<>();
153            map.put("label.mediaPublishing.stats.views", stats.getViewCount().toString());
154            map.put("label.mediaPublishing.stats.comments", stats.getCommentCount().toString());
155            map.put("label.mediaPublishing.stats.likes", stats.getLikeCount().toString());
156            map.put("label.mediaPublishing.stats.dislikes", stats.getDislikeCount().toString());
157            map.put("label.mediaPublishing.stats.favorites", stats.getFavoriteCount().toString());
158            return map;
159        } catch (IOException e) {
160            return null;
161        }
162    }
163
164    @Override
165    public boolean isMediaPublished(String mediaId, String account) {
166        YouTubeClient client = getYouTubeClient(account);
167        if (client == null) {
168            return false;
169        }
170
171        try {
172            VideoListResponse list = client.getYouTube().videos().list("id").setId(mediaId).execute();
173            return list.getItems().size() > 0;
174        } catch (IOException e) {
175            return false;
176        }
177    }
178}