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}