/*
* Copyright (C) 2014 Michell Bak
*
* 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.miz.identification;
import android.content.Context;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.SparseBooleanArray;
import com.miz.abstractclasses.MovieApiService;
import com.miz.apis.tmdb.Movie;
import com.miz.db.DbAdapterMovieMappings;
import com.miz.db.DbAdapterMovies;
import com.miz.functions.MizLib;
import com.miz.functions.MovieLibraryUpdateCallback;
import com.miz.mizuu.MizuuApplication;
import com.miz.utils.FileUtils;
import com.miz.utils.LocalBroadcastUtils;
import com.miz.utils.MovieDatabaseUtils;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static com.miz.functions.PreferenceKeys.LANGUAGE_PREFERENCE;
public class MovieIdentification {
private final Picasso mPicasso;
private final MovieLibraryUpdateCallback mCallback;
private final Context mContext;
private final ArrayList<MovieStructure> mMovieStructures;
private SparseBooleanArray mImdbMap = new SparseBooleanArray();
private String mMovieId = null, mCurrentMovieId = null, mLocale = null;
private boolean mCancel = false;
private int mCount = 0;
public MovieIdentification(Context context, MovieLibraryUpdateCallback callback, ArrayList<MovieStructure> files) {
mContext = context;
mCallback = callback;
mMovieStructures = new ArrayList<MovieStructure>(files);
mPicasso = Picasso.with(mContext);
// Get the language preference
getLanguagePreference();
}
private void getLanguagePreference() {
mLocale = PreferenceManager.getDefaultSharedPreferences(mContext).getString(LANGUAGE_PREFERENCE, "en");
}
/**
* Use this to disable movie searching
* and attempt identification based on the
* provided movie ID.
* @param movieId
*/
public void setMovieId(String movieId) {
mMovieId = movieId;
}
public void setCurrentMovieId(String oldMovieId) {
if (!TextUtils.isEmpty(oldMovieId))
mCurrentMovieId = oldMovieId;
}
private boolean overrideMovieId() {
return null != getMovieId();
}
private String getMovieId() {
return mMovieId;
}
private String getCurrentMovieId() {
return mCurrentMovieId;
}
/**
* Accepts two-letter ISO 639-1 language codes, i.e. "en".
* @param language
*/
public void setLanguage(String language) {
mLocale = language;
}
public void cancel() {
mCancel = true;
}
public void start() {
// Go through all files
for (int i = 0; i < mMovieStructures.size(); i++) {
if (mCancel)
return;
MovieStructure ms = mMovieStructures.get(i);
mImdbMap.put(i, ms.hasImdbId());
}
MovieApiService service = MizuuApplication.getMovieService(mContext);
for (MovieStructure ms : mMovieStructures) {
if (mCancel)
return;
mCount++;
Movie movie = null;
List<Movie> results = new ArrayList<Movie>();
if (!overrideMovieId()) {
// Check if there's an IMDb ID and attempt to search based on it
if (ms.hasImdbId()) {
results = service.searchByImdbId(ms.getImdbId(), null);
}
// If there's no results, attempt to search based on the movie file name and year
if (results.size() == 0) {
int year = ms.getReleaseYear();
if (year >= 0)
results = service.search(ms.getDecryptedFilename(), String.valueOf(year), null);
}
// If there's still no results, attempt to search based on the movie file name without year
if (results.size() == 0)
results = service.search(ms.getDecryptedFilename(), null);
// If there's still no results, attempt to search based on the parent folder name and year
if (results.size() == 0) {
int year = ms.getReleaseYear();
if (year >= 0)
results = service.search(ms.getDecryptedParentFolderName(), String.valueOf(year), null);
}
// If there's still no results, search based on the parent folder name only
if (results.size() == 0)
results = service.search(ms.getDecryptedParentFolderName(), null);
} else {
movie = service.get(getMovieId(), mLocale);
}
if (!overrideMovieId() && results.size() > 0) {
// Automatic library update
movie = service.get(results.get(0).getId(), mLocale);
}
// Last check - is movie still null?
if (movie == null)
movie = new Movie();
createMovie(ms, movie);
}
}
private void createMovie(MovieStructure ms, Movie movie) {
boolean downloadCovers = true;
if (!movie.getId().equals(DbAdapterMovies.UNIDENTIFIED_ID) && !TextUtils.isEmpty(movie.getId()))
// We only want to download covers if the movie doesn't already exist
downloadCovers = !MizuuApplication.getMovieAdapter().movieExists(movie.getId());
if (downloadCovers) {
String thumb_filepath = FileUtils.getMovieThumb(mContext, movie.getId()).getAbsolutePath();
// Download the cover image and try again if it fails
if (!MizLib.downloadFile(movie.getCover(), thumb_filepath))
MizLib.downloadFile(movie.getCover(), thumb_filepath);
// Download the backdrop image and try again if it fails
if (!TextUtils.isEmpty(movie.getBackdrop())) {
String backdropFile = FileUtils.getMovieBackdrop(mContext, movie.getId()).getAbsolutePath();
if (!MizLib.downloadFile(movie.getBackdrop(), backdropFile))
MizLib.downloadFile(movie.getBackdrop(), backdropFile);
}
// Download the collection image
if (!TextUtils.isEmpty(movie.getCollectionImage())) {
String collectionImage = FileUtils.getMovieThumb(mContext, movie.getCollectionId()).getAbsolutePath();
if (!MizLib.downloadFile(movie.getCollectionImage(), collectionImage))
MizLib.downloadFile(movie.getCollectionImage(), collectionImage);
}
}
addToDatabase(ms, movie);
}
private void addToDatabase(MovieStructure ms, Movie movie) {
DbAdapterMovieMappings dbHelperMovieMapping = MizuuApplication.getMovieMappingAdapter();
DbAdapterMovies dbHelper = MizuuApplication.getMovieAdapter();
// Check if this is manual identification by the user
if (overrideMovieId()) {
// How many filepaths are mapped to the current movie ID?
int currentCount = dbHelperMovieMapping.getMovieFilepaths(getCurrentMovieId()).size();
if (currentCount > 1) {
// This movie has more than one filepath mapping, so we don't want
// to remove the movie entry nor any images, etc.
// Update the ID currently used to map the filepath to the movie
dbHelperMovieMapping.updateTmdbId(ms.getFilepath(), getCurrentMovieId(), getMovieId());
} else {
if (TextUtils.isEmpty(getCurrentMovieId())) {
// We're dealing with an unidentified movie, so we update
// the mapped TMDb ID of the filepath to the new one
dbHelperMovieMapping.updateTmdbId(ms.getFilepath(), getMovieId());
} else {
// This movie only has one filepath mapping, i.e. the one we're
// currently re-assigning. It's safe to delete all movie data and
// create the filepath mapping for the new movie ID.
// Delete the old movie and everything related to it
MovieDatabaseUtils.deleteMovie(mContext, getCurrentMovieId());
// Create the new filepath mapping
dbHelperMovieMapping.createFilepathMapping(ms.getFilepath(), getMovieId());
}
}
} else {
// This is Mizuu's automatic library update...
// Just create the filepath mapping - if the filepath / movie
// combination already exists, it won't do anything
dbHelperMovieMapping.createFilepathMapping(ms.getFilepath(), movie.getId());
}
// Finally, create or update the movie
dbHelper.createOrUpdateMovie(movie.getId(), movie.getTitle(), movie.getPlot(), movie.getImdbId(), movie.getRating(), movie.getTagline(),
movie.getReleasedate(), movie.getCertification(), movie.getRuntime(), movie.getTrailer(), movie.getGenres(), "0",
movie.getCast(), movie.getCollectionTitle(), movie.getCollectionId(), "0", "0", String.valueOf(System.currentTimeMillis()));
updateNotification(movie);
}
private void updateNotification(Movie movie) {
File backdropFile = FileUtils.getMovieBackdrop(mContext, movie.getId());
if (!backdropFile.exists())
backdropFile = FileUtils.getMovieThumb(mContext, movie.getId());
if (mCallback != null) {
try {
mCallback.onMovieAdded(movie.getTitle(),
mPicasso.load(FileUtils.getMovieThumb(mContext, movie.getId())).resize(getNotificationImageSizeSmall(), (int) (getNotificationImageSizeSmall() * 1.5)).get(),
mPicasso.load(backdropFile).resize(getNotificationImageWidth(), getNotificationImageHeight()).skipMemoryCache().get(), mCount);
} catch (Exception e) {
mCallback.onMovieAdded(movie.getTitle(), null, null, mCount);
}
}
LocalBroadcastUtils.updateMovieLibrary(mContext);
}
// These variables don't need to be re-initialized
private int widgetWidth = 0, widgetHeight = 0, smallSize = 0;
private int getNotificationImageWidth() {
if (widgetWidth == 0)
widgetWidth = MizLib.getLargeNotificationWidth(mContext);
return widgetWidth;
}
private int getNotificationImageHeight() {
if (widgetHeight == 0)
widgetHeight = (int) (MizLib.getLargeNotificationWidth(mContext) / 1.778);
return widgetHeight;
}
private int getNotificationImageSizeSmall() {
if (smallSize == 0)
smallSize = MizLib.getThumbnailNotificationSize(mContext);
return smallSize;
}
}