Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 38 additions & 26 deletions mawaqit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,16 @@ Also requires `pkill` (part of `procps`, present on virtually every distro by
default) — used to stop azan playback, since neither player exposes its own
stop control.

Azan audio is **not bundled**. To enable it:
Three Azan tracks are bundled in `assets/azan1.mp3`, `assets/azan2.mp3`, and
`assets/azan3.mp3`, matching the legacy V4 plugin. In Settings → Plugins →
Mawaqit, turn on **Play Azan** and select a track from **Azan audio**.

1. Get your own azan `.mp3` file(s) from wherever you like.
2. Copy them into this plugin's `assets/` folder, named exactly `azan1.mp3`,
`azan2.mp3`, and/or `azan3.mp3` (only the ones you want to use — you don't
need all three).
3. In Settings → Plugins → Mawaqit, turn on **Play Azan** and pick which of
the three slots to play from **Azan audio**.

If the selected file isn't present, azan is silently skipped and a line is
logged — nothing else is affected.

## Usage

- **Left click** the bar widget → open the prayer times panel.
- **Right click** the bar widget → cycle its display mode: live countdown →
static time → prayer name only.
static time → prayer name only. While azan is playing, right click stops it.

Toggle the panel directly:

Expand All @@ -48,8 +41,15 @@ noctalia msg panel-toggle ycf/mawaqit:panel

The panel shows all five daily prayers plus Sunrise and, during Ramadan, Imsak,
with a live countdown banner to whichever is next, the Gregorian and Hijri
date, and a refresh button. If azan is playing, a stop button appears next to
it.
date, and a refresh button. Its Calendar tab provides Hijri-month navigation,
Gregorian day overlays, and a configurable week start. If azan is playing, a
stop button appears next to it. The panel header also opens this plugin's
settings.

Calendar conversion data is fetched by the background service and cached for
30 days (up to 24 Hijri months). The calendar marks Islamic events, shows an
upcoming-event hint, rotates a daily hadith, and displays the Ramadan last-ten-
nights message when applicable.

## Settings

