Skip to content
This repository was archived by the owner on Apr 8, 2025. It is now read-only.

Commit 27ee903

Browse files
committed
Add song temporary to queue. Song is removed once it's finished.
This closes #126
1 parent 0c245bc commit 27ee903

5 files changed

Lines changed: 93 additions & 16 deletions

File tree

spoppy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
def get_version():
13-
return '1.6.1'
13+
return '1.7.0'
1414

1515

1616
if click:

spoppy/menus.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,10 @@ def add_to_queue(self):
689689
self.navigator.player.add_to_queue(self.track)
690690
return responses.UP
691691

692+
def add_to_temp_queue(self):
693+
self.navigator.player.add_play_then_remove(self.track)
694+
return self.navigator.player
695+
692696
def replace_current(self):
693697
self.navigator.player.load_playlist(
694698
self.playlist
@@ -712,10 +716,15 @@ def get_options(self):
712716
msg,
713717
self.replace_current
714718
)
719+
formatted_track = format_track(self.track)
715720
results['aq'] = MenuValue(
716-
'Add [%s] to queue' % format_track(self.track),
721+
'Add [%s] to queue' % formatted_track,
717722
self.add_to_queue
718723
)
724+
results['tmp'] = MenuValue(
725+
'Add [%s] temporary to playlist' % formatted_track,
726+
self.add_to_temp_queue
727+
)
719728
if self.track.album:
720729
res = AlbumSelected(self.navigator)
721730
res.album = self.track.album.browse().load()

spoppy/players.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def clear(self):
9494
self.playlist = None
9595
self.song_list = []
9696
self._trigger_redraw = False
97+
self.temporary_song = None
9798

9899
def has_been_loaded(self):
99100
'''
@@ -263,33 +264,34 @@ def get_ui(self):
263264
for song_idx in songs_to_show:
264265
song = self.get_track_by_idx(song_idx)
265266
right_side = right_side_items and right_side_items.pop(0)
267+
extra_text = (
268+
artist_banned_text(self.navigator, song) or
269+
(
270+
self.song_order[song_idx] == self.temporary_song and
271+
'[temporary]'
272+
)
273+
)
266274
if song_idx == self.current_track_idx:
267275
if song_idx != songs_to_show[0]:
268276
# Small spacing around current...
269277
res.append(('', right_side or ''))
270278
right_side = (
271279
right_side_items and right_side_items.pop(0)
272280
)
273-
formatted_song = '>>>%s' % format_track(
274-
song,
275-
artist_banned_text(self.navigator, song)
276-
)
281+
formatted_song = '>>>%s' % format_track(song, extra_text)
277282
else:
278-
formatted_song = format_track(
279-
song,
280-
artist_banned_text(self.navigator, song)
281-
)
283+
formatted_song = format_track(song, extra_text)
282284
res.append((formatted_song, right_side or ''))
283285
if song_idx == self.current_track_idx:
284286
if song_idx != songs_to_show[-1]:
285287
# Small spacing around current...
286288
right_side = (
287-
right_side_items and right_side_items.pop()
289+
right_side_items and right_side_items.pop(0)
288290
)
289291
res.append(('', right_side or ''))
290292
while right_side_items:
291293
# This can happend f.x. when we have one song...
292-
res.append(('', right_side_items.pop()))
294+
res.append(('', right_side_items.pop(0)))
293295
else:
294296
res.append('No songs found in playlist!')
295297

@@ -503,6 +505,22 @@ def toggle_repeat(self):
503505
return NOOP
504506

505507
# Song handling
508+
def add_play_then_remove(self, item):
509+
'''
510+
Adds item to the current queue temporary. After the song has been added
511+
it will start playing. Once it's finished or navigated from it, it will
512+
be removed and the song that was playing when it was added will start
513+
playing.
514+
temporary_song is the index to the currently temporary song in the
515+
song_list, not in song_order
516+
'''
517+
self.clean_temporary_song()
518+
idx_of_new_item = len(self.song_list)
519+
self.song_list.append(item)
520+
self.song_order.insert(self.current_track_idx, idx_of_new_item)
521+
self.temporary_song = idx_of_new_item
522+
self.play_current_song(start_playing=True, clean_temporary=False)
523+
506524
def add_to_queue(self, item):
507525
'''
508526
Adds item to the end of the current song list. Item can be either
@@ -522,6 +540,23 @@ def add_to_queue(self, item):
522540
self.add_to_queue(track)
523541
self.playlist = None
524542

