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