/* * Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner, * Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain, * Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter, * Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann, * Samuel Zweifel * * This file is part of Jukefox. * * Jukefox 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 3 of the License, or any later version. Jukefox 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 * Jukefox. If not, see <http://www.gnu.org/licenses/>. */ package ch.ethz.dcg.pancho3.model; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; import ch.ethz.dcg.jukefox.commons.utils.Log; import ch.ethz.dcg.jukefox.commons.utils.AndroidUtils; import ch.ethz.dcg.jukefox.model.AndroidCollectionModelManager; import ch.ethz.dcg.jukefox.model.collection.BaseAlbum; import ch.ethz.dcg.jukefox.model.collection.BaseArtist; import ch.ethz.dcg.jukefox.model.collection.ImportedPlaylist; import ch.ethz.dcg.jukefox.model.collection.PlaylistSong; /** * Imports playlists that were not saved by jukefox * * @author kuhnmi * */ public class PlaylistImporter { private final static String TAG = PlaylistImporter.class.getSimpleName(); public static class PlaylistInfo { protected final String path; protected final String name; protected final Date dateModified; protected final Date dateAdded; public PlaylistInfo(String path, String name, Date dateModified, Date dateAdded) { this.path = path; this.name = name; this.dateModified = dateModified; this.dateAdded = dateAdded; } public String getPath() { return path; } public String getName() { return name; } public Date getDateModified() { return dateModified; } public Date getDateAdded() { return dateAdded; } @Override public String toString() { return path; } } private AndroidCollectionModelManager collectionModel; public PlaylistImporter(AndroidCollectionModelManager collectionModel) { this.collectionModel = collectionModel; } public List<PlaylistInfo> getPlaylists() { String[] projection = new String[] { MediaStore.Audio.PlaylistsColumns.NAME, MediaStore.Audio.PlaylistsColumns.DATA, MediaStore.Audio.PlaylistsColumns.DATE_ADDED, MediaStore.Audio.PlaylistsColumns.DATE_MODIFIED, }; ContentResolver cr = JukefoxApplication.getAppContext().getContentResolver(); List<PlaylistInfo> playlists = new ArrayList<PlaylistInfo>(); playlists.addAll(getPlaylists(projection, cr, MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI)); Log.v(TAG, "Number of external playlists found: " + playlists.size()); try { playlists.addAll(getPlaylists(projection, cr, MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI)); } catch (Throwable e) { Log.w(TAG, e); } Log.v(TAG, "Number of playlists (internal + external) found: " + playlists.size()); return playlists; } private List<PlaylistInfo> getPlaylists(String[] projection, ContentResolver cr, Uri uri) { List<PlaylistInfo> playlists = new ArrayList<PlaylistImporter.PlaylistInfo>(); Cursor cur = null; try { cur = cr.query(uri, projection, null, null, null); while (cur.moveToNext()) { String name = cur.getString(0); String data = cur.getString(1); if (!isValidFile(data)) { continue; } Date dateAdded = null; Date dateModified = null; try { String dateAddedStr = cur.getString(2); String dateModifiedStr = cur.getString(3); dateAdded = new Date(dateAddedStr); dateModified = new Date(dateModifiedStr); } catch (Exception e) { Log.w(TAG, e); } playlists.add(new PlaylistInfo(data, name, dateModified, dateAdded)); } return playlists; } finally { if (cur != null) { cur.close(); } } } private boolean isValidFile(String data) { if (data == null) { return false; } File file = new File(data); return file.exists() && !file.isDirectory(); } public ImportedPlaylist parse(PlaylistInfo info) throws IOException { Log.v(TAG, "parse"); String parentPath = getParentPathOrRoot(info.getPath()); ImportedPlaylist playlist = new ImportedPlaylist(); playlist.setPlaylistName(info.getName()); playlist.setPath(info.getPath()); playlist.setDateAdded(info.getDateAdded()); parsePlaylistFile(playlist, info.getPath(), parentPath); return playlist; } private String getParentPathOrRoot(String path) { String parentPath = new File(path).getParent(); if (parentPath == null) { // root (TODO: correct?) parentPath = "/"; } else { parentPath = new File(parentPath).getAbsolutePath(); } return parentPath; } private void parsePlaylistFile(ImportedPlaylist playlist, String path, String parentPath) throws FileNotFoundException, IOException { FileReader fileReader = new FileReader(path); BufferedReader br = new BufferedReader(fileReader); Log.v(TAG, "reading playlist at: " + path); try { String line; while ((line = br.readLine()) != null) { try { Log.v(TAG, "parsing line: " + line); String convertedLine = convertLine(playlist, parentPath, line); // Log.v(TAG, "converted: " + convertedLine); if (convertedLine == null) { continue; } if (!AndroidUtils.fileExists(convertedLine)) { playlist.incInvalidSongPathCnt(); continue; } PlaylistSong<BaseArtist, BaseAlbum> song = collectionModel.getSongProvider().getSongForPath( convertedLine, true); if (song == null) { // Check if song path is misspelled (case - Windows // systems ignore this) song = collectionModel.getSongProvider().getSongForPath(convertedLine, false); } if (song == null) { Log.v(TAG, "no song found for path: " + convertedLine); playlist.incInvalidSongPathCnt(); continue; } playlist.appendSongAtEnd(song); } catch (Exception e) { e.printStackTrace(); playlist.incUnrecognizedLineCnt(); } } } finally { br.close(); fileReader.close(); } } private String convertLine(ImportedPlaylist playlist, String parentPath, String line) { if (line == null) { playlist.incUnrecognizedLineCnt(); return null; } if (line.trim().equals("") || line.trim().startsWith("#")) { return null; } if (line.trim().startsWith("http://")) { playlist.incUrlCnt(); return null; // url } if (line.trim().substring(1, 3).equals(":\\")) { playlist.incWindowsPathCnt(); return null; // Windows absolute path } String[] tokens = line.split("#"); if (tokens[0].trim().endsWith(".m3u")) { playlist.incEmbeddedPlaylistCnt(); } if (line.trim().startsWith("/")) { // absolute path => should also work on jukefox return line.trim(); } if (line.trim().startsWith("../")) { while (line.trim().startsWith("../")) { parentPath = getParentPathOrRoot(parentPath); line = line.trim().substring(3).trim(); } return parentPath + "/" + line; } if (line.trim().startsWith("./")) { return parentPath + "/" + line.substring(2); } return parentPath + "/" + line.trim(); } }