543+
def clean_temporary_song(self):
544+
'''
545+
If there is a temporary song in the queue, remove it from the song list
546+
and make sure that the song playing before it gets selected
547+
:returns: None
548+
'''
549+
if self.temporary_song:
550+
temporary_song_index = self.song_order.index(self.temporary_song)
551+
self.song_order.remove(self.temporary_song)
552+
del self.song_list[self.temporary_song]
553+
self.temporary_song = None
554+
if temporary_song_index < self.current_track_idx:
555+
# If the previous song came before the current (which happens
556+
# unless the user selected the previous song) we have to
557+
# select the previous song so we don't jump to the next one.
558+
self.current_track_idx = self.get_prev_idx()
559+
525560
def check_end_of_track(self):
526561
'''
527562
Checks if the current song has finished playing and starts playing
@@ -607,14 +642,22 @@ def on_end_of_track(self, session=None):
607642
'''
608643
self.end_of_track.set()
609644
thread.interrupt_main()
645+
return False
610646

611-
def play_current_song(self, start_playing=True):
647+
def play_current_song(self, start_playing=True, clean_temporary=True):
612648
'''
613-
Plays the current song
649+
Plays the current song.
650+
Before playing these actions are performed:
651+
1. Removes the temporary song if there is one.
652+
2. If the current track's artist is banned, removes the current
653+
song.
614654
:returns: None
615655
'''
616656
self.player.unload()
617657

658+
if clean_temporary:
659+
self.clean_temporary_song()
660+
618661
current_track = self.get_track_by_idx(self.current_track_idx)
619662
if not current_track:
620663
self.current_track = None

spoppy/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ def single_char_with_timeout(timeout=5):
5252
return response
5353

5454

55-
def format_track(track, extra_text=''):
55+
def format_track(track, extra_text=None):
5656
return '%s by %s %s' % (
5757
track.name,
5858
' & '.join(
5959
artist.name for artist in track.artists
6060
if artist.name
6161
),
62-
extra_text
62+
extra_text or ''
6363
)
6464

6565

tests/test_players.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,3 +536,28 @@ def test_get_total_playlist_length(self, patched_get_duration_from_s):
536536
71, max_length=None
537537
)
538538
self.assertEquals(result, expected_duration)
539+
540+
def test_clean_temporary_song_does_nothing_when_no_temp_song(self):
541+
self.assertIsNone(self.player.clean_temporary_song())
542+
543+
def test_song_is_removed_if_is_temporary(self):
544+
track_should_be_there = [utils.Track('Hey im here', 'duran')]
545+
track_2_should_be_there = [utils.Track('Hey im here also', 'duran')]
546+
track_should_not_be_there = [utils.Track('Im gone', 'Brynja')]
547+
self.player.song_list = [
548+
track_should_be_there,
549+
track_should_not_be_there,
550+
track_2_should_be_there
551+
]
552+
self.player.current_track_idx = 1
553+
self.player.temporary_song = 1
554+
self.player.song_order = [0, 1, 2]
555+
556+
# We want track_2_should_be_there to be selected after removal
557+
self.assertIsNone(self.player.clean_temporary_song())
558+
self.assertEquals(len(self.player.song_order), 2)
559+
self.assertEquals(len(self.player.song_list), 2)
560+
self.assertIn(track_should_be_there, self.player.song_list)
561+
self.assertIn(track_2_should_be_there, self.player.song_list)
562+
self.assertNotIn(track_should_not_be_there, self.player.song_list)
563+
self.assertEquals(self.player.current_track_idx, 1)

0 commit comments

Comments
 (0)