speaking-clock 1.0.0__tar.gz

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.
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: speaking-clock
3
+ Version: 1.0.0
4
+ Summary: A clock that speaks the current time using ElevenLabs API
5
+ Home-page: https://github.com/example/speaking-clock
6
+ Author: Marcin Orlowski
7
+ Author-email: Marcin Orlowski <mail@marcinorlowski.com>
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: elevenlabs
15
+ Requires-Dist: PyYAML
16
+ Requires-Dist: python-dateutil
17
+ Requires-Dist: num2words
18
+ Dynamic: author
19
+ Dynamic: home-page
20
+ Dynamic: requires-python
21
+
22
+ ```
23
+ ▄▀▀▄ █ ▀ ▄▀▀▄ ▀█ █
24
+ ▀▄▄ █▀▀▄ ▄▀▀▄ ▄▀▀▄ █ ▄▀ ▀█ █▀▀▄ ▄▀▀█ █ █ ▄▀▀▄ ▄▀▀▄ █ ▄▀
25
+ █ █ █ █▀▀ ▄▄█ █▀▄ █ █ █ █ █ █ █ █ █ █ █▀▄
26
+ ▀▄▄▀ █▄▄▀ ▀▄▄▀ ▀▄▄▀ █ █ ▄█▄ █ █ ▀▄▄█ ▀▄▄▀ ▄█▄ ▀▄▄▀ ▀▄▄▀ █ █
27
+ █ ▄▄▀
28
+
29
+ @project Speaking Clock - time announcer using ElevenLabs TTS API
30
+ @author Marcin Orlowski <mail (#) marcinOrlowski (.) com>
31
+ @copyright 2025 Marcin Orlowski
32
+ @license https://www.opensource.org/licenses/mit-license.php MIT
33
+ @link https://github.com/MarcinOrlowski/speaking-clock
34
+ ```
35
+
36
+ # Speaking Clock
37
+
38
+ A small utility that speaks (usually current) time in specified language. Uses ElevenLabs API
39
+ to generate the speech. Supports caching and reusing audio files so free ElevenLabs
40
+ access is more than enough. Handy to sit in cron jobs to periodically announce the time.
41
+
42
+ ## Features
43
+
44
+ - Gets the current time and speaks it in specified language
45
+ - Converts numbers to their Polish word representation (e.g., "13:05" → "trzynasta pięć")
46
+ - Uses ElevenLabs API for high-quality text-to-speech
47
+ - Caches generated audio files for quick reuse
48
+ - Supports both 12-hour and 24-hour time formats
49
+ - Optional audio chime before speaking the time
50
+ - Parallel processing - prepares audio while chime is playing
51
+ - Overlaid audio playback with configurable timing offset
52
+ - Command-line interface driven, perfect for background jobs like cron
53
+
54
+ ## Installation
55
+
56
+ This app is regular Python package and is also hosted
57
+ on [PyPi](https://pypi.org/project/speaking-clock/) so
58
+ you can install it as usual. But because this one is supposed to rather act as the application, I
59
+ strongly recommend to use [pipx](https://pipx.pypa.io/) to install this tool in isolated
60
+ environment be it on Linux, Windows or MacOS machines. Once you got `pipx` up
61
+ and running, install the package:
62
+
63
+ ```bash
64
+ $ pipx install speaking-clock
65
+ ```
66
+
67
+ Of course, you can also use plain `pip` to do that:
68
+
69
+ ```bash
70
+ $ pip install speaking-clock
71
+ ```
72
+
73
+ But that might be a problem as some distributions no longer allow system-wide installations,
74
+ therefore use of `pipx` is strongly recommended as the all-in-one solution.
75
+
76
+ Once installed `speaking-clock` executable (and it's alias `speak-time`) should be available in
77
+ your system ready to be used. Please use `--help` to see all available options.
78
+
79
+ ## Usage
80
+
81
+ ### As a command-line tool
82
+
83
+ Once installed, you can use the command-line interface:
84
+
85
+ ```
86
+ speak-time
87
+ ```
88
+
89
+ You can specify a custom config file:
90
+
91
+ ```
92
+ speak-time --config /path/to/your/config.yml
93
+ ```
94
+
95
+ ### Configuration
96
+
97
+ The speaking-clock looks for configuration in the following places:
98
+
99
+ 1. Command-line specified config (if provided)
100
+ 1. User config file at `~/.config/speaking-clock/config.yml`
101
+ 1. Default configuration built into the package
102
+
103
+ You can create a config file at `~/.config/speaking-clock/config.yml` with the following structure:
104
+
105
+ ```yaml
106
+ language:
107
+ code: "pl" # Language code matching a file in 'languages/' directory
108
+ use_24h_clock: true # Use 24-hour (true) or 12-hour (false) format
109
+
110
+ elevenlabs:
111
+ api_key: "your-api-key-here" # Your ElevenLabs API key
112
+ voice_id: "voice-id-here" # ElevenLabs voice ID
113
+ model_id: "eleven_multilingual_v2" # TTS model to use
114
+
115
+ audio:
116
+ play_chime: true # Play a chime before speaking the time
117
+ chime_file: "clock-chime.mp3" # Path to the chime audio file
118
+ overlay_speech: true # Overlay speech over the chime sound
119
+ speech_offset_ms: 1000 # Milliseconds to wait before starting speech
120
+
121
+ cache:
122
+ directory: ".cache" # Directory for caching audio files
123
+ ```
124
+
125
+ You can also set your ElevenLabs API key as an environment variable:
126
+
127
+ ```
128
+ export ELEVENLABS_API_KEY="your-api-key-here"
129
+ ```
130
+
131
+ ## Language Support
132
+
133
+ The application supports multiple languages through YAML language definition files. These files are stored in the `languages/` directory with filenames matching their language code (e.g., `pl.yml` for Polish).
134
+
135
+ To add support for a new language:
136
+
137
+ 1. Create a new YAML file in the `languages/` directory (e.g., `en.yml` for English)
138
+ 1. Define the language elements following the structure in the existing language files
139
+ 1. Update the `language.code` value in `config.yml` to match your new language file
140
+
141
+ Example language file structure:
142
+
143
+ ```yaml
144
+ days_of_week:
145
+ - poniedziałek # Monday
146
+ - wtorek # Tuesday
147
+ # ...
148
+
149
+ hours:
150
+ 0: dwudziesta czwarta
151
+ 1: pierwsza
152
+ # ...
153
+
154
+ special_minutes:
155
+ 0: ""
156
+ 15: piętnaście
157
+ # ...
158
+
159
+ special_times:
160
+ midnight: północ, nastał {day_name}
161
+ ```
162
+
163
+ ## Cache Files
164
+
165
+ Audio files are automatically cached in the `.cache` directory using the following naming convention:
166
+
167
+ ```
168
+ LANG-VOICE-HH-MM.mp3
169
+ ```
170
+
171
+ For example:
172
+
173
+ ```
174
+ pl-voice_id-13-05.mp3 # Polish, voice_id, 13:05
175
+ ```
176
+
177
+ This caching system ensures that each unique time announcement is only generated once, reducing API calls to ElevenLabs and improving response time for frequently requested times.
178
+
179
+ # Audio Support for Cron Jobs in KDE 5
180
+
181
+ ## Problem
182
+
183
+ When running Python applications from cron jobs in KDE 5, audio playback doesn't work automatically. This is because cron jobs run in a separate environment without access to your desktop session's audio system.
184
+
185
+ ## Solution
186
+
187
+ Configure the cron job with specific environment variables to access your KDE desktop session's audio services.
188
+
189
+ ### Required Environment Variables
190
+
191
+ For audio playback in KDE 5, your cron job needs these key environment variables:
192
+
193
+ - `DISPLAY`: Points to your X server display
194
+ - `DBUS_SESSION_BUS_ADDRESS`: Connects to your D-Bus session
195
+ - `XDG_RUNTIME_DIR`: Required for PulseAudio/PipeWire access
196
+
197
+ ### Setting Up the Cron Job
198
+
199
+ Edit your crontab:
200
+
201
+ ```bash
202
+ crontab -e
203
+ ```
204
+
205
+ Add your job using this template:
206
+
207
+ ```bash
208
+ # Run every hour at minute 0
209
+ 0 * * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME plasma-session)/environ | cut -d= -f2-) XDG_RUNTIME_DIR=/run/user/$(id -u) python /path/to/your/script.py
210
+ ```
211
+
212
+ ### Testing Your Configuration
213
+
214
+ To test without waiting for the scheduled time:
215
+
216
+ ```bash
217
+ # Test the exact command that cron will run
218
+ DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME plasma-session)/environ | cut -d= -f2-) XDG_RUNTIME_DIR=/run/user/$(id -u) python /path/to/your/script.py
219
+ ```
220
+
221
+ ## Troubleshooting
222
+
223
+ ### Common Issues and Solutions
224
+
225
+ 1. **No audio despite correct configuration**:
226
+
227
+ - Ensure PulseAudio is running: `pulseaudio --check`
228
+ - Try adding `PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native` to your environment variables
229
+
230
+ 1. **D-Bus address not found**:
231
+
232
+ - If plasma-session isn't found, try: `pgrep -u $LOGNAME plasmashell` instead
233
+
234
+ 1. **Permission issues**:
235
+
236
+ - Check audio group membership: `groups | grep audio`
237
+ - Add yourself if needed: `sudo usermod -a -G audio $USER`
238
+
239
+ 1. **Application-specific audio servers**:
240
+
241
+ - For PipeWire: Add `PIPEWIRE_RUNTIME_DIR=${XDG_RUNTIME_DIR}/pipewire-0`
242
+
243
+ ## Limitations
244
+
245
+ This solution only works when:
246
+
247
+ - You are logged into your KDE session
248
+ - You are using the same user account for both KDE and the cron job
@@ -0,0 +1,227 @@
1
+ ```
2
+ ▄▀▀▄ █ ▀ ▄▀▀▄ ▀█ █
3
+ ▀▄▄ █▀▀▄ ▄▀▀▄ ▄▀▀▄ █ ▄▀ ▀█ █▀▀▄ ▄▀▀█ █ █ ▄▀▀▄ ▄▀▀▄ █ ▄▀
4
+ █ █ █ █▀▀ ▄▄█ █▀▄ █ █ █ █ █ █ █ █ █ █ █▀▄
5
+ ▀▄▄▀ █▄▄▀ ▀▄▄▀ ▀▄▄▀ █ █ ▄█▄ █ █ ▀▄▄█ ▀▄▄▀ ▄█▄ ▀▄▄▀ ▀▄▄▀ █ █
6
+ █ ▄▄▀
7
+
8
+ @project Speaking Clock - time announcer using ElevenLabs TTS API
9
+ @author Marcin Orlowski <mail (#) marcinOrlowski (.) com>
10
+ @copyright 2025 Marcin Orlowski
11
+ @license https://www.opensource.org/licenses/mit-license.php MIT
12
+ @link https://github.com/MarcinOrlowski/speaking-clock
13
+ ```
14
+
15
+ # Speaking Clock
16
+
17
+ A small utility that speaks (usually current) time in specified language. Uses ElevenLabs API
18
+ to generate the speech. Supports caching and reusing audio files so free ElevenLabs
19
+ access is more than enough. Handy to sit in cron jobs to periodically announce the time.
20
+
21
+ ## Features
22
+
23
+ - Gets the current time and speaks it in specified language
24
+ - Converts numbers to their Polish word representation (e.g., "13:05" → "trzynasta pięć")
25
+ - Uses ElevenLabs API for high-quality text-to-speech
26
+ - Caches generated audio files for quick reuse
27
+ - Supports both 12-hour and 24-hour time formats
28
+ - Optional audio chime before speaking the time
29
+ - Parallel processing - prepares audio while chime is playing
30
+ - Overlaid audio playback with configurable timing offset
31
+ - Command-line interface driven, perfect for background jobs like cron
32
+
33
+ ## Installation
34
+
35
+ This app is regular Python package and is also hosted
36
+ on [PyPi](https://pypi.org/project/speaking-clock/) so
37
+ you can install it as usual. But because this one is supposed to rather act as the application, I
38
+ strongly recommend to use [pipx](https://pipx.pypa.io/) to install this tool in isolated
39
+ environment be it on Linux, Windows or MacOS machines. Once you got `pipx` up
40
+ and running, install the package:
41
+
42
+ ```bash
43
+ $ pipx install speaking-clock
44
+ ```
45
+
46
+ Of course, you can also use plain `pip` to do that:
47
+
48
+ ```bash
49
+ $ pip install speaking-clock
50
+ ```
51
+
52
+ But that might be a problem as some distributions no longer allow system-wide installations,
53
+ therefore use of `pipx` is strongly recommended as the all-in-one solution.
54
+
55
+ Once installed `speaking-clock` executable (and it's alias `speak-time`) should be available in
56
+ your system ready to be used. Please use `--help` to see all available options.
57
+
58
+ ## Usage
59
+
60
+ ### As a command-line tool
61
+
62
+ Once installed, you can use the command-line interface:
63
+
64
+ ```
65
+ speak-time
66
+ ```
67
+
68
+ You can specify a custom config file:
69
+
70
+ ```
71
+ speak-time --config /path/to/your/config.yml
72
+ ```
73
+
74
+ ### Configuration
75
+
76
+ The speaking-clock looks for configuration in the following places:
77
+
78
+ 1. Command-line specified config (if provided)
79
+ 1. User config file at `~/.config/speaking-clock/config.yml`
80
+ 1. Default configuration built into the package
81
+
82
+ You can create a config file at `~/.config/speaking-clock/config.yml` with the following structure:
83
+
84
+ ```yaml
85
+ language:
86
+ code: "pl" # Language code matching a file in 'languages/' directory
87
+ use_24h_clock: true # Use 24-hour (true) or 12-hour (false) format
88
+
89
+ elevenlabs:
90
+ api_key: "your-api-key-here" # Your ElevenLabs API key
91
+ voice_id: "voice-id-here" # ElevenLabs voice ID
92
+ model_id: "eleven_multilingual_v2" # TTS model to use
93
+
94
+ audio:
95
+ play_chime: true # Play a chime before speaking the time
96
+ chime_file: "clock-chime.mp3" # Path to the chime audio file
97
+ overlay_speech: true # Overlay speech over the chime sound
98
+ speech_offset_ms: 1000 # Milliseconds to wait before starting speech
99
+
100
+ cache:
101
+ directory: ".cache" # Directory for caching audio files
102
+ ```
103
+
104
+ You can also set your ElevenLabs API key as an environment variable:
105
+
106
+ ```
107
+ export ELEVENLABS_API_KEY="your-api-key-here"
108
+ ```
109
+
110
+ ## Language Support
111
+
112
+ The application supports multiple languages through YAML language definition files. These files are stored in the `languages/` directory with filenames matching their language code (e.g., `pl.yml` for Polish).
113
+
114
+ To add support for a new language:
115
+
116
+ 1. Create a new YAML file in the `languages/` directory (e.g., `en.yml` for English)
117
+ 1. Define the language elements following the structure in the existing language files
118
+ 1. Update the `language.code` value in `config.yml` to match your new language file
119
+
120
+ Example language file structure:
121
+
122
+ ```yaml
123
+ days_of_week:
124
+ - poniedziałek # Monday
125
+ - wtorek # Tuesday
126
+ # ...
127
+
128
+ hours:
129
+ 0: dwudziesta czwarta
130
+ 1: pierwsza
131
+ # ...
132
+
133
+ special_minutes:
134
+ 0: ""
135
+ 15: piętnaście
136
+ # ...
137
+
138
+ special_times:
139
+ midnight: północ, nastał {day_name}
140
+ ```
141
+
142
+ ## Cache Files
143
+
144
+ Audio files are automatically cached in the `.cache` directory using the following naming convention:
145
+
146
+ ```
147
+ LANG-VOICE-HH-MM.mp3
148
+ ```
149
+
150
+ For example:
151
+
152
+ ```
153
+ pl-voice_id-13-05.mp3 # Polish, voice_id, 13:05
154
+ ```
155
+
156
+ This caching system ensures that each unique time announcement is only generated once, reducing API calls to ElevenLabs and improving response time for frequently requested times.
157
+
158
+ # Audio Support for Cron Jobs in KDE 5
159
+
160
+ ## Problem
161
+
162
+ When running Python applications from cron jobs in KDE 5, audio playback doesn't work automatically. This is because cron jobs run in a separate environment without access to your desktop session's audio system.
163
+
164
+ ## Solution
165
+
166
+ Configure the cron job with specific environment variables to access your KDE desktop session's audio services.
167
+
168
+ ### Required Environment Variables
169
+
170
+ For audio playback in KDE 5, your cron job needs these key environment variables:
171
+
172
+ - `DISPLAY`: Points to your X server display
173
+ - `DBUS_SESSION_BUS_ADDRESS`: Connects to your D-Bus session
174
+ - `XDG_RUNTIME_DIR`: Required for PulseAudio/PipeWire access
175
+
176
+ ### Setting Up the Cron Job
177
+
178
+ Edit your crontab:
179
+
180
+ ```bash
181
+ crontab -e
182
+ ```
183
+
184
+ Add your job using this template:
185
+
186
+ ```bash
187
+ # Run every hour at minute 0
188
+ 0 * * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME plasma-session)/environ | cut -d= -f2-) XDG_RUNTIME_DIR=/run/user/$(id -u) python /path/to/your/script.py
189
+ ```
190
+
191
+ ### Testing Your Configuration
192
+
193
+ To test without waiting for the scheduled time:
194
+
195
+ ```bash
196
+ # Test the exact command that cron will run
197
+ DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME plasma-session)/environ | cut -d= -f2-) XDG_RUNTIME_DIR=/run/user/$(id -u) python /path/to/your/script.py
198
+ ```
199
+
200
+ ## Troubleshooting
201
+
202
+ ### Common Issues and Solutions
203
+
204
+ 1. **No audio despite correct configuration**:
205
+
206
+ - Ensure PulseAudio is running: `pulseaudio --check`
207
+ - Try adding `PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native` to your environment variables
208
+
209
+ 1. **D-Bus address not found**:
210
+
211
+ - If plasma-session isn't found, try: `pgrep -u $LOGNAME plasmashell` instead
212
+
213
+ 1. **Permission issues**:
214
+
215
+ - Check audio group membership: `groups | grep audio`
216
+ - Add yourself if needed: `sudo usermod -a -G audio $USER`
217
+
218
+ 1. **Application-specific audio servers**:
219
+
220
+ - For PipeWire: Add `PIPEWIRE_RUNTIME_DIR=${XDG_RUNTIME_DIR}/pipewire-0`
221
+
222
+ ## Limitations
223
+
224
+ This solution only works when:
225
+
226
+ - You are logged into your KDE session
227
+ - You are using the same user account for both KDE and the cron job
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "speaking-clock"
7
+ version = "1.0.0"
8
+ description = "A clock that speaks the current time using ElevenLabs API"
9
+ readme = "README.md"
10
+ requires-python = ">=3.7"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Marcin Orlowski", email = "mail@marcinorlowski.com"}
14
+ ]
15
+ dependencies = [
16
+ "elevenlabs",
17
+ "PyYAML",
18
+ "python-dateutil",
19
+ "num2words",
20
+ ]
21
+ classifiers = [
22
+ "Programming Language :: Python :: 3",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ ]
26
+
27
+ [project.scripts]
28
+ speaking-clock = "speaking_clock.cli:main"
29
+ speak-time = "speaking_clock.cli:main"
30
+
31
+ [tool.setuptools.packages.find]
32
+ include = ["speaking_clock", "speaking_clock.*"]
33
+
34
+ [tool.setuptools.package-data]
35
+ speaking_clock = ["data/*.mp3", "data/defaults/*.yml", "languages/*.yml"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ ##################################################################################
4
+ #
5
+ # ▄▀▀▄ █ ▀ ▄▀▀▄ ▀█ █
6
+ # ▀▄▄ █▀▀▄ ▄▀▀▄ ▄▀▀▄ █ ▄▀ ▀█ █▀▀▄ ▄▀▀█ █ █ ▄▀▀▄ ▄▀▀▄ █ ▄▀
7
+ # █ █ █ █▀▀ ▄▄█ █▀▄ █ █ █ █ █ █ █ █ █ █ █▀▄
8
+ # ▀▄▄▀ █▄▄▀ ▀▄▄▀ ▀▄▄▀ █ █ ▄█▄ █ █ ▀▄▄█ ▀▄▄▀ ▄█▄ ▀▄▄▀ ▀▄▄▀ █ █
9
+ # █ ▄▄▀
10
+ #
11
+ # @project Speaking Clock - time announcer using ElevenLabs TTS API
12
+ # @author Marcin Orlowski <mail (#) marcinOrlowski (.) com>
13
+ # @copyright 2025 Marcin Orlowski
14
+ # @license https://www.opensource.org/licenses/mit-license.php MIT
15
+ # @link https://github.com/MarcinOrlowski/speaking-clock
16
+ #
17
+ ##################################################################################
18
+ #
19
+ # python -m venv venv
20
+ # source venv/bin/activate
21
+ # pip install -r requirements-dev.txt
22
+ # python -m build
23
+ # # Reinstall the app (do not do "install --upgrade" as cached bytecode can not be updated)
24
+ # pip uninstall --yes dist/speaking_clock-1.0.0-py3-none-any.whl
25
+ # # intentionally no --upgrade for install to enforce conflict if not uninstalled fully first.
26
+ # pip install dist/spaking_clock-1.0.0-py3-none-any.whl
27
+ # twine upload dist/*
28
+ #
29
+ """
30
+
31
+ import os
32
+ from setuptools import setup, find_packages
33
+
34
+ # Read the contents of README.md
35
+ with open('README.md', 'r', encoding='utf-8') as fh:
36
+ long_description = fh.read()
37
+
38
+ setup(
39
+ name="speaking-clock",
40
+ version="1.0.0",
41
+ author="Marcin Orlowski",
42
+ author_email="info@marcinorlowski.com",
43
+ description="A clock that speaks the current time using ElevenLabs API",
44
+ long_description=long_description,
45
+ long_description_content_type="text/markdown",
46
+ url="https://github.com/example/speaking-clock",
47
+ packages=find_packages(),
48
+ install_requires=[
49
+ 'elevenlabs',
50
+ 'PyYAML',
51
+ 'python-dateutil',
52
+ 'num2words',
53
+ ],
54
+ classifiers=[
55
+ "Programming Language :: Python :: 3",
56
+ "License :: OSI Approved :: MIT License",
57
+ "Operating System :: OS Independent",
58
+ ],
59
+ python_requires='>=3.7',
60
+ entry_points={
61
+ 'console_scripts': [
62
+ 'speak-time=speaking_clock.cli:main',
63
+ ],
64
+ },
65
+ package_data={
66
+ 'speaking_clock': [
67
+ 'data/*.mp3',
68
+ 'data/defaults/config.yml',
69
+ 'languages/*.yml',
70
+ ],
71
+ },
72
+ include_package_data=True,
73
+ )
@@ -0,0 +1,18 @@
1
+ """
2
+ Speaking Clock - A Python package that speaks the current time
3
+ using ElevenLabs API and caches audio for reuse
4
+ """
5
+
6
+ from .clock import SpeakingClock
7
+ from .config import ConfigManager
8
+ from .audio import AudioCache
9
+ from .utils.number_converter import PolishTimeFormatter, PolishNumberConverter
10
+
11
+ __version__ = "0.1.0"
12
+ __author__ = "Carlos"
13
+ __email__ = "carlos@example.com"
14
+
15
+ # Expose main function for easy imports
16
+ def speak_time():
17
+ """Main entry point to speak the current time"""
18
+ SpeakingClock().speak_time()
@@ -0,0 +1,84 @@
1
+ """
2
+ ##################################################################################
3
+ #
4
+ # ▄▀▀▄ █ ▀ ▄▀▀▄ ▀█ █
5
+ # ▀▄▄ █▀▀▄ ▄▀▀▄ ▄▀▀▄ █ ▄▀ ▀█ █▀▀▄ ▄▀▀█ █ █ ▄▀▀▄ ▄▀▀▄ █ ▄▀
6
+ # █ █ █ █▀▀ ▄▄█ █▀▄ █ █ █ █ █ █ █ █ █ █ █▀▄
7
+ # ▀▄▄▀ █▄▄▀ ▀▄▄▀ ▀▄▄▀ █ █ ▄█▄ █ █ ▀▄▄█ ▀▄▄▀ ▄█▄ ▀▄▄▀ ▀▄▄▀ █ █
8
+ # █ ▄▄▀
9
+ #
10
+ # @project Speaking Clock - time announcer using ElevenLabs TTS API
11
+ # @author Marcin Orlowski <mail (#) marcinOrlowski (.) com>
12
+ # @copyright 2025 Marcin Orlowski
13
+ # @license https://www.opensource.org/licenses/mit-license.php MIT
14
+ # @link https://github.com/MarcinOrlowski/speaking-clock
15
+ #
16
+ ##################################################################################
17
+
18
+ Audio caching functionality for the speaking clock
19
+ """
20
+
21
+ import os
22
+ from pathlib import Path
23
+ from typing import Optional
24
+
25
+
26
+ class AudioCache:
27
+ """Audio cache manager for speaking clock"""
28
+ def __init__(self, cache_dir: str, language: str):
29
+ self.base_dir = Path(os.path.expanduser(cache_dir))
30
+ self.base_dir.mkdir(parents=True, exist_ok=True)
31
+ self.language = language
32
+
33
+ def get_cache_filename(self, voice_id: str, hour: int, minute: int) -> str:
34
+ """
35
+ Get cache filename using the format: LANG-VOICE-HH-MM.mp3 (lowercased)
36
+
37
+ Args:
38
+ voice_id: ElevenLabs voice ID or name
39
+ hour: Hour (00-23)
40
+ minute: Minute (00-59)
41
+
42
+ Returns:
43
+ Cache filename
44
+ """
45
+ return f"{self.language}-{voice_id}-{hour:02d}-{minute:02d}.mp3".lower()
46
+
47
+ def get_cached_file_path(self, voice_id: str, hour: int, minute: int) -> Path:
48
+ """Get full path for a cached audio file"""
49
+ filename = self.get_cache_filename(voice_id, hour, minute)
50
+ return self.base_dir / filename
51
+
52
+ def get_cached_audio(self, voice_id: str, hour: int, minute: int) -> Optional[Path]:
53
+ """
54
+ Get cached audio file if it exists
55
+
56
+ Args:
57
+ voice_id: ElevenLabs voice ID
58
+ hour: Hour (0-23)
59
+ minute: Minute (0-59)
60
+
61
+ Returns:
62
+ Path to cached file or None if not found
63
+ """
64
+ cache_path = self.get_cached_file_path(voice_id, hour, minute)
65
+ return cache_path if cache_path.exists() else None
66
+
67
+ def save_audio(self, audio_data: bytes, voice_id: str, hour: int, minute: int) -> Path:
68
+ """
69
+ Save audio data to cache
70
+
71
+ Args:
72
+ audio_data: Audio data bytes
73
+ voice_id: ElevenLabs voice ID
74
+ hour: Hour (0-23)
75
+ minute: Minute (0-59)
76
+
77
+ Returns:
78
+ Path to cached file
79
+ """
80
+ cache_path = self.get_cached_file_path(voice_id, hour, minute)
81
+ with open(cache_path, 'wb') as file:
82
+ file.write(audio_data)
83
+
84
+ return cache_path