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}