- Use external library chamelon (lizzy) - Adds the ability to specify playlist export format - Fixes some deficiences with playlist handling Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>master
parent
e36d64dc04
commit
9584bfaea5
@ -0,0 +1,49 @@ |
||||
package org.libresonic.player.service.playlist; |
||||
|
||||
import chameleon.content.Content; |
||||
import chameleon.playlist.Media; |
||||
import chameleon.playlist.Playlist; |
||||
import chameleon.playlist.SpecificPlaylist; |
||||
import chameleon.playlist.SpecificPlaylistProvider; |
||||
import org.libresonic.player.dao.MediaFileDao; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import java.util.List; |
||||
|
||||
@Component |
||||
public class DefaultPlaylistExportHandler implements PlaylistExportHandler { |
||||
|
||||
@Autowired |
||||
MediaFileDao mediaFileDao; |
||||
|
||||
@Override |
||||
public boolean canHandle(Class<? extends SpecificPlaylistProvider> providerClass) { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public SpecificPlaylist handle(int id, SpecificPlaylistProvider provider) throws Exception { |
||||
chameleon.playlist.Playlist playlist = createChameleonGenericPlaylistFromDBId(id); |
||||
return provider.toSpecificPlaylist(playlist); |
||||
} |
||||
|
||||
Playlist createChameleonGenericPlaylistFromDBId(int id) { |
||||
Playlist newPlaylist = new Playlist(); |
||||
List<MediaFile> files = mediaFileDao.getFilesInPlaylist(id); |
||||
files.forEach(file -> { |
||||
Media component = new Media(); |
||||
Content content = new Content(file.getPath()); |
||||
component.setSource(content); |
||||
newPlaylist.getRootSequence().addComponent(component); |
||||
}); |
||||
return newPlaylist; |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return Ordered.LOWEST_PRECEDENCE; |
||||
} |
||||
} |
@ -0,0 +1,97 @@ |
||||
package org.libresonic.player.service.playlist; |
||||
|
||||
import chameleon.playlist.*; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.libresonic.player.service.MediaFileService; |
||||
import org.libresonic.player.util.Pair; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import java.io.File; |
||||
import java.net.URI; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
@Component |
||||
public class DefaultPlaylistImportHandler implements PlaylistImportHandler { |
||||
|
||||
@Autowired |
||||
MediaFileService mediaFileService; |
||||
|
||||
@Override |
||||
public boolean canHandle(Class<? extends SpecificPlaylist> playlistClass) { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public Pair<List<MediaFile>, List<String>> handle( |
||||
SpecificPlaylist inputSpecificPlaylist |
||||
) { |
||||
List<MediaFile> mediaFiles = new ArrayList<>(); |
||||
List<String> errors = new ArrayList<>(); |
||||
try { |
||||
inputSpecificPlaylist.toPlaylist().acceptDown(new PlaylistVisitor() { |
||||
@Override |
||||
public void beginVisitPlaylist(Playlist playlist) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void endVisitPlaylist(Playlist playlist) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void beginVisitParallel(Parallel parallel) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void endVisitParallel(Parallel parallel) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void beginVisitSequence(Sequence sequence) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void endVisitSequence(Sequence sequence) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void beginVisitMedia(Media media) throws Exception { |
||||
try { |
||||
URI uri = media.getSource().getURI(); |
||||
File file = new File(uri); |
||||
MediaFile mediaFile = mediaFileService.getMediaFile(file); |
||||
if(mediaFile != null) { |
||||
mediaFiles.add(mediaFile); |
||||
} else { |
||||
errors.add("Cannot find media file " + file); |
||||
} |
||||
} catch (Exception e) { |
||||
errors.add(e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void endVisitMedia(Media media) throws Exception { |
||||
|
||||
} |
||||
}); |
||||
} catch (Exception e) { |
||||
errors.add(e.getMessage()); |
||||
} |
||||
|
||||
return Pair.create(mediaFiles, errors); |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return Ordered.LOWEST_PRECEDENCE; |
||||
} |
||||
} |
@ -0,0 +1,11 @@ |
||||
package org.libresonic.player.service.playlist; |
||||
|
||||
import chameleon.playlist.SpecificPlaylist; |
||||
import chameleon.playlist.SpecificPlaylistProvider; |
||||
import org.springframework.core.Ordered; |
||||
|
||||
public interface PlaylistExportHandler extends Ordered { |
||||
boolean canHandle(Class<? extends SpecificPlaylistProvider> providerClass); |
||||
|
||||
SpecificPlaylist handle(int id, SpecificPlaylistProvider provider) throws Exception; |
||||
} |
@ -0,0 +1,14 @@ |
||||
package org.libresonic.player.service.playlist; |
||||
|
||||
import chameleon.playlist.SpecificPlaylist; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.libresonic.player.util.Pair; |
||||
import org.springframework.core.Ordered; |
||||
|
||||
import java.util.List; |
||||
|
||||
public interface PlaylistImportHandler extends Ordered { |
||||
boolean canHandle(Class<? extends SpecificPlaylist> playlistClass); |
||||
|
||||
Pair<List<MediaFile>,List<String>> handle(SpecificPlaylist inputSpecificPlaylist); |
||||
} |
@ -0,0 +1,66 @@ |
||||
package org.libresonic.player.service.playlist; |
||||
|
||||
import chameleon.playlist.SpecificPlaylist; |
||||
import chameleon.playlist.SpecificPlaylistProvider; |
||||
import chameleon.playlist.xspf.Location; |
||||
import chameleon.playlist.xspf.Track; |
||||
import chameleon.playlist.xspf.XspfProvider; |
||||
import org.libresonic.player.dao.MediaFileDao; |
||||
import org.libresonic.player.dao.PlaylistDao; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
@Component |
||||
public class XspfPlaylistExportHandler implements PlaylistExportHandler { |
||||
|
||||
@Autowired |
||||
MediaFileDao mediaFileDao; |
||||
|
||||
@Autowired |
||||
PlaylistDao playlistDao; |
||||
|
||||
@Override |
||||
public boolean canHandle(Class<? extends SpecificPlaylistProvider> providerClass) { |
||||
return XspfProvider.class.equals(providerClass); |
||||
} |
||||
|
||||
@Override |
||||
public SpecificPlaylist handle(int id, SpecificPlaylistProvider provider) throws Exception { |
||||
chameleon.playlist.xspf.Playlist playlist = createXsfpPlaylistFromDBId(id); |
||||
return playlist; |
||||
} |
||||
|
||||
chameleon.playlist.xspf.Playlist createXsfpPlaylistFromDBId(int id) { |
||||
chameleon.playlist.xspf.Playlist newPlaylist = new chameleon.playlist.xspf.Playlist(); |
||||
org.libresonic.player.domain.Playlist playlist = playlistDao.getPlaylist(id); |
||||
newPlaylist.setTitle(playlist.getName()); |
||||
newPlaylist.setCreator("Libresonic user " + playlist.getUsername()); |
||||
newPlaylist.setDate(new Date()); |
||||
List<MediaFile> files = mediaFileDao.getFilesInPlaylist(id); |
||||
|
||||
files.stream().map(mediaFile -> { |
||||
Track track = new Track(); |
||||
track.setTrackNumber(mediaFile.getTrackNumber()); |
||||
track.setCreator(mediaFile.getArtist()); |
||||
track.setTitle(mediaFile.getTitle()); |
||||
track.setAlbum(mediaFile.getAlbumName()); |
||||
track.setDuration(mediaFile.getDurationSeconds()); |
||||
track.setImage(mediaFile.getCoverArtPath()); |
||||
Location location = new Location(); |
||||
location.setText(mediaFile.getPath()); |
||||
track.getStringContainers().add(location); |
||||
return track; |
||||
}).forEach(newPlaylist::addTrack); |
||||
|
||||
return newPlaylist; |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return 0; |
||||
} |
||||
} |
@ -0,0 +1,73 @@ |
||||
package org.libresonic.player.service.playlist; |
||||
|
||||
import chameleon.playlist.SpecificPlaylist; |
||||
import chameleon.playlist.xspf.Location; |
||||
import chameleon.playlist.xspf.Playlist; |
||||
import chameleon.playlist.xspf.StringContainer; |
||||
import org.libresonic.player.Logger; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.libresonic.player.service.MediaFileService; |
||||
import org.libresonic.player.util.Pair; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import java.io.File; |
||||
import java.net.URI; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.stream.Collectors; |
||||
|
||||
@Component |
||||
public class XspfPlaylistImportHandler implements PlaylistImportHandler { |
||||
|
||||
private static final Logger LOG = Logger.getLogger(XspfPlaylistImportHandler.class); |
||||
|
||||
@Autowired |
||||
MediaFileService mediaFileService; |
||||
|
||||
@Override |
||||
public boolean canHandle(Class<? extends SpecificPlaylist> playlistClass) { |
||||
return Playlist.class.equals(playlistClass); |
||||
} |
||||
|
||||
@Override |
||||
public Pair<List<MediaFile>, List<String>> handle(SpecificPlaylist inputSpecificPlaylist) { |
||||
List<MediaFile> mediaFiles = new ArrayList<>(); |
||||
List<String> errors = new ArrayList<>(); |
||||
Playlist xspfPlaylist = (Playlist) inputSpecificPlaylist; |
||||
xspfPlaylist.getTracks().forEach(track -> { |
||||
MediaFile mediaFile = null; |
||||
for(StringContainer sc : track.getStringContainers()) { |
||||
if(sc instanceof Location) { |
||||
Location location = (Location) sc; |
||||
try { |
||||
File file = new File(new URI(location.getText())); |
||||
mediaFile = mediaFileService.getMediaFile(file); |
||||
} catch (Exception ignored) {} |
||||
|
||||
if(mediaFile == null) { |
||||
try { |
||||
File file = new File(sc.getText()); |
||||
mediaFile = mediaFileService.getMediaFile(file); |
||||
} catch (Exception ignored) {} |
||||
} |
||||
} |
||||
} |
||||
if(mediaFile != null) { |
||||
mediaFiles.add(mediaFile); |
||||
} else { |
||||
String errorMsg = "Could not find media file matching "; |
||||
try { |
||||
errorMsg += track.getStringContainers().stream().map(StringContainer::getText).collect(Collectors.joining(",")); |
||||
} catch (Exception ignored) {} |
||||
errors.add(errorMsg); |
||||
} |
||||
}); |
||||
return Pair.create(mediaFiles, errors); |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return 40; |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
# First one, as it is a binary format that can easily be recognized. |
||||
chameleon.playlist.pla.PLAProvider |
||||
chameleon.playlist.asx.AsxProvider |
||||
chameleon.playlist.b4s.B4sProvider |
||||
# BEFORE SMIL (same root element). |
||||
chameleon.playlist.wpl.WplProvider |
||||
chameleon.playlist.smil.SmilProvider |
||||
chameleon.playlist.rss.RSSProvider |
||||
chameleon.playlist.atom.AtomProvider |
||||
# Before XSPF, because this format is very close to XSPF, |
||||
# but its XML format is strictly checked (and XSPF's format is not) |
||||
chameleon.playlist.hypetape.HypetapeProvider |
||||
chameleon.playlist.xspf.XspfProvider |
||||
chameleon.playlist.rmp.RmpProvider |
||||
chameleon.playlist.plist.PlistProvider |
||||
chameleon.playlist.kpl.KplProvider |
||||
chameleon.playlist.pls.PLSProvider |
||||
chameleon.playlist.mpcpl.MPCPLProvider |
||||
chameleon.playlist.plp.PLPProvider |
||||
# Shall be last, as the M3U format can match almost everything. |
||||
chameleon.playlist.m3u.M3UProvider |
@ -0,0 +1,108 @@ |
||||
package org.libresonic.player.service; |
||||
|
||||
import com.google.common.collect.Lists; |
||||
import org.apache.commons.io.IOUtils; |
||||
import org.apache.commons.io.output.ByteArrayOutputStream; |
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
import org.junit.runner.RunWith; |
||||
import org.libresonic.player.dao.MediaFileDao; |
||||
import org.libresonic.player.dao.PlaylistDao; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.libresonic.player.domain.Playlist; |
||||
import org.libresonic.player.service.playlist.DefaultPlaylistExportHandler; |
||||
import org.mockito.ArgumentCaptor; |
||||
import org.mockito.Captor; |
||||
import org.mockito.InjectMocks; |
||||
import org.mockito.Mock; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class PlaylistServiceTestExport { |
||||
|
||||
PlaylistService playlistService; |
||||
|
||||
@InjectMocks |
||||
DefaultPlaylistExportHandler defaultPlaylistExportHandler; |
||||
|
||||
@Mock |
||||
MediaFileDao mediaFileDao; |
||||
|
||||
@Mock |
||||
PlaylistDao playlistDao; |
||||
|
||||
@Mock |
||||
MediaFileService mediaFileService; |
||||
|
||||
@Mock |
||||
SettingsService settingsService; |
||||
|
||||
@Mock |
||||
SecurityService securityService; |
||||
|
||||
@Rule |
||||
public TemporaryFolder folder = new TemporaryFolder(); |
||||
|
||||
@Captor |
||||
ArgumentCaptor<Playlist> actual; |
||||
|
||||
@Captor |
||||
ArgumentCaptor<List<MediaFile>> medias; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
playlistService = new PlaylistService(mediaFileDao, |
||||
playlistDao, |
||||
securityService, |
||||
settingsService, |
||||
Lists.newArrayList( |
||||
defaultPlaylistExportHandler), |
||||
Collections.emptyList()); |
||||
} |
||||
|
||||
@Test |
||||
public void testExportToM3U() throws Exception { |
||||
|
||||
when(mediaFileDao.getFilesInPlaylist(eq(23))).thenReturn(getPlaylistFiles()); |
||||
when(settingsService.getPlaylistExportFormat()).thenReturn("m3u"); |
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
||||
playlistService.exportPlaylist(23, outputStream); |
||||
String actual = outputStream.toString(); |
||||
Assert.assertEquals(IOUtils.toString(getClass().getResourceAsStream("/PLAYLISTS/23.m3u")), actual); |
||||
} |
||||
|
||||
private List<MediaFile> getPlaylistFiles() { |
||||
List<MediaFile> mediaFiles = new ArrayList<>(); |
||||
|
||||
MediaFile mf1 = new MediaFile(); |
||||
mf1.setId(142); |
||||
mf1.setPath("/some/path/to_album/to_artist/name - of - song.mp3"); |
||||
mf1.setPresent(true); |
||||
mediaFiles.add(mf1); |
||||
|
||||
MediaFile mf2 = new MediaFile(); |
||||
mf2.setId(1235); |
||||
mf2.setPath("/some/path/to_album2/to_artist/another song.mp3"); |
||||
mf2.setPresent(true); |
||||
mediaFiles.add(mf2); |
||||
|
||||
MediaFile mf3 = new MediaFile(); |
||||
mf3.setId(198403); |
||||
mf3.setPath("/some/path/to_album2/to_artist/another song2.mp3"); |
||||
mf3.setPresent(false); |
||||
mediaFiles.add(mf3); |
||||
|
||||
return mediaFiles; |
||||
} |
||||
} |
@ -0,0 +1,210 @@ |
||||
package org.libresonic.player.service; |
||||
|
||||
import com.google.common.collect.Lists; |
||||
import org.apache.commons.io.FileUtils; |
||||
import org.apache.commons.lang3.builder.EqualsBuilder; |
||||
import org.apache.commons.lang3.builder.ToStringBuilder; |
||||
import org.junit.Before; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
import org.junit.runner.RunWith; |
||||
import org.libresonic.player.dao.MediaFileDao; |
||||
import org.libresonic.player.dao.PlaylistDao; |
||||
import org.libresonic.player.domain.MediaFile; |
||||
import org.libresonic.player.domain.Playlist; |
||||
import org.libresonic.player.service.playlist.DefaultPlaylistExportHandler; |
||||
import org.libresonic.player.service.playlist.DefaultPlaylistImportHandler; |
||||
import org.mockito.ArgumentCaptor; |
||||
import org.mockito.Captor; |
||||
import org.mockito.InjectMocks; |
||||
import org.mockito.Mock; |
||||
import org.mockito.invocation.InvocationOnMock; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
import org.mockito.stubbing.Answer; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.File; |
||||
import java.io.InputStream; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertTrue; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.Mockito.*; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class PlaylistServiceTestImport { |
||||
|
||||
PlaylistService playlistService; |
||||
|
||||
@InjectMocks |
||||
DefaultPlaylistImportHandler defaultPlaylistImportHandler; |
||||
|
||||
@Mock |
||||
MediaFileDao mediaFileDao; |
||||
|
||||
@Mock |
||||
PlaylistDao playlistDao; |
||||
|
||||
@Mock |
||||
MediaFileService mediaFileService; |
||||
|
||||
@Mock |
||||
SettingsService settingsService; |
||||
|
||||
@Mock |
||||
SecurityService securityService; |
||||
|
||||
@Rule |
||||
public TemporaryFolder folder = new TemporaryFolder(); |
||||
|
||||
@Captor |
||||
ArgumentCaptor<Playlist> actual; |
||||
|
||||
@Captor |
||||
ArgumentCaptor<List<MediaFile>> medias; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
playlistService = new PlaylistService( |
||||
mediaFileDao, |
||||
playlistDao, |
||||
securityService, |
||||
settingsService, |
||||
Collections.emptyList(), |
||||
Lists.newArrayList(defaultPlaylistImportHandler)); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testImportFromM3U() throws Exception { |
||||
String username = "testUser"; |
||||
String playlistName = "test-playlist"; |
||||
StringBuilder builder = new StringBuilder(); |
||||
builder.append("#EXTM3U\n"); |
||||
File mf1 = folder.newFile(); |
||||
FileUtils.touch(mf1); |
||||
File mf2 = folder.newFile(); |
||||
FileUtils.touch(mf2); |
||||
File mf3 = folder.newFile(); |
||||
FileUtils.touch(mf3); |
||||
builder.append(mf1.getAbsolutePath() + "\n"); |
||||
builder.append(mf2.getAbsolutePath() + "\n"); |
||||
builder.append(mf3.getAbsolutePath() + "\n"); |
||||
doAnswer(new PersistPlayList(23)).when(playlistDao).createPlaylist(any()); |
||||
doAnswer(new MediaFileHasEverything()).when(mediaFileService).getMediaFile(any(File.class)); |
||||
InputStream inputStream = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); |
||||
String path = "/path/to/"+playlistName+".m3u"; |
||||
playlistService.importPlaylist(username, playlistName, path, inputStream, null); |
||||
verify(playlistDao).createPlaylist(actual.capture()); |
||||
verify(playlistDao).setFilesInPlaylist(eq(23), medias.capture()); |
||||
Playlist expected = new Playlist(); |
||||
expected.setUsername(username); |
||||
expected.setName(playlistName); |
||||
expected.setComment("Auto-imported from " + path); |
||||
expected.setImportedFrom(path); |
||||
expected.setShared(true); |
||||
expected.setId(23); |
||||
assertTrue("\n" + ToStringBuilder.reflectionToString(actual.getValue()) + "\n\n did not equal \n\n" + ToStringBuilder.reflectionToString(expected), EqualsBuilder.reflectionEquals(actual.getValue(), expected, "created", "changed")); |
||||
List<MediaFile> mediaFiles = medias.getValue(); |
||||
assertEquals(3, mediaFiles.size()); |
||||
} |
||||
|
||||
@Test |
||||
public void testImportFromPLS() throws Exception { |
||||
String username = "testUser"; |
||||
String playlistName = "test-playlist"; |
||||
StringBuilder builder = new StringBuilder(); |
||||
builder.append("[playlist]\n"); |
||||
File mf1 = folder.newFile(); |
||||
FileUtils.touch(mf1); |
||||
File mf2 = folder.newFile(); |
||||
FileUtils.touch(mf2); |
||||
File mf3 = folder.newFile(); |
||||
FileUtils.touch(mf3); |
||||
builder.append("File1=" + mf1.getAbsolutePath() + "\n"); |
||||
builder.append("File2=" + mf2.getAbsolutePath() + "\n"); |
||||
builder.append("File3=" + mf3.getAbsolutePath() + "\n"); |
||||
doAnswer(new PersistPlayList(23)).when(playlistDao).createPlaylist(any()); |
||||
doAnswer(new MediaFileHasEverything()).when(mediaFileService).getMediaFile(any(File.class)); |
||||
InputStream inputStream = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); |
||||
String path = "/path/to/"+playlistName+".pls"; |
||||
playlistService.importPlaylist(username, playlistName, path, inputStream, null); |
||||
verify(playlistDao).createPlaylist(actual.capture()); |
||||
verify(playlistDao).setFilesInPlaylist(eq(23), medias.capture()); |
||||
Playlist expected = new Playlist(); |
||||
expected.setUsername(username); |
||||
expected.setName(playlistName); |
||||
expected.setComment("Auto-imported from " + path); |
||||
expected.setImportedFrom(path); |
||||
expected.setShared(true); |
||||
expected.setId(23); |
||||
assertTrue("\n" + ToStringBuilder.reflectionToString(actual.getValue()) + "\n\n did not equal \n\n" + ToStringBuilder.reflectionToString(expected), EqualsBuilder.reflectionEquals(actual.getValue(), expected, "created", "changed")); |
||||
List<MediaFile> mediaFiles = medias.getValue(); |
||||
assertEquals(3, mediaFiles.size()); |
||||
} |
||||
|
||||
@Test |
||||
public void testImportFromXSPF() throws Exception { |
||||
String username = "testUser"; |
||||
String playlistName = "test-playlist"; |
||||
StringBuilder builder = new StringBuilder(); |
||||
builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
||||
+ "<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\">\n" |
||||
+ " <trackList>\n"); |
||||
File mf1 = folder.newFile(); |
||||
FileUtils.touch(mf1); |
||||
File mf2 = folder.newFile(); |
||||
FileUtils.touch(mf2); |
||||
File mf3 = folder.newFile(); |
||||
FileUtils.touch(mf3); |
||||
builder.append("<track><location>file://" + mf1.getAbsolutePath() + "</location></track>\n"); |
||||
builder.append("<track><location>file://" + mf2.getAbsolutePath() + "</location></track>\n"); |
||||
builder.append("<track><location>file://" + mf3.getAbsolutePath() + "</location></track>\n"); |
||||
builder.append(" </trackList>\n" + "</playlist>\n"); |
||||
doAnswer(new PersistPlayList(23)).when(playlistDao).createPlaylist(any()); |
||||
doAnswer(new MediaFileHasEverything()).when(mediaFileService).getMediaFile(any(File.class)); |
||||
InputStream inputStream = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); |
||||
String path = "/path/to/"+playlistName+".xspf"; |
||||
playlistService.importPlaylist(username, playlistName, path, inputStream, null); |
||||
verify(playlistDao).createPlaylist(actual.capture()); |
||||
verify(playlistDao).setFilesInPlaylist(eq(23), medias.capture()); |
||||
Playlist expected = new Playlist(); |
||||
expected.setUsername(username); |
||||
expected.setName(playlistName); |
||||
expected.setComment("Auto-imported from " + path); |
||||
expected.setImportedFrom(path); |
||||
expected.setShared(true); |
||||
expected.setId(23); |
||||
assertTrue("\n" + ToStringBuilder.reflectionToString(actual.getValue()) + "\n\n did not equal \n\n" + ToStringBuilder.reflectionToString(expected), EqualsBuilder.reflectionEquals(actual.getValue(), expected, "created", "changed")); |
||||
List<MediaFile> mediaFiles = medias.getValue(); |
||||
assertEquals(3, mediaFiles.size()); |
||||
} |
||||
|
||||
private class PersistPlayList implements Answer { |
||||
private final int id; |
||||
public PersistPlayList(int id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
@Override |
||||
public Object answer(InvocationOnMock invocationOnMock) throws Throwable { |
||||
Playlist playlist = invocationOnMock.getArgument(0); |
||||
playlist.setId(id); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private class MediaFileHasEverything implements Answer { |
||||
|
||||
@Override |
||||
public Object answer(InvocationOnMock invocationOnMock) throws Throwable { |
||||
File file = invocationOnMock.getArgument(0); |
||||
MediaFile mediaFile = new MediaFile(); |
||||
mediaFile.setPath(file.getPath()); |
||||
return mediaFile; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,3 @@ |
||||
/some/path/to_album/to_artist/name - of - song.mp3 |
||||
/some/path/to_album2/to_artist/another song.mp3 |
||||
/some/path/to_album2/to_artist/another song2.mp3 |
@ -0,0 +1,6 @@ |
||||
[playlist] |
||||
File1=/some/path/to_album/to_artist/name - of - song.mp3 |
||||
File2=/some/path/to_album2/to_artist/another song.mp3 |
||||
File3=/some/path/to_album2/to_artist/another song2.mp3 |
||||
NumberOfEntries=3 |
||||
Version=2 |
@ -0,0 +1,8 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<playlist version="1" xmlns="http://xspf.org/ns/0/"> |
||||
<trackList> |
||||
<track><location>file:///some/path/to_album/to_artist/name - of - song.mp3</location></track> |
||||
<track><location>file:///some/path/to_album2/to_artist/another song.mp3</location></track> |
||||
<track><location>file:///some/path/to_album2/to_artist/another song2.mp3</location></track> |
||||
</trackList> |
||||
</playlist> |
Loading…
Reference in new issue