aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--diagram.drawio2
-rw-r--r--player_vlc.py36
-rw-r--r--playlist.py4
-rw-r--r--playlist_unittest.py53
-rw-r--r--solo_tool.py37
-rw-r--r--solo_tool_integrationtest.py68
6 files changed, 166 insertions, 34 deletions
diff --git a/diagram.drawio b/diagram.drawio
index d671dd7..3fc9e3f 100644
--- a/diagram.drawio
+++ b/diagram.drawio
@@ -1 +1 @@
-<mxfile host="app.diagrams.net" modified="2021-12-21T07:22:08.107Z" agent="5.0 (X11)" etag="LSUaRkEzADL58n23WmbH" version="16.0.0" type="device"><diagram id="g-wcGVps3MkI6_XAwNEs" name="Page-1">5VxLd9o6EP41LMmxLb9YJiRN0pPc5lzaJunOYGHU2Ba1BYH++kpYxg8phBJs43qFNXrPzDcjjSR6YBisriNnPrvHLvR7muKueuCyp2mqagP6wyjrhGLpnOBFyOWFMsII/YacqHDqArkwLhQkGPsEzYvECQ5DOCEFmhNF+LVYbIr9Yq9zx4MCYTRxfJH6iFwyS+dlDrKMG4i8Ge/a1qwkI3DSwnwm8cxx8WuOBK56YBhhTJKvYDWEPmNeypek3qc3crcDi2BI9qlw/019Ho0vvl5Z4OXR8MLBr/73vsHHRtbphKFL58+TOCIz7OHQ8a8y6kWEF6ELWasKTWVl7jCeU6JKiT8hIWsuTGdBMCXNSODzXLhC5IlVP7MMnnzmrbHvy1U+sU4TIYnWT2kLLPGca4Kls3qbVFpR5BNnXYwX0YTP2lLtyYv9YzGMwcWXz5/64dAnfa6pxIk8SHYwkZdjnMt1wKVwDXEA6XhogQj6DkHLomY5XEG9bblMhvSDi/EvRGom7S4df8F76mmmT8d/4aIl/fTY53ARbfjBc2hHuUxJ+TmOEUE4TLPGUblwuQmJWt05Y2odCqrg+MgL6feEDgZGlLCEEUEUfuc8I0Cum2gdjNFvZ7xpT9mMCIVkwzvjomdcSgW9S+VZR3DVk9gQ3kkBpgU58lrKmQY0O6nKrVuft7S3pHnjD2wyWcup8VtL6+PpNKb6WNaT7QD3Up3B9Jd+N71VHrWbJ937Go//J2Y6+t2qE0AXOYzRvrOG0Z7iL9qM1xkicDR3Nuh7pY6jqBRvIlaQ2ZuyMewiCw2Lp19zRtzktFnefisfh6WUt0DC2wZMb2pFlTOjYEffMaKZyc5b7NSYyy32XoZXClE19fQ5y7tLYY9neeV41PWiNulAOVOArlNnb9impljFBpP58TY+hFI5d7R9YDpiJkKZ/KWdj3HotcvG7wTbMWy8mvL7UCVKfYNeUpPq7LghUZAmbU1xxXaUBZt03npTZuNDnkEXpPVAXasgMarJpDpgMfHFiSRZ0zGJ8AscYh/Tdi9DHLJWpsj3S6QjuGpdKRlXQ3TVusRTa1V5aquj6DFbiR5xu/PgLGLYGfiAQQk+tiXAx6gTPoOOwsduJXxsQVojQlncFfSUnY+hgWadT7r1+dfRkoY4WgaXdNh5vGw2WiwaMnYmL2zuc0hl0RUEAa2EIFMSadFqhRDoCIS0dkJIDF8IEMrCzV1BUSnkawxMEUWgIhRJo0ytCk/uBSJ5ME3EUAvOeMRA/bnrso5oa2P666MAke6AxyyCZ3t+kgOPXSd2rEawc0CIPoc3qybASQ5VT8tp7Rp1DnAp1CaYMgb7PjsKKwm97kMvqxQKAKDGQy+5nVIEpvyTXmTQSi8iRmquwo2JzxxJgN0OhdJAyY/IDo3VihzJt+B+NLx9/n5+i/77svSfrt2bH01fzznEkRyy+ynh4XiHxm+DsLGVm7h0Y/seH8Xieq3pSxMn4D/0Zv1HBVt5+Tz3vWqmntaySBXXRclGJLlH0BW/YZVwIwmBWXXuP1SzI7AxWgob8YLGcIYxO7XsGHKMEnIGInIGtSLH7ghyLBE5LdiGq+LdjCR2vMT+IujQTqUU8TKBeGxZa8RLa2Shdrj+a/tuFtTT2rJrzewIs4CKouhFG6Vb+jtWapN6gBGiLGCQ+6Dp2l90pyU5ceN3h53NWhnGcZfOulTw/nK5VqevNXxgXFeUkpVqYZgyHbZstdzRA6/Se4TtFaV8oEapCELSp3LNxGl4oDL9zi2aKwpUHnRNQwTdrteGVb9lGSjKGVCz1yugoEkGKGlIMuxjvGWRTlr2UuHojxVP8dnKLhQd5dmKnW4JPqgvW+941Gcr0unv9XL1sHdN7Xy/2h4lUYtmpK+WPU11WiOGoAndaUSCBOs+TbFLsa0qn6DSZPZHAgljs79jAFd/AA==</diagram></mxfile> \ No newline at end of file
+<mxfile host="app.diagrams.net" modified="2021-12-21T17:41:54.343Z" agent="5.0 (X11)" etag="0TS7O8wDBKDC3BJ4ppdc" version="16.0.0" type="device"><diagram id="g-wcGVps3MkI6_XAwNEs" name="Page-1">7Vxbd9o4EP41PJJjW74+BpI22ZNsu0svSd8EFsYbY1FbkKS/fmUs44uEa8AXvOwTlizJ0sx8M6PRiAEYL98+BnC1eMQ28gaKZL8NwM1AUWRVkehPVPPOagzZimucwLVZXVoxcX8hVsk6OmvXRmGuIcHYI+4qXznDvo9mJFcHgwC/5pvNsZf/6go6iKuYzKDH1353bbJgtbJupS/ukOss2KdNxYhfLGHSmK0kXEAbv2aqwO0AjAOMSfy0fBsjL6JeQpe434c9b3cTC5BPqnTQ7kfyF3RzbQZ/Od/wRnG9559DNsoGemu2YDZZ8p5QIMBr30bRINIAjF4XLkGTFZxFb18p02ndgiw9WpLpow3DxbZtVHA8GIas327128ILIrMFK8xdzxtjDwe07GOfjjtik0IBQW97VyvvaEilD+ElIsE7bcI6aBojeyJ4KmPYa8pFDbA2iwwDd5WQSY6zGzslLn1g9BXT+vGr/DyZjr7cGuDlu+b41s/ht6HGkRbZVNZYEQdkgR3sQ+82rR3liZ+2ecB4xaj8DyLknQEHrgnOMwS9ueQp6n6lsdIzGyx6vnnLFt6Tgk+X+5QMEBW2fa4MLSmn/balpOMeJtE143UwY4s2ZHP2Yv5Yj0Mw+vTHh6E/9sgQMGjDwEGkhIasXUS4UikIkAeJu8mDuHaO6gL06B6JcOBu6KMTPY7XwZYe7A39UOaloP0Khy5xsZ+8mgbFxsUhBFL1AKdUE+ckAXqu49PnGZ0MomAbRfhyqaa7Zi+Wrm3HQodC9xecbseTtjNyfbKlnTYaaDdCRpdJvADITF2zj+Q0ogjN0pUCFDMH6ER1VeY0G/xztJh0ZLmgJvL98XweUnksyslugpVEx5r/VB/m99J35e5Jdb6E07+JLlS8nCgske3CiNAefEdBRfYfpK+zynegAFtDpq1GGpoE+AVl3pjKFOh6GcY5Lu/XzWae6JohcbpZ1gW62axBNQu5AX5vBtvQ1YneZcp6p3l/o3bFOj7R/mIdX0lVC0EtJ25YRleXiXh9ulqMYFXNS5MKpCsJqCr1xDRTVyQjP2C8PjbGSbgWU0epAuxJpFSk2YGWIcS+0y+rUAq2OqyCnND7WCFKrIlaEJPmNL8mEJAudU3ex6vFxROuW+1KbZxkGVSOW5+pMeY4RiWZNAesiH1hzEmZM85sz7R3G3WSqValgnJNcJIx1arAUitNWWrjQtGj9xI9/AbpM1yH6GLgA6wCfEyVg4/WJnysC4WP2Uv4mBy3JoSS+FLQUzQ+msLvE1s1PsnW57+OliQo0jO4JNPO4mW70YriJ1M4e4nWvkKUF5eCIKAUEKTx7pustAohcCEQUvoJIT58wUEoDVBfCooKQWLNAjyKRGdJdaBIfGzXsSE6LD4plPAjg488qoQEUloCUdkkMxi6tu3oQ3S0Kf313KVLDkBPEEtUP8FjFYL9OyudAY/ZEHaE3DE6gc4RIfoM3Iwj8HYMvATHsOdltMpmncFbgrQZpoTBnhcdnhWYfv7HZEYheABAi8dkQq1qXajVsXhY7BfErlDAh3Zu/a1NSA3PEtuHxN48NO+v2TEKPpsAO3JDZufr8nEyvn/+dn3v/vlp4z19tO9+nFP2T1Wz08BeqfKJcg+yf2Tez4t2SZ4b8s7d+VubYlJG99amG0ete2sjC7ywM9zk8F5XvMuJsxQuY3OjFSLUggC10WZcwLxUyGgVLYjcrcXgcz/GC4yjA9GLgo1aTADkYWO1GRKQO8ZNa46WwcOkB/t7mU/6iIPSG+ytlxeUTaDnYaMLXLSmQmniMLTE0f4y7I2iVLQ3nUYEklmKzM2xsehexwTM33prstQQfoS3XtRO4MNiAslzxuh0ExMos0BZgJVdHGo6ydySpCsgp2nlIO+/FO+MxdOuI8lcuGhRCnHt947OMZ+8DEW15JObgHH2RHkZKiDfpZZ8cuHyK11CO+7CQT+vovVHSFQ9p0aGctHSNCc1fPSGuMtTj8lqsNFm4dCr1bthQie344SlY6+CKYfeBTvUMd4fkjynOIxwlvyljpLQZWs6rLJuyrNmv9CW6TAL5F2YejRasuPY3apqQJ0J19vx6ZpxVFZHC7vXk0Da1uZVOMlKbo0wr+rcfZU6ca5V9lUSSCr1uC6ggPQmrk+WCW+5XIQoDEu2MvxFe+hDJ71hf7DstHK8e9L/oegFv0o2u/arZL1PjlWN6lcW3ITt9Hy3dJYZoD1guPWSEnBVDhp2fVh12j8JmVpBg7Z3WiXmTCeJEXUCYI/VOtEmGcYeFVd/VK5kWfljKrhB/yNm2Nz5Li2m/6AWMzL9Izpw+y8=</diagram></mxfile> \ No newline at end of file
diff --git a/player_vlc.py b/player_vlc.py
new file mode 100644
index 0000000..9c8362a
--- /dev/null
+++ b/player_vlc.py
@@ -0,0 +1,36 @@
+import vlc
+
+class Player:
+ def __init__(self):
+ self.player = vlc.MediaPlayer()
+
+ def play(self):
+ self.player.play()
+
+ def stop(self):
+ self.player.stop()
+
+ def pause(self):
+ self.player.pause()
+
+ def setPlaybackRate(self, rate):
+ self.player.set_rate(rate)
+
+ def getPlaybackRate(self):
+ return self.player.get_rate()
+
+ def setPlaybackPosition(self, position):
+ self.player.set_position(position)
+
+ def getPlaybackPosition(self):
+ return self.player.get_position()
+
+ def setPlaybackVolume(self, volume):
+ self.player.audio_set_volume(int(volume * 100))
+
+ def getPlaybackVolume(self):
+ return self.player.audio_get_volume() / 100.0
+
+ def setCurrentSong(self, path):
+ media = vlc.Media(path)
+ self.player.set_media(media)
diff --git a/playlist.py b/playlist.py
index 5c52774..e5a4daf 100644
--- a/playlist.py
+++ b/playlist.py
@@ -1,10 +1,10 @@
import logging
class Playlist:
- def __init__(self, callback):
+ def __init__(self, player):
self._songList = list()
self._currentSong = None
- self._setSongCallback = callback
+ self._setSongCallback = player.setCurrentSong
def addSong(self, path):
self._songList.append(path)
diff --git a/playlist_unittest.py b/playlist_unittest.py
index ff5a79c..06785cc 100644
--- a/playlist_unittest.py
+++ b/playlist_unittest.py
@@ -1,76 +1,67 @@
from playlist import Playlist
+class MockPlayer:
+ def __init__(self):
+ self.songSetByCallback = None
+
+ def setCurrentSong(self, path):
+ self.songSetByCallback = path
+
def test_addAndSelectOneSong():
songAddedByUser = "/path/to/song"
- songSetByCallback = None
-
- def testCallback(song):
- nonlocal songSetByCallback
- songSetByCallback = song
+ mockPlayer = MockPlayer()
- uut = Playlist(testCallback)
+ uut = Playlist(mockPlayer)
uut.addSong(songAddedByUser)
uut.setCurrentSong(0)
- assert songAddedByUser == songSetByCallback
+ assert songAddedByUser == mockPlayer.songSetByCallback
assert uut.getCurrentSong() == songAddedByUser
assert uut.getSongs() == [songAddedByUser]
def test_addTwoSongsAndSelectBoth():
songAddedByUser = ["/path/to/song", "/path/to/second/song"]
- songSetByCallback = None
+ mockPlayer = MockPlayer()
- def testCallback(song):
- nonlocal songSetByCallback
- songSetByCallback = song
-
- uut = Playlist(testCallback)
+ uut = Playlist(mockPlayer)
uut.addSong(songAddedByUser[0])
uut.addSong(songAddedByUser[1])
assert uut.getSongs() == songAddedByUser
uut.setCurrentSong(0)
- assert songAddedByUser[0] == songSetByCallback
+ assert songAddedByUser[0] == mockPlayer.songSetByCallback
assert uut.getCurrentSong() == songAddedByUser[0]
uut.setCurrentSong(1)
- assert songAddedByUser[1] == songSetByCallback
+ assert songAddedByUser[1] == mockPlayer.songSetByCallback
assert uut.getCurrentSong() == songAddedByUser[1]
def test_firstAddedSongIsNotSelected():
songAddedByUser = "/path/to/song"
- songSetByCallback = None
-
- def testCallback(song):
- nonlocal songSetByCallback
- songSetByCallback = song
+ mockPlayer = MockPlayer()
- uut = Playlist(testCallback)
+ uut = Playlist(mockPlayer)
uut.addSong(songAddedByUser)
- assert songSetByCallback == None
+ assert mockPlayer.songSetByCallback == None
assert uut.getCurrentSong() == None
assert uut.getSongs() == [songAddedByUser]
def test_invalidSongSelection():
songAddedByUser = "/path/to/song"
- songSetByCallback = None
-
- def testCallback(song):
- nonlocal songSetByCallback
- songSetByCallback = song
+ mockPlayer = MockPlayer()
- uut = Playlist(testCallback)
- assert songSetByCallback == None
+ uut = Playlist(mockPlayer)
+ assert mockPlayer.songSetByCallback == None
assert uut.getCurrentSong() == None
uut.setCurrentSong(10)
- assert songSetByCallback == None
+ assert mockPlayer.songSetByCallback == None
assert uut.getCurrentSong() == None
uut.addSong(songAddedByUser)
uut.setCurrentSong(10)
- assert songSetByCallback == None
+ assert mockPlayer.songSetByCallback == None
assert uut.getCurrentSong() == None
assert uut.getSongs() == [songAddedByUser]
diff --git a/solo_tool.py b/solo_tool.py
new file mode 100644
index 0000000..da1a402
--- /dev/null
+++ b/solo_tool.py
@@ -0,0 +1,37 @@
+from playlist import Playlist
+from abcontroller import ABController
+from session_manager import SessionManager
+from player_vlc import Player
+
+class SoloTool:
+ def __init__(self, player=None):
+ self._player = Player() if player is None else player
+ self._playlist = Playlist(self._player)
+ self._abController = ABController()
+ self._sessionManager = SessionManager(self._playlist, self._abController)
+
+ def addSong(self, path):
+ self._sessionManager.addSong(path)
+
+ def setSong(self, index):
+ self._playlist.setCurrentSong(index)
+
+ # Playback control
+ def play(self):
+ self._player.play()
+
+ def pause(self):
+ self._player.pause()
+
+ def stop(self):
+ self._player.stop()
+
+ def setPlaybackRate(self, rate):
+ self._player.setPlaybackRate(rate)
+
+ def setPlaybackPosition(self, position):
+ self._player.setPlaybackPosition(position)
+
+ def setPlaybackVolume(self, volume):
+ self._player.setPlaybackVolume(volume)
+
diff --git a/solo_tool_integrationtest.py b/solo_tool_integrationtest.py
new file mode 100644
index 0000000..19bb406
--- /dev/null
+++ b/solo_tool_integrationtest.py
@@ -0,0 +1,68 @@
+from solo_tool import SoloTool
+from time import sleep
+
+class MockPlayer():
+ STOPPED = 0
+ PLAYING = 1
+ PAUSED = 2
+
+ def __init__(self):
+ self.state = MockPlayer.STOPPED
+ self.rate = 1.0
+ self.position = 0.0
+ self.volume = 1.0
+ self.currentSong = ""
+
+ def play(self):
+ self.state = MockPlayer.PLAYING
+
+ def stop(self):
+ self.state = MockPlayer.STOPPED
+
+ def pause(self):
+ self.state = MockPlayer.PAUSED
+
+ def setPlaybackRate(self, rate):
+ self.rate = rate
+
+ def getPlaybackRate(self):
+ return self.rate
+
+ def setPlaybackPosition(self, position):
+ self.position = position
+
+ def getPlaybackPosition(self):
+ return self.position
+
+ def setPlaybackVolume(self, volume):
+ self.volume = volume
+
+ def getPlaybackVolume(self):
+ return self.volume
+
+ def setCurrentSong(self, path):
+ self.currentSong = path
+
+def test_playerControls():
+ mockPlayer = MockPlayer()
+ uut = SoloTool(mockPlayer)
+
+ assert mockPlayer.state == MockPlayer.STOPPED
+ uut.play()
+ assert mockPlayer.state == MockPlayer.PLAYING
+ uut.pause()
+ assert mockPlayer.state == MockPlayer.PAUSED
+ uut.stop()
+ assert mockPlayer.state == MockPlayer.STOPPED
+
+ assert mockPlayer.rate == 1.0
+ uut.setPlaybackRate(0.5)
+ assert mockPlayer.rate == 0.5
+
+ assert mockPlayer.position == 0.0
+ uut.setPlaybackPosition(0.5)
+ assert mockPlayer.position == 0.5
+
+ assert mockPlayer.volume == 1.0
+ uut.setPlaybackVolume(0.5)
+ assert mockPlayer.volume == 0.5