Skip to content
This repository has been archived by the owner on Dec 27, 2021. It is now read-only.

Commit

Permalink
Merge pull request #22 from vmichalak/feature/todidlmetadata
Browse files Browse the repository at this point in the history
Close #21 - Add toDIDL() method, replace metadata strings by TrackMetadata
  • Loading branch information
vmichalak authored Nov 9, 2017
2 parents f9c166f + e996271 commit 2c93ab3
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 19 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile group: 'org.mockito', name: 'mockito-core', version: '1.10.8'
testCompile group: 'org.powermock', name: 'powermock-mockito-release-full', version: '1.6.4'
testCompile 'com.squareup.okhttp3:mockwebserver:3.9.0'
testRuntime "org.slf4j:slf4j-api:1.7.10"
}
21 changes: 13 additions & 8 deletions src/main/java/com/vmichalak/sonoscontroller/SonosDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,26 @@ public void play() throws IOException, SonosControllerException {
/**
* Play a given stream. Pauses the queue.
* @param uri URI of a stream to be played.
* @param meta The track metadata to show in the player (DIDL format).
* @param metadata The track metadata to show in the player (DIDL format).
* @throws IOException
* @throws SonosControllerException
*/
public void playUri(String uri, String metadata) throws IOException, SonosControllerException {
public void playUri(String uri, TrackMetadata metadata) throws IOException, SonosControllerException {
String metadataString = "";
if(metadata != null) { metadataString = metadata.toDIDL(); }
CommandBuilder.transport("SetAVTransportURI").put("InstanceID", "0").put("CurrentURI", uri)
.put("CurrentURIMetaData", metadata).executeOn(this.ip);
.put("CurrentURIMetaData", metadataString).executeOn(this.ip);
this.play();
}


/**
* Play an item from the queue.
* @param queueIndex >= 0
*/
public void playFromQueue(int queueIndex) throws IOException, SonosControllerException {
if(queueIndex < 0) { throw new IllegalArgumentException("Queue index cannot be < 0."); }
this.playUri("x-rincon-queue:" + this.getSpeakerInfo().getLocalUID() + "#0", "");
this.playUri("x-rincon-queue:" + this.getSpeakerInfo().getLocalUID() + "#0", null);
CommandBuilder.transport("Seek").put("InstanceID", "0").put("Unit", "TRACK_NR")
.put("Target", String.valueOf(queueIndex)).executeOn(this.ip);
this.play();
Expand All @@ -61,12 +64,12 @@ public void playFromQueue(int queueIndex) throws IOException, SonosControllerExc
* @throws SonosControllerException
* @throws InterruptedException
*/
public void clip(String uri, String metadata) throws IOException, SonosControllerException, InterruptedException {
public void clip(String uri, TrackMetadata metadata) throws IOException, SonosControllerException, InterruptedException {
PlayState previousState = this.getPlayState();
TrackInfo previous = this.getCurrentTrackInfo();
this.playUri(uri, metadata);
while (!this.getPlayState().equals(PlayState.STOPPED)) { Thread.sleep(500); }
this.playUri("x-rincon-queue:" + this.getSpeakerInfo().getLocalUID() + "#0", "");
this.playUri("x-rincon-queue:" + this.getSpeakerInfo().getLocalUID() + "#0", null);
CommandBuilder.transport("Seek").put("InstanceID", "0").put("Unit", "TRACK_NR")
.put("Target", String.valueOf(previous.getQueueIndex())).executeOn(this.ip);
this.seek(previous.getPosition());
Expand Down Expand Up @@ -138,9 +141,11 @@ public void previous() throws IOException, SonosControllerException {
* @throws IOException
* @throws SonosControllerException
*/
public void addToQueue(String uri, String metadata) throws IOException, SonosControllerException {
public void addToQueue(String uri, TrackMetadata metadata) throws IOException, SonosControllerException {
String metadataString = "";
if(metadata != null) { metadataString = metadata.toDIDL(); }
CommandBuilder.transport("AddURIToQueue").put("InstanceID", "0").put("EnqueuedURI", uri)
.put("EnqueuedURIMetaData", metadata).put("DesiredFirstTrackNumberEnqueued", "0")
.put("EnqueuedURIMetaData", metadataString).put("DesiredFirstTrackNumberEnqueued", "0")
.put("EnqueueAsNext", "1").executeOn(this.ip);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.vmichalak.sonoscontroller.model;

import com.vmichalak.sonoscontroller.ParserHelper;
import org.apache.commons.text.StringEscapeUtils;

public class TrackMetadata {
private final String title;
Expand Down Expand Up @@ -57,4 +58,16 @@ public String toString() {
", albumArtURI='" + albumArtURI + '\'' +
'}';
}

public String toDIDL() {
return "<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:r=\"urn:schemas-rinconnetworks-com:metadata-1-0/\" xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\">" +
"<item>" +
"<dc:title>" + title + "</dc:title>" +
"<dc:creator>" + creator + "</dc:creator>" +
"<dc:albumArtist>" + albumArtist + "</dc:albumArtist>" +
"<upnp:album>" + album + "</upnp:album>" +
"<upnp:albumArtURI>" + albumArtURI + "</upnp:albumArtURI>" +
"</item>" +
"</DIDL-Lite>";
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package com.vmichalak.sonoscontroller;

import com.vmichalak.sonoscontroller.exception.SonosControllerException;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.Test;

import java.io.IOException;

import static org.junit.Assert.assertEquals;

public class CommandBuilderTest {
Expand All @@ -22,4 +27,21 @@ public void alreadyEscaped() {
assertEquals(expected, CommandBuilder.transport("test").put("a", escaped).getBody());
}

@Test
public void otherAlreadyEscapedTest() {
assertEquals("<a>aa&lt;bbcc</a>", CommandBuilder.transport("test").put("a", "aa&lt;bbcc").getBody());
assertEquals("<a>aadze&gt;bbcc</a>", CommandBuilder.transport("test").put("a", "aadze&gt;bbcc").getBody());
assertEquals("<a>sssaa&quot;bbcc</a>", CommandBuilder.transport("test").put("a", "sssaa&quot;bbcc").getBody());
assertEquals("<a>sqsda&apos;bbqdc</a>", CommandBuilder.transport("test").put("a", "sqsda&apos;bbqdc").getBody());
}

@Test
public void unescape() throws IOException, SonosControllerException {
MockWebServer server = new MockWebServer();
server.enqueue(new MockResponse().setBody("hello &amp;quot;world&amp;quot; !"));
server.start(1400);
String s = CommandBuilder.transport("test").put("a", "a").executeOn("127.0.0.1");
assertEquals("hello \"world\" !", s);
server.shutdown();
}
}
19 changes: 13 additions & 6 deletions src/test/java/com/vmichalak/sonoscontroller/SonosDeviceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import com.vmichalak.sonoscontroller.exception.SonosControllerException;
import com.vmichalak.sonoscontroller.exception.UPnPSonosControllerException;
import com.vmichalak.sonoscontroller.model.PlayMode;
import com.vmichalak.sonoscontroller.model.PlayState;
import com.vmichalak.sonoscontroller.model.SonosSpeakerInfo;
import com.vmichalak.sonoscontroller.model.SonosZoneInfo;
import com.vmichalak.sonoscontroller.model.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
Expand Down Expand Up @@ -82,6 +79,12 @@ public void getTreble() throws Exception {
assertEquals(-1, new SonosDevice("127.0.0.1").getTreble());
}

@Test(expected = IllegalArgumentException.class)
public void setInvalidQueueIndex() throws Exception {
MockHelper.mockCommandBuilder("");
new SonosDevice("127.0.0.1").playFromQueue(-1);
}

@Test(expected = IllegalArgumentException.class)
public void setInvalidTrebleValue() throws Exception {
MockHelper.mockCommandBuilder("");
Expand Down Expand Up @@ -581,7 +584,7 @@ public void checkCommandBuilderUsage() throws Exception {
SonosDevice sonosDevice = new SonosDevice("127.0.0.1");

sonosDevice.play();
sonosDevice.playUri("http://test.com", "");
sonosDevice.playUri("http://test.com", new TrackMetadata("", "", "", "", ""));
sonosDevice.pause();
sonosDevice.stop();
sonosDevice.seek("01:01:01");
Expand All @@ -593,15 +596,19 @@ public void checkCommandBuilderUsage() throws Exception {
sonosDevice.unjoin();
sonosDevice.setVolume(100);
sonosDevice.setMute(true);
sonosDevice.setMute(false);
sonosDevice.switchMute();
sonosDevice.setLoudness(true);
sonosDevice.setLoudness(false);
sonosDevice.setTreble(8);
sonosDevice.setNightMode(true);
sonosDevice.setZoneName("test");
sonosDevice.setLedState(true);
sonosDevice.setLedState(false);
sonosDevice.setDialogMode(true);
sonosDevice.setDialogMode(false);

Mockito.verify(commandBuilderMock, Mockito.times(21)).executeOn("127.0.0.1");
Mockito.verify(commandBuilderMock, Mockito.times(26)).executeOn("127.0.0.1");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.vmichalak.sonoscontroller.exception.UPnPSonosControllerException;
import com.vmichalak.sonoscontroller.model.PlayMode;
import com.vmichalak.sonoscontroller.model.PlayState;
import com.vmichalak.sonoscontroller.model.TrackMetadata;
import com.vmichalak.sonoscontroller.testcategory.UnmockedTest;
import org.junit.Before;
import org.junit.Test;
Expand Down Expand Up @@ -49,24 +50,30 @@ public void testPlayPauseStop() throws IOException, SonosControllerException, In
}
}

@Test
public void testPlayUri() throws IOException, SonosControllerException, InterruptedException {
sonosDevice.playUri("https://allthingsaudio.wikispaces.com/file/view/Shuffle%20for%20K.M.mp3/139190697/Shuffle%20for%20K.M.mp3",
new TrackMetadata("Shuffle Sample", "All Things Studio", "All Things Studio", "Integration tests with good sample music", "https://allthingsaudio.wikispaces.com/space/showlogo/1398536774/logo.png"));
}

@Test
public void testPlayMode() throws IOException, SonosControllerException, InterruptedException {
try {
PlayMode initialMode = sonosDevice.getPlayMode();
sonosDevice.setPlayMode(PlayMode.NORMAL);
Thread.sleep(100);
Thread.sleep(250);
assertEquals(PlayMode.NORMAL, sonosDevice.getPlayMode());
sonosDevice.setPlayMode(PlayMode.REPEAT_ALL);
Thread.sleep(100);
Thread.sleep(250);
assertEquals(PlayMode.REPEAT_ALL, sonosDevice.getPlayMode());
sonosDevice.setPlayMode(PlayMode.REPEAT_ONE);
Thread.sleep(100);
Thread.sleep(250);
assertEquals(PlayMode.REPEAT_ONE, sonosDevice.getPlayMode());
sonosDevice.setPlayMode(PlayMode.SHUFFLE);
Thread.sleep(100);
Thread.sleep(250);
assertEquals(PlayMode.SHUFFLE, sonosDevice.getPlayMode());
sonosDevice.setPlayMode(PlayMode.SHUFFLE_NOREPEAT);
Thread.sleep(100);
Thread.sleep(250);
assertEquals(PlayMode.SHUFFLE_NOREPEAT, sonosDevice.getPlayMode());
sonosDevice.setPlayMode(initialMode);
} catch (UPnPSonosControllerException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ public void parse() {
"<r:tiid>ed24b408301ad5d0e5271e1581023364</r:tiid>" +
"</item>" +
"</DIDL-Lite>";

TrackMetadata parsedMetadata = TrackMetadata.parse(metadataString);
assertEquals("Drunk In The Morning", parsedMetadata.getTitle());
assertEquals("Lukas Graham", parsedMetadata.getCreator());
assertEquals("Lukas Graham", parsedMetadata.getAlbumArtist());
assertEquals("Lukas Graham (Blue Album)", parsedMetadata.getAlbum());
assertEquals("https://i.scdn.co/image/581f4402e14ac0f839f7b50dff4fdd0bbc02bee5", parsedMetadata.getAlbumArtURI());
assertEquals("TrackMetadata{title='Drunk In The Morning', creator='Lukas Graham', albumArtist='Lukas Graham', album='Lukas Graham (Blue Album)', albumArtURI='https://i.scdn.co/image/581f4402e14ac0f839f7b50dff4fdd0bbc02bee5'}", parsedMetadata.toString());
assertEquals("<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:r=\"urn:schemas-rinconnetworks-com:metadata-1-0/\" xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\"><item><dc:title>Drunk In The Morning</dc:title><dc:creator>Lukas Graham</dc:creator><dc:albumArtist>Lukas Graham</dc:albumArtist><upnp:album>Lukas Graham (Blue Album)</upnp:album><upnp:albumArtURI>https://i.scdn.co/image/581f4402e14ac0f839f7b50dff4fdd0bbc02bee5</upnp:albumArtURI></item></DIDL-Lite>", parsedMetadata.toDIDL());
}
}

0 comments on commit 2c93ab3

Please sign in to comment.