Skip to content

Commit

Permalink
feat(#1): Add context manager for playing background music
Browse files Browse the repository at this point in the history
  • Loading branch information
Timo Reymann authored and Timo Reymann committed Aug 11, 2022
1 parent 547b2b3 commit d5dd9a9
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 55 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,26 @@ script-background-music
## Usage

It is very simple to use the package inside your scripts:
It is very simple to use the package inside your scripts ...

### ... the entire time, until your script exits

```python
from script_background_music import play_music_in_background

play_music_in_background()
```

### ... for a specific set of instructions

```python
from script_background_music import BackgroundMusicContext

with BackgroundMusicContext():
# your instructions go here
pass
```

## Notes on implementation

### Can it break my script?
Expand Down
16 changes: 13 additions & 3 deletions example.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
#!/usr/bin/env python3
from script_background_music import play_music_in_background
import sys
from time import sleep

from script_background_music import play_music_in_background, BackgroundMusicContext

def main():

def main_background():
play_music_in_background()
input()


def main_context():
while True:
with BackgroundMusicContext():
print("Press any key to play random song")
input()


if __name__ == "__main__":
main()
main_context()
46 changes: 3 additions & 43 deletions script_background_music/__init__.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,3 @@
import logging
from threading import Thread
from typing import Union

from script_background_music.songs import get_random_song
from script_background_music.vendor.playsound import get_play_sound


def __music(song_title):
try:
while True:
get_play_sound()(song_title, block=True)
break
except:
logging.debug("Could not start music, exiting.")


def play_music_in_background(song_file: Union[str, None] = None):
"""
Play music in background if no song is provided, a random will be picked
:param song_file: Song to play, set to None or omit to use a random one
"""
song_to_play = get_random_song() if song_file is None else song_file
thread = Thread(target=__music, args=(song_to_play,))
thread.daemon = True
thread.start()


def play_random_music_in_background():
"""
Play random music from the available songs in the background
"""
play_music_in_background(None)


def play_song_in_background(file_name: str):
"""
Play song from given file in background
:param file_name: Filename of song to play in background
:return:
"""
play_music_in_background(file_name)
from script_background_music.play import play_music_in_background, play_random_music_in_background, \
play_song_in_background
from script_background_music.context import BackgroundMusicContext
26 changes: 26 additions & 0 deletions script_background_music/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Callable

from script_background_music.play import play_random_music_in_background, PlayThread


class BackgroundMusicContext(object):
"""
Run background music in a given context
<b>WARNING: Only verified to work on macOS! Should work on Linux and Windows as well since they also create a subprocess under the hood.</b>
"""
__thread: PlayThread = None

def __init__(self, player_callback: Callable[[], PlayThread] = play_random_music_in_background):
"""
Create new background music context
:param player_callback: Callback to run the music, defaults to<i>script_background_music.play.play_random_music_in_background</i>
"""
self.__thread = player_callback()

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.__thread.kill_children()
self.__thread.terminate()
51 changes: 51 additions & 0 deletions script_background_music/play.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import logging
from multiprocessing import Process
from typing import Union
import psutil
from script_background_music.songs import get_random_song
from script_background_music.vendor.playsound import get_play_sound


class PlayThread(Process):
def kill_children(self):
process = psutil.Process(self.pid)
for child in process.children(recursive=True):
child.kill()


def __music(song_title):
try:
while True:
get_play_sound()(song_title, block=True)
except:
logging.debug("Could not start music, exiting.")


def play_music_in_background(song_file: Union[str, None] = None) -> PlayThread:
"""
Play music in background if no song is provided, a random will be picked
:param song_file: Song to play, set to None or omit to use a random one
:return: Underlying thread for playing music
"""
song_to_play = get_random_song() if song_file is None else song_file
thread = PlayThread(target=__music, args=(song_to_play,))
# thread.daemon = True
thread.start()
return thread


def play_random_music_in_background() -> PlayThread:
"""
Play random music from the available songs in the background
:return: Underlying thread for playing music
"""
return play_music_in_background(None)


def play_song_in_background(file_name: str) -> PlayThread:
"""
Play song from given file in background
:param file_name: Filename of song to play in background
:return: Underlying thread for playing music
"""
return play_music_in_background(file_name)
12 changes: 4 additions & 8 deletions script_background_music/vendor/playsound/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
SOFTWARE.
"""
import logging
import os
import sys
from platform import system
import subprocess

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -118,13 +119,8 @@ def winCommand(*command):


def __playsound_osx(sound, block=True):
exit_code = subprocess.call(
["afplay", sound],
stdout=subprocess.DEVNULL,
stderr=subprocess.STDOUT
)
if exit_code != 0:
raise Exception(f"Exited with status {exit_code}")
p = subprocess.Popen(["afplay", sound], stdout=sys.stdout, stderr=sys.stderr)
p.wait()


def __playsound_nix(sound, block=True):
Expand Down

0 comments on commit d5dd9a9

Please sign in to comment.