/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.streams.youtube.serializer;
import org.apache.streams.exceptions.ActivitySerializerException;
import org.apache.streams.pojo.extensions.ExtensionUtil;
import org.apache.streams.pojo.json.Activity;
import org.apache.streams.pojo.json.ActivityObject;
import org.apache.streams.pojo.json.Image;
import org.apache.streams.pojo.json.Provider;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.Channel;
import com.google.api.services.youtube.model.Thumbnail;
import com.google.api.services.youtube.model.ThumbnailDetails;
import com.google.api.services.youtube.model.Video;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class YoutubeActivityUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(YoutubeActivityUtil.class);
/**
* Given a {@link YouTube.Videos} object and an
* {@link Activity} object, fill out the appropriate details
*
* @param video Video
* @param activity Activity
* @throws ActivitySerializerException ActivitySerializerException
*/
public static void updateActivity(Video video, Activity activity, String channelId) throws ActivitySerializerException {
activity.setActor(buildActor(video, video.getSnippet().getChannelId()));
activity.setVerb("post");
activity.setId(formatId(activity.getVerb(), Optional.ofNullable(video.getId()).orElse(null)));
activity.setPublished(new DateTime(video.getSnippet().getPublishedAt().getValue()));
activity.setTitle(video.getSnippet().getTitle());
activity.setContent(video.getSnippet().getDescription());
activity.setUrl("https://www.youtube.com/watch?v=" + video.getId());
activity.setProvider(getProvider());
activity.setObject(buildActivityObject(video));
addYoutubeExtensions(activity, video);
}
/**
* Given a {@link Channel} object and an
* {@link Activity} object, fill out the appropriate details
*
* @param channel Channel
* @param activity Activity
* @throws ActivitySerializerException ActivitySerializerException
*/
public static void updateActivity(Channel channel, Activity activity, String channelId) throws ActivitySerializerException {
try {
activity.setProvider(getProvider());
activity.setVerb("post");
activity.setActor(createActorForChannel(channel));
Map<String, Object> extensions = new HashMap<>();
extensions.put("youtube", channel);
activity.setAdditionalProperty("extensions", extensions);
} catch (Throwable throwable) {
throw new ActivitySerializerException(throwable);
}
}
/**
* createActorForChannel.
* @param channel Channel
* @return $.actor
*/
public static ActivityObject createActorForChannel(Channel channel) {
ActivityObject actor = new ActivityObject();
// TODO: use generic provider id concatenator
actor.setId("id:youtube:" + channel.getId());
actor.setSummary(channel.getSnippet().getDescription());
actor.setDisplayName(channel.getSnippet().getTitle());
Image image = new Image();
image.setUrl(channel.getSnippet().getThumbnails().getHigh().getUrl());
actor.setImage(image);
actor.setUrl("https://youtube.com/user/" + channel.getId());
Map<String, Object> actorExtensions = new HashMap<>();
actorExtensions.put("followers", channel.getStatistics().getSubscriberCount());
actorExtensions.put("posts", channel.getStatistics().getVideoCount());
actor.setAdditionalProperty("extensions", actorExtensions);
return actor;
}
/**
* Given a video object, create the appropriate activity object with a valid image
* (thumbnail) and video URL.
* @param video Video
* @return Activity Object with Video URL and a thumbnail image
*/
private static ActivityObject buildActivityObject(Video video) {
ActivityObject activityObject = new ActivityObject();
ThumbnailDetails thumbnailDetails = video.getSnippet().getThumbnails();
Thumbnail thumbnail = thumbnailDetails.getDefault();
if (thumbnail != null) {
Image image = new Image();
image.setUrl(thumbnail.getUrl());
image.setHeight(thumbnail.getHeight());
image.setWidth(thumbnail.getWidth());
activityObject.setImage(image);
}
activityObject.setUrl("https://www.youtube.com/watch?v=" + video.getId());
activityObject.setObjectType("video");
return activityObject;
}
/**
* Add the Youtube extensions to the Activity object that we're building.
* @param activity Activity
* @param video Video
*/
private static void addYoutubeExtensions(Activity activity, Video video) {
Map<String, Object> extensions = ExtensionUtil.getInstance().ensureExtensions(activity);
extensions.put("youtube", video);
if (video.getStatistics() != null) {
Map<String, Object> likes = new HashMap<>();
likes.put("count", video.getStatistics().getCommentCount());
extensions.put("likes", likes);
}
}
/**
* Build an {@link ActivityObject} actor given the video object
* @param video Video
* @param id id
* @return Actor object
*/
private static ActivityObject buildActor(Video video, String id) {
ActivityObject actor = new ActivityObject();
actor.setId("id:youtube:" + id);
actor.setDisplayName(video.getSnippet().getChannelTitle());
actor.setSummary(video.getSnippet().getDescription());
actor.setAdditionalProperty("handle", video.getSnippet().getChannelTitle());
return actor;
}
/**
* Gets the common youtube {@link Provider} object
* @return a provider object representing YouTube
*/
public static Provider getProvider() {
Provider provider = new Provider();
provider.setId("id:providers:youtube");
provider.setDisplayName("YouTube");
return provider;
}
/**
* Formats the ID to conform with the Apache Streams activity ID convention
* @param idparts the parts of the ID to join
* @return a valid Activity ID in format "id:youtube:part1:part2:...partN"
*/
public static String formatId(String... idparts) {
return String.join(":",
Stream.concat(Arrays.stream(new String[] {"id:youtube"}), Arrays.stream(idparts)).collect(Collectors.toList()));
}
}