blob: 4e87470701d597b55478a5a626ce4e864134fb26 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed 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 com.motorola.studio.android.videos.model;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.common.utilities.HttpUtils;
import com.motorola.studio.android.videos.Activator;
import com.motorola.studio.android.videos.implementation.youtube.YoutubeVideoServiceProvider;
import com.motorola.studio.android.videos.model.extension.VideoServiceProvider;
/**
* Manage the actions related to videos, including loading them and
* providing any related information to other classes.
*/
public class VideoManager
{
/*
* Sort options
*/
public static final int SORT_MOST_RECENT = 0;
public static final int SORT_MOST_VIEWED = 1;
public static final int SORT_TOP_RATED = 2;
/*
* Video channels and source definitions (XML)
*/
public static final String VIDEOS_DEFINITIONS = "resources/motodev_videos.xml";
public static final String TAG_USER = "user";
public static final String TAG_USER_ATT_NAME = "name";
public static final String TAG_CHANNEL = "channel";
public static final String TAG_CHANNEL_ATT_NAME = "name";
public static final String TAG_CHANNEL_ATT_DISPLAY_NAME = "display_name";
// "fixed" or "variable"
public static final String TAG_CHANNEL_ATT_ORDER = "order";
public static final String TAG_CHANNEL_ATT_ORDER_FIXED = "fixed";
// "true" or "false"
public static final String TAG_CHANNEL_ATT_DEFAULT = "default";
/*
* Singleton
*/
private static VideoManager instance;
/*
* The selected video service provider
*/
private VideoServiceProvider videoServiceProvider = null;
/*
* Credentials information to be passed to the video service provider
*/
private String userName = null;
/*
* The video channel objects (the videos themselves are attributes of these objects)
*/
private String defaultVideoChannel = null;
// Map "channel name" -> object that represent the video channel
private final Map<String, VideoChannel> channelsMap = new HashMap<String, VideoChannel>();
private final List<VideoChannel> channelsList = new ArrayList<VideoChannel>();
/**
* Singleton
*
* @return a unique VideoManager instance
* @throws Exception
*/
public static synchronized VideoManager getInstance() throws Exception
{
if (instance == null)
{
instance = new VideoManager();
}
return instance;
}
/**
* Load all channels and videos
*/
public void load() throws Exception
{
channelsMap.clear();
channelsList.clear();
File file =
new File(FileLocator.toFileURL(
Activator.getDefault().getBundle().getEntry(VIDEOS_DEFINITIONS)).getPath());
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = documentBuilder.parse(file);
/*
* Get service username
*/
NodeList user = doc.getElementsByTagName(TAG_USER);
Node userNameNode = user.item(0).getAttributes().getNamedItem(TAG_USER_ATT_NAME);
userName = userNameNode.getNodeValue();
/*
* Initialize video service provider
*/
videoServiceProvider = new YoutubeVideoServiceProvider(userName);
/*
* Get all channels
*/
NodeList channels = doc.getElementsByTagName(TAG_CHANNEL);
for (int i = 0; i < channels.getLength(); i++)
{
Node channel = channels.item(i);
String displayName =
channel.getAttributes().getNamedItem(TAG_CHANNEL_ATT_DISPLAY_NAME)
.getTextContent();
String name =
channel.getAttributes().getNamedItem(TAG_CHANNEL_ATT_NAME).getTextContent();
boolean order = false;
boolean defaultChannel = false;
if (channel.getAttributes().getNamedItem(TAG_CHANNEL_ATT_ORDER) != null)
{
order =
channel.getAttributes().getNamedItem(TAG_CHANNEL_ATT_ORDER)
.getTextContent().equals(TAG_CHANNEL_ATT_ORDER_FIXED) ? true
: false;
}
if (channel.getAttributes().getNamedItem(TAG_CHANNEL_ATT_DEFAULT) != null)
{
defaultChannel =
channel.getAttributes().getNamedItem(TAG_CHANNEL_ATT_DEFAULT)
.getTextContent().equals(new Boolean(true).toString()) ? true
: false;
}
/*
* Create and populate the channels
*/
VideoChannel videoChannel = new VideoChannel(name);
videoChannel.setDisplayName(displayName);
videoChannel.setOrdered(order);
videoChannel.setDefaultChannel(defaultChannel);
if (defaultChannel)
{
defaultVideoChannel = name;
}
List<Video> videos = videoServiceProvider.loadVideos(videoChannel);
if (videos != null)
{
videoChannel.setVideos(videos);
}
else
{
videoChannel.setActive(false);
}
channelsMap.put(name, videoChannel);
channelsList.add(videoChannel);
}
}
/**
* Sort all videos from all channels
*
* @param criteria
*/
public void sort(final int criteria)
{
for (VideoChannel channel : channelsList)
{
if (!channel.isOrdered())
{
List<Video> videos = channel.getVideos();
Collections.sort(videos, new Comparator<Video>()
{
public int compare(Video arg0, Video arg1)
{
int result = 0;
switch (criteria)
{
case VideoManager.SORT_MOST_RECENT:
result = arg0.getDate().compareTo(arg1.getDate());
break;
case VideoManager.SORT_MOST_VIEWED:
result = arg0.getViews() >= arg1.getViews() ? 1 : -1;
break;
case VideoManager.SORT_TOP_RATED:
result = arg0.getRating() >= arg1.getRating() ? 1 : -1;
break;
}
return result;
}
});
}
}
}
/**
* Get videos from a channel
*
* @param channel channel to retrieve the videos
*/
public List<Video> getVideos(VideoChannel channel)
{
List<Video> videos = null;
if (channelsMap.get(channel.getName()) != null)
{
videos = channelsMap.get(channel.getName()).getVideos();
}
return videos;
}
/**
* Get all channels
*
* @return all channels
*/
public List<VideoChannel> getChannels()
{
return channelsList;
}
/**
* Get only the active channels
*
* @return the active channels, which were found by the video service provider
*/
public List<VideoChannel> getActiveChannels()
{
List<VideoChannel> activeVideoChannels = new ArrayList<VideoChannel>();
for (VideoChannel channel : channelsList)
{
if (channel.isActive())
{
activeVideoChannels.add(channel);
}
}
return activeVideoChannels;
}
/**
* Get the default channel, to be selected in the UI by default
*
* @return the default channel
*/
public VideoChannel getDefaultChannel()
{
return channelsMap.get(defaultVideoChannel);
}
/**
* Rate a video
*
* @param video video to be rated
* @param rate video rate
*/
public void rate(Video video, int rate) throws Exception
{
// delegate to the video service provider
videoServiceProvider.rate(video, rate);
}
/**
* Search all videos from all channels
*
* @param keyword search keyword
* @return only the videos that match the keyword
*/
public List<Video> search(String keyword)
{
List<Video> selectedVideos = new ArrayList<Video>();
// split the keyword into tokens
String[] tokens = keyword.split("\\s");
int numberOfTokens = tokens.length;
/*
* For each channel, search the videos and try to find all
* tokens on each video
*/
int visibleVideosInChannel;
for (VideoChannel channel : channelsList)
{
visibleVideosInChannel = 0;
for (Video video : channel.getVideos())
{
int tokensFound = 0;
if (numberOfTokens > 0)
{
StringBuffer sb = new StringBuffer();
sb.append(video.getTitle());
sb.append(" ");
sb.append(video.getDescription());
sb.append(" ");
sb.append(video.getKeywords());
for (int i = 0; i < tokens.length; i++)
{
String token = tokens[i];
if (sb.toString().toUpperCase().contains(token.toUpperCase()))
{
tokensFound++;
}
}
}
// if all tokens were found, mark the video as visible ...
if (tokensFound == numberOfTokens)
{
video.setVisible(true);
visibleVideosInChannel++;
selectedVideos.add(video);
}
// ... otherwise, mark the video as not visible
else
{
video.setVisible(false);
}
}
channel.setVisibleVideos(visibleVideosInChannel);
}
return selectedVideos;
}
/**
* Get the video thumbnail from the internet, given its URL
*
* @param url video URL
* @return the file representing the downloaded thumbnail
*/
public File getThumbnail(URL url)
{
File cacheIconFile = null;
HttpUtils httpUtils = new HttpUtils();
InputStream inStream = null;
FileOutputStream outStream = null;
try
{
inStream = httpUtils.getInputStreamForUrl(url.toString(), new NullProgressMonitor());
File remoteFile = new File(url.toString());
String[] remoteFileName = remoteFile.getName().split("\\.");
cacheIconFile = File.createTempFile(remoteFileName[0], "." + remoteFileName[1]);
cacheIconFile.deleteOnExit();
outStream = new FileOutputStream(cacheIconFile);
byte[] buf = new byte[1024];
int len;
while ((len = inStream.read(buf)) > 0)
{
outStream.write(buf, 0, len);
}
}
catch (Exception e)
{
StudioLogger.error(this.getClass(), "Error while retrieving video thumbnail", e);
}
finally
{
try
{
inStream.close();
outStream.close();
}
catch (Exception e)
{
StudioLogger.error(e.getMessage());
}
}
return cacheIconFile;
}
}