def remove_all(request: WSGIRequest) -> HttpResponse: """Empties the queue. Only admin is permitted to do this.""" if not user_manager.is_admin(request.user): return HttpResponseForbidden() with playback.mopidy_command() as allowed: if allowed: with transaction.atomic(): playback.queue.all().delete() return HttpResponse()
def restart(_request: WSGIRequest) -> None: """Restarts the current song from the beginning.""" with playback.mopidy_command() as allowed: if allowed: PLAYER.playback.seek(0) try: current_song = models.CurrentSong.objects.get() current_song.created = timezone.now() current_song.save() except models.CurrentSong.DoesNotExist: pass
def seek_forward(_request: WSGIRequest) -> None: """Jumps forward in the current song.""" with playback.mopidy_command() as allowed: if allowed: current_position = PLAYER.playback.get_time_position() PLAYER.playback.seek(current_position + SEEK_DISTANCE * 1000) try: current_song = models.CurrentSong.objects.get() current_song.created -= datetime.timedelta(seconds=SEEK_DISTANCE) current_song.save() except models.CurrentSong.DoesNotExist: pass
def pause(_request: WSGIRequest) -> None: """Pauses the current song if it is playing. No-op if already paused.""" with playback.mopidy_command() as allowed: if allowed: PLAYER.playback.pause() try: current_song = models.CurrentSong.objects.get() current_song.last_paused = timezone.now() current_song.save() except models.CurrentSong.DoesNotExist: pass storage.put("paused", True)
def _set_volume(volume) -> None: try: # Try to set the volume via the pulse server. # This is faster and does not impact visualization subprocess.run( f"pactl set-sink-volume @DEFAULT_SINK@ {round(volume*100)}%".split( ), env={"PULSE_SERVER": conf.PULSE_SERVER}, check=True, ) except (FileNotFoundError, subprocess.CalledProcessError): # pulse is not installed or there is no server running. # change mopidy's volume with playback.mopidy_command() as allowed: if allowed: PLAYER.mixer.set_volume(round(volume * 100))
def play(_request: WSGIRequest) -> None: """Resumes the current song if it is paused. No-op if already playing.""" with playback.mopidy_command() as allowed: if allowed: PLAYER.playback.play() try: # move the creation timestamp into the future for the duration of the pause # this ensures that the progress calculation (starting from created) is correct current_song = models.CurrentSong.objects.get() now = timezone.now() pause_duration = (now - current_song.last_paused).total_seconds() current_song.created += datetime.timedelta(seconds=pause_duration) current_song.created = min(current_song.created, now) current_song.save() except models.CurrentSong.DoesNotExist: pass storage.put("paused", False)
def vote(request: WSGIRequest) -> HttpResponse: """Modify the vote-count of the given song by the given amount. If a song receives too many downvotes, it is removed.""" key_param = request.POST.get("key") amount_param = request.POST.get("amount") if key_param is None or amount_param is None: return HttpResponseBadRequest() key = int(key_param) amount = int(amount_param) if amount < -2 or amount > 2: return HttpResponseBadRequest() if storage.get("ip_checking") and not user_manager.try_vote( user_manager.get_client_ip(request), key, amount): return HttpResponseBadRequest("nice try") models.CurrentSong.objects.filter(queue_key=key).update(votes=F("votes") + amount) try: current_song = models.CurrentSong.objects.get() if (current_song.queue_key == key and current_song.votes <= -storage.get( # pylint: disable=invalid-unary-operand-type "downvotes_to_kick")): with playback.mopidy_command() as allowed: if allowed: PLAYER.playback.next() except models.CurrentSong.DoesNotExist: pass removed = playback.queue.vote( key, amount, -storage.get("downvotes_to_kick"), # pylint: disable=invalid-unary-operand-type ) # if we removed a song by voting, and it was added by autoplay, # we want it to be the new basis for autoplay if removed is not None: if not removed.manually_requested: playback.handle_autoplay(removed.external_url or removed.title) else: playback.handle_autoplay() musiq.update_state() return HttpResponse()
def skip(_request: WSGIRequest) -> None: """Skips the current song and continues with the next one.""" with playback.mopidy_command() as allowed: if allowed: redis.put("backup_playing", False) PLAYER.playback.next()