/*
* Copyright (C) 2005-2009 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC Remote; see the file license. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
package org.xbmc.jsonrpc.client;
import java.util.ArrayList;
import java.util.Iterator;
import org.codehaus.jackson.JsonNode;
import org.xbmc.api.business.INotifiableManager;
import org.xbmc.api.data.IVideoClient;
import org.xbmc.api.data.IControlClient.ICurrentlyPlaying;
import org.xbmc.api.info.PlayStatus;
import org.xbmc.api.object.Actor;
import org.xbmc.api.object.Genre;
import org.xbmc.api.object.Host;
import org.xbmc.api.object.ICoverArt;
import org.xbmc.api.object.Movie;
import org.xbmc.api.type.MediaType;
import org.xbmc.api.type.SortType;
import org.xbmc.jsonrpc.Connection;
import android.graphics.Bitmap;
/**
* Takes care of everything related to the video database.
*
* @author Team XBMC
*/
public class VideoClient extends Client implements IVideoClient {
public static final String TAG = "VideoClient";
public static final int PLAYLIST_ID = 1;
public static final int PLAYLIST_LIMIT = 100;
/**
* Class constructor needs reference to HTTP client connection
* @param connection
*/
public VideoClient(Connection connection) {
super(connection);
}
/**
* Updates host info on the connection.
* @param host
*/
public void setHost(Host host) {
mConnection.setHost(host);
}
/**
* Gets all movies from database
* @param sortBy Sort field, see SortType.*
* @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC.
* @return All movies
*/
public ArrayList<Movie> getMovies(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) {
return getMovies(manager, obj(), sortBy, sortOrder, hideWatched);
}
public ArrayList<Movie> getMovies(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, boolean hideWatched) {
obj = sort(obj.p(PARAM_PROPERTIES, arr().add("director").add("file").add("genre").add("imdbnumber").add("playcount").add("rating").add("runtime").add("thumbnail").add("year")), sortBy, sortOrder);
final ArrayList<Movie> movies = new ArrayList<Movie>();
final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetMovies", obj);
final JsonNode jsonMovies = result.get("movies");
if(jsonMovies != null){
for (Iterator<JsonNode> i = jsonMovies.getElements(); i.hasNext();) {
JsonNode jsonMovie = (JsonNode)i.next();
int playcount =getInt(jsonMovie, "playcount");
if(playcount > 0 && hideWatched)
continue;
int runtime = getInt(jsonMovie, "runtime");
String formatted_runtime = "";
if(runtime != -1){
if(runtime >= 3600)
formatted_runtime = (runtime / 3600) + "hr ";
formatted_runtime += ((runtime % 3600) / 60) + "min";
}
movies.add(new Movie(
getInt(jsonMovie, "movieid"),
getString(jsonMovie, "label"),
getInt(jsonMovie, "year"),
"",
getString(jsonMovie, "file"),
getString(jsonMovie, "director"),
formatted_runtime,
getString(jsonMovie, "genre"),
getDouble(jsonMovie, "rating"),
playcount,
getString(jsonMovie, "imdbnumber"),
getString(jsonMovie, "thumbnail")
));
}
}
return movies;
}
/**
* Gets movies from database with offset
* @param sortBy Sort field, see SortType.*
* @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC.
* @return Movies with offset
*/
public ArrayList<Movie> getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, boolean hideWatched) {
return getMovies(manager, obj().p("limits", obj().p("start", 0)), sortBy, sortOrder, hideWatched);
}
/**
* Gets all movies with an actor from database
* @param actor Display only movies with this actor.
* @param sortBy Sort field, see SortType.*
* @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC.
* @return All movies with an actor
*/
public ArrayList<Movie> getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched) {
return getMovies(manager, obj().p("filter", obj().p("actor", actor.name)), sortBy, sortOrder, hideWatched);
}
/**
* Gets all movies of a genre from database
* @param genre Display only movies of this genre.
* @param sortBy Sort field, see SortType.*
* @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC.
* @return All movies of a genre
*/
public ArrayList<Movie> getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched) {
return getMovies(manager, obj().p("filter", obj().p("genreid", genre.id)), sortBy, sortOrder, hideWatched);
}
/**
* Gets all movies from database
* @param sortBy Sort field, see SortType.*
* @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC.
* @return Updated movie
*/
public Movie updateMovieDetails(INotifiableManager manager, Movie movie) {
ObjNode obj = obj().p("movieid", movie.getId()).p(PARAM_PROPERTIES, arr().add("cast").add("mpaa").add("plot").add("studio").add("tagline").add("trailer").add("votes"));
final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetMovieDetails", obj);
final JsonNode jsonMovie = result.get("moviedetails");
movie.tagline = getString(jsonMovie, "tagline");
movie.plot = getString(jsonMovie, "plot");
movie.numVotes = getInt(jsonMovie, "votes");
movie.studio = getString(jsonMovie, "studio");
movie.rated = getString(jsonMovie, "mpaa");
movie.trailerUrl = getString(jsonMovie, "trailer");
ArrayList<Actor> actors = new ArrayList<Actor>();
final JsonNode jsonCast = jsonMovie.get("cast");
for (Iterator<JsonNode> i = jsonCast.getElements(); i.hasNext();) {
JsonNode jsonActor = (JsonNode)i.next();
actors.add(new Actor(
getInt(jsonActor,"actorid"),
getString(jsonActor, "name"),
getString(jsonActor, "thumbnail"),
getString(jsonActor, "role")
));
}
movie.actors = actors;
return movie;
}
/**
* Gets all actors from database. Use {@link getMovieActors()} and
* {@link getTvActors()} for filtered actors.
* @return All actors
*/
public ArrayList<Actor> getActors(INotifiableManager manager) {
//TODO
return new ArrayList<Actor>();
}
/**
* Gets all movie actors from database
* @return All movie actors
*/
public ArrayList<Actor> getMovieActors(INotifiableManager manager) {
//TODO
return new ArrayList<Actor>();
}
/**
* Gets all movie actors from database
* @return All movie actors
*/
public ArrayList<Actor> getTvShowActors(INotifiableManager manager) {
return new ArrayList<Actor>();//parseActors(mConnection.query("QueryVideoDatabase", sb.toString(), manager));
}
/**
* Gets all movie genres from database
* @return All movie genres
*/
public ArrayList<Genre> getGenres(INotifiableManager manager, String type) {
ObjNode obj = sort(obj().p("type", type), SortType.TITLE, "descending");
final ArrayList<Genre> genres = new ArrayList<Genre>();
final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetGenres", obj);
final JsonNode jsonGenres = result.get("genres");
if(jsonGenres != null){
for (Iterator<JsonNode> i = jsonGenres.getElements(); i.hasNext();) {
JsonNode jsonGenre = (JsonNode)i.next();
genres.add(new Genre(
getInt(jsonGenre, "genreid"),
getString(jsonGenre, "label")
));
}
}
return genres;
}
public ArrayList<Genre> getMovieGenres(INotifiableManager manager) {
return getGenres(manager, "movie");
}
/**
* Gets all tv show genres from database
* @return All tv show genres
*/
public ArrayList<Genre> getTvShowGenres(INotifiableManager manager) {
return getGenres(manager, "tvshow");
}
/**
* Returns a pre-resized movie cover. Pre-resizing is done in a way that
* the bitmap at least as large as the specified size but not larger than
* the double.
* @param manager Postback manager
* @param cover Cover object
* @param size Minmal size to pre-resize to.
* @return Thumbnail bitmap
*/
public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) {
String url = null;
if(Movie.getThumbUri(cover) != ""){
final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", Movie.getThumbUri(cover)));
if(dl != null){
JsonNode details = dl.get("details");
if(details != null)
url = mConnection.getUrl(getString(details, "path"));
}
}
return getCover(manager, cover, size, url);
}
static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) {
return new ICurrentlyPlaying() {
private static final long serialVersionUID = 5036994329211476714L;
public String getTitle() {
String title =getString(item, "title");
if (title != null && !title.equals(""))
return title;
String[] path = getString(item, "file").replaceAll("\\\\", "/").split("/");
return path[path.length - 1];
}
public int getTime() {
return ControlClient.parseTime(player.get("time"));
}
public int getPlayStatus() {
return getInt(player, "speed");
}
public int getPlaylistPosition() {
return getInt(player, "position");
}
//Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156
public float getPercentage() {
try{
return getInt(player, "percentage");
} catch (NumberFormatException e) { }
return (float)getDouble(player, "percentage");
}
public String getFilename() {
return getString(item, "file");
}
public int getDuration() {
return ControlClient.parseTime(player.get("totaltime"));
}
public String getArtist() {
return getString(item, "genre");
}
public String getAlbum() {
String title = getString(item, "tagline");
if (title != null)
return title;
String path = getString(item, "file").replaceAll("\\\\", "/");
return path.substring(0, path.lastIndexOf("/"));
}
public int getMediaType() {
return MediaType.VIDEO;
}
public boolean isPlaying() {
return getInt(player, "speed") == PlayStatus.PLAYING;
}
public int getHeight() {
return 0;
}
public int getWidth() {
return 0;
}
};
}
/**
* Retrieves the currently playing video number in the playlist.
* @return Number of items in the playlist
*/
public int getPlaylistPosition(INotifiableManager manager) {
final JsonNode active = mConnection.getJson(manager, "Player.GetActivePlayers", null).get(0);
return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getInt(active, "playerid")).p(PARAM_PROPERTIES, arr().add("position")), "position");
}
/**
* Sets the media at playlist position to be the next item to be played.
* @param position New position, starting with 0.
* @return True on success, false otherwise.
*/
public boolean setPlaylistPosition(INotifiableManager manager, int position) {
int playerid = getActivePlayerId(manager);
if(playerid == -1)
return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", PLAYLIST_ID).p("position", position))).equals("OK");
else
return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", getActivePlayerId(manager)).p("position", position)).equals("OK");
}
/**
* Returns the first {@link PLAYLIST_LIMIT} videos of the playlist.
* @return Videos in the playlist.
*/
public ArrayList<String> getPlaylist(INotifiableManager manager) {
JsonNode jsonItems = mConnection.getJson(manager, "PlayList.GetItems", obj().p("playlistid", PLAYLIST_ID).p("limits", obj().p("start", 0).p("end", PLAYLIST_LIMIT)).p("properties", arr().add("file")));
JsonNode jsonSongs = jsonItems.get("items");
final ArrayList<String> files = new ArrayList<String>();
if (jsonSongs != null) {
for (Iterator<JsonNode> i = jsonSongs.getElements(); i.hasNext();) {
JsonNode jsonSong = (JsonNode)i.next();
files.add(getString(jsonSong, "file"));
}
}
return files;
}
/**
* Removes media from the current playlist. It is not possible to remove the media if it is currently being played.
* @param position Complete path (including filename) of the media to be removed.
* @return True on success, false otherwise.
*/
public boolean removeFromPlaylist(INotifiableManager manager, String path) {
return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", PLAYLIST_ID).p("position", "position")).equals("OK");
}
}