| /* |
| * 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; |
| } |
| |
| } |