playsound3 2.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
playsound3/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from playsound3.playsound3 import playsound
@@ -0,0 +1,132 @@
1
+ import atexit
2
+ import ctypes
3
+ import logging
4
+ import platform
5
+ import subprocess
6
+ import tempfile
7
+ import urllib.request
8
+ import uuid
9
+ from pathlib import Path
10
+ from threading import Thread
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ SYSTEM = platform.system()
15
+ DOWNLOAD_CACHE = dict()
16
+
17
+
18
+ class PlaysoundException(Exception):
19
+ pass
20
+
21
+
22
+ def playsound(sound, block: bool = True) -> None:
23
+ """Play a sound file using an audio backend availabile in your system.
24
+
25
+ Args:
26
+ sound: Path to the sound file. Can be either an str or pathlib.Path.
27
+ block: If True, the function will block execution until the sound finishes playing.
28
+ """
29
+ sound = _prepare_path(sound)
30
+
31
+ if SYSTEM == "Linux":
32
+ func = _playsound_gstreamer
33
+ elif SYSTEM == "Windows":
34
+ func = _playsound_winmm
35
+ elif SYSTEM == "Darwin":
36
+ func = _playsound_afplay
37
+ else:
38
+ raise PlaysoundException(f"Platform '{SYSTEM}' is not supported")
39
+
40
+ if block:
41
+ func(sound)
42
+ else:
43
+ t = Thread(target=func, args=(sound,), daemon=True).start()
44
+
45
+
46
+ def _prepare_path(sound):
47
+ if sound.startswith(("http://", "https://")):
48
+ # To play file from URL, we download the file first to a temporary location
49
+ if sound not in DOWNLOAD_CACHE:
50
+ with tempfile.NamedTemporaryFile(delete=False, prefix="playsound3-") as f:
51
+ urllib.request.urlretrieve(sound, f.name)
52
+ DOWNLOAD_CACHE[sound] = f.name
53
+ sound = DOWNLOAD_CACHE[sound]
54
+
55
+ path = Path(sound)
56
+
57
+ if not path.exists():
58
+ raise PlaysoundException(f"File not found: {sound}")
59
+ return path.absolute().as_posix()
60
+
61
+
62
+ def _playsound_gstreamer(sound):
63
+ """Play a sound using gstreamer (built-in Linux)."""
64
+
65
+ if not sound.startswith("file://"):
66
+ sound = "file://" + urllib.request.pathname2url(sound)
67
+
68
+ import gi
69
+
70
+ # Silences gi warning
71
+ gi.require_version("Gst", "1.0")
72
+
73
+ # GStreamer is included in all Linux distributions
74
+ from gi.repository import Gst
75
+
76
+ Gst.init(None)
77
+
78
+ playbin = Gst.ElementFactory.make("playbin", "playbin")
79
+ playbin.props.uri = sound
80
+
81
+ logger.debug("gstreamer: starting playing %s", sound)
82
+ set_result = playbin.set_state(Gst.State.PLAYING)
83
+ if set_result != Gst.StateChangeReturn.ASYNC:
84
+ raise PlaysoundException("playbin.set_state returned " + repr(set_result))
85
+ bus = playbin.get_bus()
86
+ try:
87
+ bus.poll(Gst.MessageType.EOS, Gst.CLOCK_TIME_NONE)
88
+ finally:
89
+ playbin.set_state(Gst.State.NULL)
90
+ logger.debug("gstreamer: finishing play %s", sound)
91
+
92
+
93
+ def _send_winmm_mci_command(command):
94
+ winmm = ctypes.WinDLL("winmm.dll")
95
+ buffer = ctypes.create_string_buffer(255)
96
+ error_code = winmm.mciSendStringA(ctypes.c_char_p(command.encode()), buffer, 254, 0)
97
+ if error_code:
98
+ logger.error("Error code: %s", error_code)
99
+ return buffer.value
100
+
101
+
102
+ def _playsound_winmm(sound):
103
+ """Play a sound utilizing windll.winmm."""
104
+
105
+ # Select a unique alias for the sound
106
+ alias = str(uuid.uuid4())
107
+ logger.debug("winmm: starting playing %s", sound)
108
+ _send_winmm_mci_command(f'open "{sound}" type mpegvideo alias {alias}')
109
+ _send_winmm_mci_command(f"play {alias} wait")
110
+ _send_winmm_mci_command(f"close {alias}")
111
+ logger.debug("winmm: finishing play %s", sound)
112
+
113
+
114
+ def _playsound_afplay(sound):
115
+ """Uses afplay utility (built-in macOS)."""
116
+ logger.debug("afplay: starting playing %s", sound)
117
+ try:
118
+ subprocess.run(["afplay", sound], check=True)
119
+ except subprocess.CalledProcessError as e:
120
+ raise PlaysoundException(f"afplay failed to play sound: {e}")
121
+ logger.debug("afplay: finishing play %s", sound)
122
+
123
+
124
+ def _remove_cached_files(cache):
125
+ """Remove all files saved in the cache when the program ends."""
126
+ import os
127
+
128
+ for path in cache.values():
129
+ os.remove(path)
130
+
131
+
132
+ atexit.register(_remove_cached_files, DOWNLOAD_CACHE)
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.3
2
+ Name: playsound3
3
+ Version: 2.1.1
4
+ Summary: Cross-platform library to play audio files
5
+ Project-URL: Repository, https://github.com/sjmikler/playsound3
6
+ Project-URL: Issues, https://github.com/sjmikler/playsound3/issues
7
+ Project-URL: Documentation, https://github.com/sjmikler/playsound3?tab=readme-ov-file#documentation
8
+ Author-email: Szymon Mikler <sjmikler@gmail.com>, Taylor Marks <taylor@marksfam.com>
9
+ Maintainer-email: Szymon Mikler <sjmikler@gmail.com>
10
+ License: MIT License
11
+ License-File: LICENSE
12
+ Keywords: audio,media,mp3,music,play,playsound,song,sound,wav,wave
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.7
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Multimedia :: Sound/Audio :: MIDI
25
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Players
26
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Players :: MP3
27
+ Requires-Python: >=3.7
28
+ Requires-Dist: pygobject; platform_system == 'Linux'
29
+ Description-Content-Type: text/markdown
30
+
31
+ > This repository was forked from [TaylorSMarks/playsound](https://github.com/TaylorSMarks/playsound)
32
+
33
+ # playsound3
34
+
35
+ [![PyPi version](https://img.shields.io/badge/dynamic/json?label=latest&query=info.version&url=https%3A%2F%2Fpypi.org%2Fpypi%2Fplaysound3%2Fjson)](https://pypi.org/project/playsound3)
36
+ [![PyPI license](https://img.shields.io/badge/dynamic/json?label=license&query=info.license&url=https%3A%2F%2Fpypi.org%2Fpypi%2Fplaysound3%2Fjson)](https://pypi.org/project/playsound3)
37
+
38
+ Cross platform library to play sound files in Python.
39
+
40
+ ## Installation
41
+
42
+ Install via pip:
43
+
44
+ ```
45
+ pip install playsound3
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ Once installed, you can use the playsound function to play sound files:
51
+
52
+ ```python
53
+ from playsound3 import playsound
54
+
55
+ playsound("/path/to/sound/file.mp3")
56
+
57
+ # or use directly on URLs
58
+ playsound("http://url/to/sound/file.mp3")
59
+ ```
60
+
61
+ ## Documentation
62
+
63
+ The playsound module contains only one thing - the function (also named) playsound:
64
+
65
+ ```python
66
+ def playsound(sound, block: bool = True) -> None:
67
+ """Play a sound file using an audio backend availabile in your system.
68
+
69
+ Args:
70
+ sound: Path to the sound file. Can be either an str or pathlib.Path.
71
+ block: If True, the function will block execution until the sound finishes playing.
72
+ """
73
+ ```
74
+
75
+ It requires one argument - the path to the file with the sound you'd like to play.
76
+ This should be a local file or a URL.
77
+ There's an optional second argument, block, which is set to True by default.
78
+ Setting it to False makes the function run asynchronously.
79
+
80
+ ## Supported systems
81
+
82
+ * Linux, using GStreamer (built-in on Linux distributions)
83
+ * Windows, using winmm.dll (built-in on Windows)
84
+ * OS X, using afplay utility (built-in on OS X)
@@ -0,0 +1,6 @@
1
+ playsound3/__init__.py,sha256=uAfl17fNqC-3wGYFxtdENOTWu31_IONpDU_wgdCnemc,44
2
+ playsound3/playsound3.py,sha256=5WOt6vjUY1hC0jVJ1e6FN05-WIjCF5hkj7ITY-kkwxQ,3898
3
+ playsound3-2.1.1.dist-info/METADATA,sha256=e5sB9NhmNqlwQDU7lxu2FSV5ECq8eMruWUvn-T6kCSU,3136
4
+ playsound3-2.1.1.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
5
+ playsound3-2.1.1.dist-info/licenses/LICENSE,sha256=VTRyASdB4LydQkt1egAUbIjG1zWMkh-UUELP1SdccXw,1155
6
+ playsound3-2.1.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.24.2
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Szymon Mikler <sjmikler@gmail.com>
4
+ Copyright (c) 2021 Taylor Marks <taylor@marksfam.com>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.