/* * 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.filesources; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.database.Cursor; import android.os.IBinder; import android.text.TextUtils; import com.miz.abstractclasses.MovieFileSource; import com.miz.db.DbAdapterMovieMappings; import com.miz.functions.ColumnIndexCache; import com.miz.functions.DbMovie; import com.miz.functions.FileSource; import com.miz.functions.MizLib; import com.miz.mizuu.MizuuApplication; import com.miz.service.WireUpnpService; import com.miz.utils.MovieDatabaseUtils; import org.teleal.cling.android.AndroidUpnpService; import org.teleal.cling.model.action.ActionInvocation; import org.teleal.cling.model.message.UpnpResponse; import org.teleal.cling.model.meta.Device; import org.teleal.cling.model.meta.LocalDevice; import org.teleal.cling.model.meta.RemoteDevice; import org.teleal.cling.model.meta.Service; import org.teleal.cling.model.types.UDAServiceType; import org.teleal.cling.registry.DefaultRegistryListener; import org.teleal.cling.registry.Registry; import org.teleal.cling.support.contentdirectory.callback.Browse; import org.teleal.cling.support.model.BrowseFlag; import org.teleal.cling.support.model.DIDLContent; import org.teleal.cling.support.model.SortCriterion; import org.teleal.cling.support.model.container.Container; import org.teleal.cling.support.model.item.Item; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.TreeSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class UpnpMovie extends MovieFileSource<String> { private TreeSet<String> results = new TreeSet<String>(); private HashMap<String, String> existingMovies = new HashMap<String, String>(); private CountDownLatch mLatch = new CountDownLatch(1); private AndroidUpnpService mUpnpService; public UpnpMovie(Context context, FileSource fileSource, boolean clearLibrary) { super(context, fileSource, clearLibrary); } @Override public void removeUnidentifiedFiles() { List<DbMovie> dbMovies = getDbMovies(); int count = dbMovies.size(); for (int i = 0; i < count; i++) { if (dbMovies.get(i).isUpnpFile() && dbMovies.get(i).isUnidentified() && MizLib.exists(dbMovies.get(i).getFilepath())) MovieDatabaseUtils.deleteMovie(mContext, dbMovies.get(i).getTmdbId()); } } @Override public void removeUnavailableFiles() { List<DbMovie> dbMovies = getDbMovies(); int count = dbMovies.size(); for (int i = 0; i < count; i++) { if (dbMovies.get(i).isUpnpFile() && !MizLib.exists(dbMovies.get(i).getFilepath())) { MovieDatabaseUtils.deleteMovie(mContext, dbMovies.get(i).getTmdbId()); } } } @Override public List<String> searchFolder() { DbAdapterMovieMappings dbHelper = MizuuApplication.getMovieMappingAdapter(); Cursor cursor = dbHelper.getAllFilepaths(false); // Query database to return all filepaths in a cursor ColumnIndexCache cache = new ColumnIndexCache(); try { while (cursor.moveToNext()) {// Add all movies in cursor to ArrayList of all existing movies existingMovies.put(cursor.getString(cache.getColumnIndex(cursor, DbAdapterMovieMappings.KEY_FILEPATH)), ""); } } catch (Exception e) { } finally { cursor.close(); // Close cursor cache.clear(); } // Do a recursive search in the file source folder recursiveSearch(getFolder(), results); List<String> list = new ArrayList<String>(); Iterator<String> it = results.iterator(); while (it.hasNext()) list.add(it.next()); return list; } @Override public void recursiveSearch(String folder, TreeSet<String> results) { mContext.getApplicationContext().bindService(new Intent(mContext, WireUpnpService.class), serviceConnection, Context.BIND_AUTO_CREATE); try { mLatch.await(10, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } } public void addToResults(String file, long size, TreeSet<String> results) { if (MizLib.checkFileTypes(file)) { if (size < getFileSizeLimit()) return; if (!clearLibrary()) if (existingMovies.get(file.split("<MiZ>")[1]) != null || existingMovies.get(file) != null) return; String tempFileName = file.substring(0, file.lastIndexOf(".")); if (tempFileName.toLowerCase(Locale.ENGLISH).matches(".*part[2-9]|cd[2-9]")) return; //Add the file if it reaches this point results.add(file); } } @Override public String getRootFolder() { return mFileSource.getUpnpFolderId(); } @Override public String toString() { return mFileSource.getFilepath(); } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mUpnpService = (AndroidUpnpService) service; boolean found = false; for (Device<?, ?, ?> device : mUpnpService.getRegistry().getDevices()) { try { if (!TextUtils.isEmpty(device.getDetails().getSerialNumber())) { if (device.getDetails().getSerialNumber().equals(mFileSource.getUpnpSerialNumber())) { startBrowse(device); found = true; } } else { if (device.getIdentity().getUdn().toString().equals(mFileSource.getUpnpSerialNumber())) { startBrowse(device); found = true; } } } catch (Exception e) {} } if (!found) { mUpnpService.getRegistry().addListener(new DeviceListRegistryListener()); mUpnpService.getControlPoint().search(); } } public void onServiceDisconnected(ComponentName className) { mUpnpService = null; } private void startBrowse(Device<?, ?, ?> device) { Service<?, ?> service = device.findService(new UDAServiceType("ContentDirectory")); browse(service, getRootFolder(), mFileSource.getUpnpName()); } }; private int mFolderCount = 0, mScannedCount = 0; private class BrowseCallback extends Browse { private Service<?, ?> mService; private String mPrefix; public BrowseCallback(String prefix, Service<?, ?> service, String containerId) { super(service, containerId, BrowseFlag.DIRECT_CHILDREN, "*", 0, null, new SortCriterion(true, "dc:title")); mService = service; mPrefix = prefix; } @SuppressWarnings("rawtypes") @Override public void received(ActionInvocation arg0, DIDLContent didl) { try { for (Container childContainer : didl.getContainers()) { mFolderCount++; mUpnpService.getControlPoint().execute(new BrowseCallback(mPrefix + "/" + childContainer.getTitle(), mService, childContainer.getId())); } for (Item childItem : didl.getItems()) { addToResults(mPrefix + "/" + childItem.getTitle() + "<MiZ>" + childItem.getFirstResource().getValue(), childItem.getFirstResource().getSize(), results); } mScannedCount++; if (mFolderCount == mScannedCount) { mLatch.countDown(); mContext.unbindService(serviceConnection); } } catch (Exception e) {} } @Override public void updateStatus(Status arg0) {} @SuppressWarnings("rawtypes") @Override public void failure(ActionInvocation arg0, UpnpResponse arg1, String arg2) {} } public class DeviceListRegistryListener extends DefaultRegistryListener { private boolean found = false; @Override public void remoteDeviceAdded(Registry registry, RemoteDevice device) { if (device.getType().getNamespace().equals("schemas-upnp-org") && device.getType().getType().equals("MediaServer")) { if (!found) { try { if (!TextUtils.isEmpty(device.getDetails().getSerialNumber())) { if (device.getDetails().getSerialNumber().equals(mFileSource.getUpnpSerialNumber())) { startBrowse(device); found = true; } } else { if (device.getIdentity().getUdn().toString().equals(mFileSource.getUpnpSerialNumber())) { startBrowse(device); found = true; } } } catch (Exception e) {} } } } @Override public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {} @Override public void localDeviceAdded(Registry registry, LocalDevice device) { if (!found) { try { if (!TextUtils.isEmpty(device.getDetails().getSerialNumber())) { if (device.getDetails().getSerialNumber().equals(mFileSource.getUpnpSerialNumber())) { startBrowse(device); found = true; } } else { if (device.getIdentity().getUdn().toString().equals(mFileSource.getUpnpSerialNumber())) { startBrowse(device); found = true; } } } catch (Exception e) {} } } @Override public void localDeviceRemoved(Registry registry, LocalDevice device) {} private void startBrowse(Device<?, ?, ?> device) { mFolderCount++; Service<?, ?> service = device.findService(new UDAServiceType("ContentDirectory")); browse(service, getRootFolder(), mFileSource.getFilepath().substring(mFileSource.getFilepath().lastIndexOf("/") + 1, mFileSource.getFilepath().length())); } } private void browse(Service<?, ?> service, String containerId, String title) { mUpnpService.getControlPoint().execute(new BrowseCallback(title, service, containerId)); } @Override public void addToResults(String folder, TreeSet<String> results) {} }