Expand All @@ -60,12 +60,15 @@ Plugin-level (Settings → Plugins → Mawaqit):
| `city` | `string` | `London` | Your city name in English. |
| `country` | `string` | `UK` | Country name or 2-letter code. |
| `method` | `select` | `3` (MWL) | Calculation authority followed in your region. |
| `fajrAngle` | `string` | `""` | Fajr angle for Custom Method, a decimal greater than 0 and less than 90. |
| `ishaAngle` | `string` | `""` | Isha angle for Custom Method, a decimal greater than 0 and less than 90. |
| `school` | `select` | `0` (Shafi/Maliki/Hanbali) | Asr convention — Hanafi uses a later shadow factor. |
| `hijriDayOffset` | `select` | `0` | Shift the displayed Hijri day by −1/0/+1 if it doesn't match local moon sighting. |
| `weekStartDay` | `select` | `1` (Monday) | First day of the Hijri calendar week. |
| `twelveHourFormat` | `bool` | `false` | Show prayer times as 12-hour (e.g. `5:23 AM`) instead of 24-hour. |
| `showNotifications` | `bool` | `true` | Show a system notification when each prayer time begins. |
| `showNotifications` | `bool` | `true` | Show a system notification when each prayer time and Ramadan Imsak begin. |
| `playAzan` | `bool` | `false` | Play an azan audio file when each prayer time begins. |
| `azanFile` | `select` | `azan1.mp3` | Which bundled azan track to play (see Requirements for setup). |
| `azanFile` | `select` | `azan1.mp3` | Which user-supplied azan file slot to play (see Requirements for setup). |
| `tune` | `bool` | `false` | Enable the per-prayer minute offsets below. |
| `tuneFajr` | `int` | `0` | Fajr offset, in minutes (−60 to 60). |
| `tuneDhuhr` | `int` | `0` | Dhuhr offset, in minutes. |
Expand Down Expand Up @@ -100,19 +103,28 @@ Set the bar widget's display mode directly:
noctalia msg plugin ycf/mawaqit:bar all mode countdown|static|name
```

Preview the selected local azan file without enabling **Play Azan**:

```sh
noctalia msg plugin ycf/mawaqit:fetcher all preview-azan
```

## Notes

- The background service fetches prayer times once daily from
`api.aladhan.com`, sending the configured city/country/method/school as
query parameters, plus a second request for the next day's Fajr time (used
for the countdown after Isha).
- Azan playback runs `paplay` or `pw-cat` against a file **you supply** (see
Requirements) — no audio is bundled with this plugin. Playback is stopped
by matching the exact file path being played (via `pkill -f`), not a
generic pattern — this is the only termination method available since the
plugin API doesn't currently expose a PID or stop handle for spawned
processes. Stopping happens when the plugin exits or is disabled, or
manually from the panel while azan is playing.
- The background service fetches the current month's prayer calendar once
daily from `api.aladhan.com`, sending the configured
city/country/method/school as query parameters. It falls back to a
single-day request and retries failures with bounded backoff. A second
request fetches the next day's Fajr time for the countdown after Isha.
- The current month's calendar is stored in the plugin data directory and is
reused immediately after a restart or while the network is unavailable,
provided the location, calculation method, school, and month still match.
- Azan playback runs `paplay` or `pw-cat` against the selected bundled file.
Playback is stopped by matching the exact file path being played (via
`pkill -f`), not a generic pattern — this is the only termination method
available since the plugin API doesn't currently expose a PID or stop
handle for spawned processes. Stopping happens when the plugin exits or is
disabled, or manually from the panel while azan is playing.
- The Arabic Hijri date and prayer-time banner are rendered with the bundled
Reem Kufi font (`ReemKufi.ttf`), licensed under the SIL Open Font License —
see `OFL.txt`.
Expand Down
Binary file added mawaqit/assets/azan1.mp3
Binary file not shown.
Binary file added mawaqit/assets/azan2.mp3
Binary file not shown.
Binary file added mawaqit/assets/azan3.mp3
Binary file not shown.
31 changes: 31 additions & 0 deletions mawaqit/bar_widget.luau
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ local displayMode = MODE_COUNTDOWN
local hasData = false
local errorMsg = ""
local isJumuah = false
local azanPlaying = false

-- ── Helpers ───────────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -122,6 +123,15 @@ end
-- ── Display ───────────────────────────────────────────────────────────────────

local function updateDisplay()
if azanPlaying then
barWidget.setGlyph("player-stop-filled")
barWidget.setText("Azan")
barWidget.setColor(activeColor ~= "" and activeColor or "primary")
barWidget.setGlyphColor(activeColor ~= "" and activeColor or "primary")
barWidget.setTooltip("Azan playing - right-click to stop")
return
end

if not hasData then
barWidget.setGlyph(widgetIcon ~= "" and widgetIcon or "building-mosque")
barWidget.setText(errorMsg ~= "" and "!" or "...")
Expand All @@ -133,6 +143,8 @@ local function updateDisplay()

local currentIdx, nextIdx, secondsToNext, secondsElapsed = findCurrentPrayer()
local displayPrayer, isActive, timeStr = nil, false, ""
local isNow = currentIdx ~= nil and secondsElapsed ~= nil
and secondsElapsed >= 0 and secondsElapsed < 300

local showingElapsed = false
if showElapsed and currentIdx ~= nil and secondsElapsed ~= nil then
Expand All @@ -152,6 +164,10 @@ local function updateDisplay()
elseif displayMode == MODE_STATIC then
timeStr = prayers[currentIdx].time
end
elseif isNow and currentIdx ~= nil then
displayPrayer = prayers[currentIdx].name
isActive = true
if displayMode ~= MODE_NAME_ONLY then timeStr = "now" end
elseif secondsToNext ~= nil and secondsToNext <= 60 then
isActive = true
if displayMode ~= MODE_NAME_ONLY then timeStr = "now" end
Expand All @@ -172,6 +188,10 @@ local function updateDisplay()
elseif displayMode == MODE_STATIC then
timeStr = prayers[currentIdx].time
end
elseif isNow and currentIdx ~= nil then
displayPrayer = prayers[currentIdx].name
isActive = true
if displayMode ~= MODE_NAME_ONLY then timeStr = "now" end
elseif secondsToNext ~= nil then
if displayMode == MODE_COUNTDOWN and showCountdown then
timeStr = formatCountdown(secondsToNext)
Expand Down Expand Up @@ -228,6 +248,11 @@ noctalia.state.watch("isJumuah", function(val)
isJumuah = (val == true)
end)

noctalia.state.watch("azanPlaying", function(val)
azanPlaying = (val == true)
updateDisplay()
end)

noctalia.state.watch("error", function(val)
if type(val) == "string" and val ~= "" then
errorMsg = val
Expand All @@ -246,6 +271,10 @@ function onClick()
end

function onRightClick()
if azanPlaying then
noctalia.state.set("command", { action = "stopAzan" })
return
end
if displayMode == MODE_COUNTDOWN then
displayMode = MODE_STATIC
elseif displayMode == MODE_STATIC then
Expand Down Expand Up @@ -285,5 +314,7 @@ local existingTomorrow = noctalia.state.get("tomorrowFajr")
if existingTomorrow then tomorrowFajr = tonumber(existingTomorrow) end
local existingJumuah = noctalia.state.get("isJumuah")
if existingJumuah ~= nil then isJumuah = (existingJumuah == true) end
local existingAzan = noctalia.state.get("azanPlaying")
if existingAzan ~= nil then azanPlaying = (existingAzan == true) end

updateDisplay()
Loading
Loading