salat 3.1.0 → 3.2.0
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.
- package/README.md +215 -23
- package/dist/app.js +58 -0
- package/dist/constants.js +13 -0
- package/dist/data/prayers.json +20 -0
- package/dist/types.js +2 -0
- package/dist/utils.js +76 -0
- package/package.json +15 -7
- package/{app.js → src/app.ts} +27 -19
- package/src/constants.ts +13 -0
- package/src/data/cities.json +766 -0
- package/src/types.ts +15 -0
- package/src/utils.ts +86 -0
- package/tsconfig.json +15 -0
- package/constants.js +0 -18
- package/utils.js +0 -80
- /package/{data → dist/data}/cities.json +0 -0
- /package/{data → src/data}/prayers.json +0 -0
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Salat [](https://badge.fury.io/js/salat)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PLEASE SUPPORT THIS REPO WITH A STAR ⭐🌟💫
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Description
|
|
6
6
|
|
|
7
|
+
> Daily prayer time in all the cities in [Morocco](https://www.google.com/search?q=morocco) , directly in your terminal, at the tip of your fingers
|
|
7
8
|
|
|
8
9
|
**A stupid simple Command line utility to get the daily prayers time for all the citiy in Morocco**
|
|
9
10
|
|
|
@@ -11,6 +12,215 @@ The source of the data is [the Moroccan Ministery Website](http://www.habous.gov
|
|
|
11
12
|
|
|
12
13
|
## Getting started
|
|
13
14
|
|
|
15
|
+
```bash
|
|
16
|
+
npx salat [cityName]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Please note that if the cityName contains space of `'` you need to use quotes, example
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx salat "el jadida"
|
|
23
|
+
npx salat "L'msid"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## City List
|
|
27
|
+
|
|
28
|
+
This is an exhaustive list of the supported cities :
|
|
29
|
+
|
|
30
|
+
- Agadir
|
|
31
|
+
- Ahfir
|
|
32
|
+
- Ain Aouda
|
|
33
|
+
- Aïn Chaïr
|
|
34
|
+
- Ait El Kak
|
|
35
|
+
- Ait Ourir
|
|
36
|
+
- Akayouar
|
|
37
|
+
- Akdal Amelchil
|
|
38
|
+
- Akdez
|
|
39
|
+
- Akhefnir
|
|
40
|
+
- Akka
|
|
41
|
+
- Aknoul
|
|
42
|
+
- Akoudal Amelchil Midelt
|
|
43
|
+
- Amkala
|
|
44
|
+
- Amsmrir
|
|
45
|
+
- Araich
|
|
46
|
+
- Arbaoua
|
|
47
|
+
- Arfoud
|
|
48
|
+
- Asa
|
|
49
|
+
- Askin
|
|
50
|
+
- Asoul
|
|
51
|
+
- Assila
|
|
52
|
+
- Azemmour
|
|
53
|
+
- Azilal
|
|
54
|
+
- Azrou
|
|
55
|
+
- Bab Bared
|
|
56
|
+
- Ben Ahmed
|
|
57
|
+
- Ben Slimane
|
|
58
|
+
- Bengrir
|
|
59
|
+
- Beni Adrar
|
|
60
|
+
- Beni Ansar
|
|
61
|
+
- Beni Mellal
|
|
62
|
+
- Beni Tejit
|
|
63
|
+
- Berkane
|
|
64
|
+
- Berrchid
|
|
65
|
+
- Bir Anzaran
|
|
66
|
+
- Bir Kandour
|
|
67
|
+
- Bouanan
|
|
68
|
+
- Bouarfa
|
|
69
|
+
- Bouikra
|
|
70
|
+
- Bouizkaren
|
|
71
|
+
- Boujdour
|
|
72
|
+
- Boukrae
|
|
73
|
+
- Boulmane
|
|
74
|
+
- Boumalen Dadas
|
|
75
|
+
- Bourd
|
|
76
|
+
- Bouskoura
|
|
77
|
+
- Bouznika
|
|
78
|
+
- Casablanca
|
|
79
|
+
- Chefchaouan
|
|
80
|
+
- Chichaoua
|
|
81
|
+
- Dakhla
|
|
82
|
+
- Debdou
|
|
83
|
+
- Demnat
|
|
84
|
+
- Deryouche
|
|
85
|
+
- El Brouj
|
|
86
|
+
- El Gara
|
|
87
|
+
- El Hajeb
|
|
88
|
+
- El Jabha
|
|
89
|
+
- El Jadida
|
|
90
|
+
- El Kasba
|
|
91
|
+
- El Mahbes
|
|
92
|
+
- El Menzel
|
|
93
|
+
- Enif
|
|
94
|
+
- Erich
|
|
95
|
+
- Errachidia
|
|
96
|
+
- Essaouira
|
|
97
|
+
- Ezak
|
|
98
|
+
- Fem Lehsan
|
|
99
|
+
- Fem Zkid
|
|
100
|
+
- Ferkhana
|
|
101
|
+
- Fes
|
|
102
|
+
- Fezouane
|
|
103
|
+
- Figuig
|
|
104
|
+
- Fnideq
|
|
105
|
+
- Fquih Ben Salah
|
|
106
|
+
- Geltat Zamour
|
|
107
|
+
- Guelmim
|
|
108
|
+
- Guercif
|
|
109
|
+
- Hoceima
|
|
110
|
+
- Igherem
|
|
111
|
+
- Ikes
|
|
112
|
+
- Imelchil
|
|
113
|
+
- Imin Telat
|
|
114
|
+
- Imntanout
|
|
115
|
+
- Imouzzer Kandar
|
|
116
|
+
- Jerada
|
|
117
|
+
- Kalaat Megouna
|
|
118
|
+
- Kalaat Sraghna
|
|
119
|
+
- Kares
|
|
120
|
+
- Kariat Ba Mohammed
|
|
121
|
+
- Kasbah Tadla
|
|
122
|
+
- Katara
|
|
123
|
+
- Kelmima
|
|
124
|
+
- Kénitra
|
|
125
|
+
- Ketama
|
|
126
|
+
- Khemis Sidi Abd Jelil
|
|
127
|
+
- Khemis Zemamra
|
|
128
|
+
- Khémissat
|
|
129
|
+
- Khenifra
|
|
130
|
+
- Khouribga
|
|
131
|
+
- Ksar El Kebir
|
|
132
|
+
- Ksar El Sghir
|
|
133
|
+
- Ksar Ich
|
|
134
|
+
- L'msid
|
|
135
|
+
- Laayoune
|
|
136
|
+
- Laayoune Sidi Mellouk
|
|
137
|
+
- Lagouira
|
|
138
|
+
- Marrakech
|
|
139
|
+
- Martil
|
|
140
|
+
- Mediek
|
|
141
|
+
- Meknes
|
|
142
|
+
- Melilla
|
|
143
|
+
- Meskoura
|
|
144
|
+
- Metmata
|
|
145
|
+
- Midelt
|
|
146
|
+
- Misour
|
|
147
|
+
- Mohammedia
|
|
148
|
+
- Moulay Bouaza
|
|
149
|
+
- Moulay Bousselham
|
|
150
|
+
- Moulay Yacoub
|
|
151
|
+
- Nador
|
|
152
|
+
- Oualidia
|
|
153
|
+
- Ouazane
|
|
154
|
+
- Oued Amlil
|
|
155
|
+
- Oued Law
|
|
156
|
+
- Oued Zam
|
|
157
|
+
- Oujda
|
|
158
|
+
- Oulad Ayad
|
|
159
|
+
- Oulad Tayma
|
|
160
|
+
- Oulmes
|
|
161
|
+
- Ourzazate
|
|
162
|
+
- Ousered
|
|
163
|
+
- Rabat
|
|
164
|
+
- Ras Alma
|
|
165
|
+
- Remani
|
|
166
|
+
- Rhamna
|
|
167
|
+
- Ribate El Kheir
|
|
168
|
+
- Risani
|
|
169
|
+
- Safi
|
|
170
|
+
- Saïdia
|
|
171
|
+
- Sebta
|
|
172
|
+
- Sefrou
|
|
173
|
+
- Selouane
|
|
174
|
+
- Settat
|
|
175
|
+
- Sidi Benour
|
|
176
|
+
- Sidi Ghanem
|
|
177
|
+
- Sidi Ifni
|
|
178
|
+
- Sidi Kacém
|
|
179
|
+
- Sidi Slimane
|
|
180
|
+
- Sidi Yahya Gharb
|
|
181
|
+
- Smara
|
|
182
|
+
- Souq Arbiâ Gharb
|
|
183
|
+
- Tafntan
|
|
184
|
+
- Tafougalt
|
|
185
|
+
- Tafraouet
|
|
186
|
+
- Tahla
|
|
187
|
+
- Tahla
|
|
188
|
+
- Talouine
|
|
189
|
+
- Talsint
|
|
190
|
+
- Tamslouhet
|
|
191
|
+
- Tanger
|
|
192
|
+
- Tantan
|
|
193
|
+
- Taounat
|
|
194
|
+
- Taourirt
|
|
195
|
+
- Tarfaya
|
|
196
|
+
- Taroudant
|
|
197
|
+
- Tasltanet
|
|
198
|
+
- Tata
|
|
199
|
+
- Taza
|
|
200
|
+
- Tazarin
|
|
201
|
+
- Tefariti
|
|
202
|
+
- Temnar
|
|
203
|
+
- Tendrara
|
|
204
|
+
- Tenghir
|
|
205
|
+
- Tenjedad
|
|
206
|
+
- Tetouan
|
|
207
|
+
- Tiflet
|
|
208
|
+
- Tindit
|
|
209
|
+
- Tisa
|
|
210
|
+
- Tisenet
|
|
211
|
+
- Tizi Ousli
|
|
212
|
+
- Tiznit
|
|
213
|
+
- Toulkoult
|
|
214
|
+
- Yefrin
|
|
215
|
+
- Yousofia
|
|
216
|
+
- Zagoura
|
|
217
|
+
- Zaouiat Ahansal
|
|
218
|
+
- Zaouiat Moulay Ibrahim
|
|
219
|
+
- Zayou
|
|
220
|
+
- Zerhoune
|
|
221
|
+
|
|
222
|
+
Alternatively You can also install it globally
|
|
223
|
+
|
|
14
224
|
```bash
|
|
15
225
|
# Install
|
|
16
226
|
|
|
@@ -25,33 +235,16 @@ $ salat
|
|
|
25
235
|
$ salat [cityName]
|
|
26
236
|
```
|
|
27
237
|
|
|
28
|
-
Alternatively, if you don't want to install it globally, you can just use:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npx salat
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
`City name should be provided the same way it's written in the cities.json`
|
|
35
|
-
|
|
36
238
|
## Output
|
|
37
239
|
|
|
38
240
|
```bash
|
|
39
241
|
# The programs prints to the console the prayers' time for the current day in the default city as shown bellow:
|
|
40
242
|
```
|
|
243
|
+
|
|
41
244
|

|
|
42
245
|

|
|
43
246
|

|
|
44
247
|
|
|
45
|
-
|
|
46
|
-
## Dependecies
|
|
47
|
-
|
|
48
|
-
The code behind depends on :
|
|
49
|
-
|
|
50
|
-
- [axios](https://github.com/axios/axios) to make an http request ( fetch the data).
|
|
51
|
-
- [jsdom](https://github.com/jsdom/jsdom) to parse the html result.
|
|
52
|
-
- [chalk](https://github.com/chalk/chalk) to avoid boring styles and colors.
|
|
53
|
-
- [node-localstorage](https://github.com/lmaccherone/node-localstorage) to read and write from localstorage.
|
|
54
|
-
|
|
55
248
|
## Change the default city
|
|
56
249
|
|
|
57
250
|
- The default city is :heart: [Marrakech](https://www.google.com/search?q=marrakech) :heart:, set as a value for the `DEFAULT_CITY` variable in `./constants.js`
|
|
@@ -68,10 +261,9 @@ The code behind depends on :
|
|
|
68
261
|
|
|
69
262
|
- [x] Use a default city
|
|
70
263
|
- [x] Use localstorage-like api for caching purposes
|
|
71
|
-
- [x] Display execution time
|
|
72
264
|
- [ ] Improve performance
|
|
73
265
|
- [ ] Add unit tests
|
|
74
|
-
- [
|
|
266
|
+
- [x] Add a documentation site
|
|
75
267
|
- [ ] Command to set the default city
|
|
76
268
|
- [ ] Command to display the list of available cities
|
|
77
269
|
- [ ] Command to display the time table for the whole month
|
|
@@ -80,4 +272,4 @@ The code behind depends on :
|
|
|
80
272
|
|
|
81
273
|
This project is under the MIT license.
|
|
82
274
|
|
|
83
|
-
### Built With
|
|
275
|
+
### Built With 💖 in Ramadan
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
// Project's dependencies
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
// Project's data
|
|
11
|
+
const constants_1 = require("./constants");
|
|
12
|
+
const cities_json_1 = __importDefault(require("./data/cities.json"));
|
|
13
|
+
// Setting up localStorage
|
|
14
|
+
const node_localstorage_1 = require("node-localstorage");
|
|
15
|
+
const args = process.argv;
|
|
16
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
17
|
+
// Logging function
|
|
18
|
+
const green = (msg) => console.log(chalk_1.default.green(msg));
|
|
19
|
+
// Cast citiesData to City[] properly
|
|
20
|
+
const cities = cities_json_1.default;
|
|
21
|
+
const localStorage = new node_localstorage_1.LocalStorage(constants_1.LOCAL_STORAGE_PATH);
|
|
22
|
+
const cityNameArg = args[2];
|
|
23
|
+
const cityName = (0, utils_1.getCityName)(cityNameArg, cities);
|
|
24
|
+
// Convert string ID to number since getCityId returns number and getData expects number
|
|
25
|
+
const cityId = (0, utils_1.getCityId)(cityName, cities);
|
|
26
|
+
const main = async () => {
|
|
27
|
+
// Printing a banner ('cause I'm cool and I can do it XD)
|
|
28
|
+
green(constants_1.BANNER);
|
|
29
|
+
const storageKey = `${cityName.toLowerCase()}_${new Date().toLocaleDateString()}`;
|
|
30
|
+
let item = localStorage.getItem(storageKey);
|
|
31
|
+
// Disable localStorage for local development
|
|
32
|
+
if (process.env.NODE_ENV === "development") {
|
|
33
|
+
console.log("development mode: localStorage is disabled");
|
|
34
|
+
item = null;
|
|
35
|
+
}
|
|
36
|
+
let prayers = null;
|
|
37
|
+
if (item) {
|
|
38
|
+
prayers = JSON.parse(item);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
try {
|
|
42
|
+
const data = await (0, utils_1.getData)(cityId);
|
|
43
|
+
prayers = (0, utils_1.parsePrayerTimesFromResponse)(data);
|
|
44
|
+
localStorage.setItem(storageKey, JSON.stringify(prayers));
|
|
45
|
+
}
|
|
46
|
+
catch (ex) {
|
|
47
|
+
//TODO: Use a more descriptive error message
|
|
48
|
+
console.error("Something went wrong!");
|
|
49
|
+
console.log(ex);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
console.clear();
|
|
54
|
+
(0, utils_1.displayResult)(prayers, cityName);
|
|
55
|
+
};
|
|
56
|
+
(async () => {
|
|
57
|
+
await main();
|
|
58
|
+
})();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LOCAL_STORAGE_PATH = exports.DEFAULT_CITY = exports.NOT_FOUND_ERROR = exports.BANNER = exports.API_URL = void 0;
|
|
4
|
+
exports.API_URL = "https://www.habous.gov.ma/prieres/horaire-api.php";
|
|
5
|
+
exports.BANNER = ``;
|
|
6
|
+
exports.NOT_FOUND_ERROR = `
|
|
7
|
+
Your city was not found in the list
|
|
8
|
+
Using the default city
|
|
9
|
+
----------------------
|
|
10
|
+
You may need to check the spelling
|
|
11
|
+
`;
|
|
12
|
+
exports.DEFAULT_CITY = "Marrakech";
|
|
13
|
+
exports.LOCAL_STORAGE_PATH = "./storage";
|
package/dist/types.js
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.displayResult = exports.parsePrayerTimesFromResponse = exports.getData = exports.getCityId = exports.getCityName = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const domino_1 = __importDefault(require("domino"));
|
|
9
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
10
|
+
const constants_1 = require("./constants");
|
|
11
|
+
const prayers_json_1 = __importDefault(require("./data/prayers.json"));
|
|
12
|
+
const error = (msg) => console.log(chalk_1.default.red(msg));
|
|
13
|
+
const getCityName = (arg, cities) => {
|
|
14
|
+
if (arg == null)
|
|
15
|
+
return constants_1.DEFAULT_CITY;
|
|
16
|
+
const index = getCityIndex(arg, cities);
|
|
17
|
+
if (index === -1) {
|
|
18
|
+
error(constants_1.NOT_FOUND_ERROR);
|
|
19
|
+
return constants_1.DEFAULT_CITY;
|
|
20
|
+
}
|
|
21
|
+
return arg;
|
|
22
|
+
};
|
|
23
|
+
exports.getCityName = getCityName;
|
|
24
|
+
const getCityId = (arg, cities) => {
|
|
25
|
+
const parsed = parseInt(arg);
|
|
26
|
+
if (parsed && cities.length >= parsed) {
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
return getCityIndex(arg, cities) + 1;
|
|
30
|
+
};
|
|
31
|
+
exports.getCityId = getCityId;
|
|
32
|
+
const getCityIndex = (city, cities) => cities.map((e) => e.name.toLowerCase()).indexOf(city.toLowerCase());
|
|
33
|
+
const getData = async (cityId) => {
|
|
34
|
+
const response = await (0, node_fetch_1.default)(`${constants_1.API_URL}?ville=${cityId}`, {});
|
|
35
|
+
return await response.text();
|
|
36
|
+
};
|
|
37
|
+
exports.getData = getData;
|
|
38
|
+
const parsePrayerTimesFromResponse = (response) => {
|
|
39
|
+
const window = domino_1.default.createWindow(response);
|
|
40
|
+
const document = window.document;
|
|
41
|
+
const tds = document.getElementsByTagName("td");
|
|
42
|
+
const prayers = JSON.parse(JSON.stringify(prayers_json_1.default));
|
|
43
|
+
let j = 0;
|
|
44
|
+
for (let i = 1; i < tds.length && j < prayers.length; i += 2) {
|
|
45
|
+
prayers[j].time = tds[i].textContent.trim();
|
|
46
|
+
j++;
|
|
47
|
+
}
|
|
48
|
+
// Transform array to object and return it
|
|
49
|
+
return prayers.reduce((acc, { prayer, time }) => {
|
|
50
|
+
if (time) {
|
|
51
|
+
acc[prayer] = time;
|
|
52
|
+
}
|
|
53
|
+
return acc;
|
|
54
|
+
}, {});
|
|
55
|
+
};
|
|
56
|
+
exports.parsePrayerTimesFromResponse = parsePrayerTimesFromResponse;
|
|
57
|
+
function tConv24(time24) {
|
|
58
|
+
const [hours, minutes] = time24.split(":");
|
|
59
|
+
const hour = Number(hours);
|
|
60
|
+
const formattedHour = hour % 12 || 12;
|
|
61
|
+
const formattedHourWithZero = (formattedHour + "").padStart(2, "0");
|
|
62
|
+
const formattedMinutes = minutes.padStart(2, "0");
|
|
63
|
+
const formattedTime = `${formattedHourWithZero}:${formattedMinutes}`;
|
|
64
|
+
const ampm = hour < 12 ? "AM" : "PM";
|
|
65
|
+
return `${formattedTime} ${ampm}`;
|
|
66
|
+
}
|
|
67
|
+
const displayResult = (prayers, city) => {
|
|
68
|
+
if (!prayers)
|
|
69
|
+
return;
|
|
70
|
+
console.log(` 🧭 ${city}, Morocco\n\n 📆 ${new Date().toDateString()}\n`);
|
|
71
|
+
Object.keys(prayers).forEach((key) => {
|
|
72
|
+
console.log(` ${chalk_1.default.cyan(key.padEnd(7, " "))} --> ${chalk_1.default.green(tConv24(prayers[key]))}`);
|
|
73
|
+
});
|
|
74
|
+
console.log("\n");
|
|
75
|
+
};
|
|
76
|
+
exports.displayResult = displayResult;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "salat",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Daily Moroccan prayers time, right in your console, at the tip of your fingers",
|
|
5
|
-
"homepage": "https://github.
|
|
6
|
-
"main": "app.js",
|
|
5
|
+
"homepage": "https://kafiln.github.io/salat-cli/",
|
|
6
|
+
"main": "dist/app.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"salat": "app.js"
|
|
8
|
+
"salat": "dist/app.js"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"chalk": "^2.4.2",
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
"node-localstorage": "^1.3.1"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"dev": "
|
|
18
|
-
"
|
|
17
|
+
"dev": "ts-node src/app.ts",
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"start": "node dist/app.js",
|
|
20
|
+
"prestart": "npm run build",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
19
22
|
},
|
|
20
23
|
"keywords": [
|
|
21
24
|
"prayers",
|
|
@@ -29,6 +32,11 @@
|
|
|
29
32
|
},
|
|
30
33
|
"license": "MIT",
|
|
31
34
|
"devDependencies": {
|
|
32
|
-
"
|
|
35
|
+
"@types/node": "^25.2.1",
|
|
36
|
+
"@types/node-fetch": "^2.6.13",
|
|
37
|
+
"@types/node-localstorage": "^1.3.3",
|
|
38
|
+
"nodemon": "^3.1.0",
|
|
39
|
+
"ts-node": "^10.9.2",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
33
41
|
}
|
|
34
42
|
}
|
package/{app.js → src/app.ts}
RENAMED
|
@@ -1,33 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Project's dependencies
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import {
|
|
6
|
+
displayResult,
|
|
7
7
|
getCityId,
|
|
8
8
|
getCityName,
|
|
9
|
-
displayResult,
|
|
10
9
|
getData,
|
|
11
10
|
parsePrayerTimesFromResponse,
|
|
12
|
-
}
|
|
13
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
14
|
-
|
|
15
|
-
// Logging functioin
|
|
16
|
-
const green = (msg) => console.log(chalk.green(msg));
|
|
11
|
+
} from "./utils";
|
|
17
12
|
|
|
18
13
|
// Project's data
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
import { BANNER, LOCAL_STORAGE_PATH } from "./constants";
|
|
15
|
+
import citiesData from "./data/cities.json";
|
|
16
|
+
import { City, PrayerTimes } from "./types";
|
|
21
17
|
|
|
22
18
|
// Setting up localStorage
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
import { LocalStorage } from "node-localstorage";
|
|
20
|
+
|
|
21
|
+
const args = process.argv;
|
|
22
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
23
|
+
|
|
24
|
+
// Logging function
|
|
25
|
+
const green = (msg: string) => console.log(chalk.green(msg));
|
|
26
|
+
|
|
27
|
+
// Cast citiesData to City[] properly
|
|
28
|
+
const cities: City[] = citiesData as City[];
|
|
29
|
+
|
|
30
|
+
const localStorage = new LocalStorage(LOCAL_STORAGE_PATH);
|
|
25
31
|
|
|
26
|
-
const
|
|
32
|
+
const cityNameArg = args[2];
|
|
33
|
+
const cityName = getCityName(cityNameArg, cities);
|
|
34
|
+
// Convert string ID to number since getCityId returns number and getData expects number
|
|
27
35
|
const cityId = getCityId(cityName, cities);
|
|
28
36
|
|
|
29
37
|
const main = async () => {
|
|
30
|
-
//
|
|
38
|
+
// Printing a banner ('cause I'm cool and I can do it XD)
|
|
31
39
|
green(BANNER);
|
|
32
40
|
|
|
33
41
|
const storageKey = `${cityName.toLowerCase()}_${new Date().toLocaleDateString()}`;
|
|
@@ -38,19 +46,19 @@ const main = async () => {
|
|
|
38
46
|
console.log("development mode: localStorage is disabled");
|
|
39
47
|
item = null;
|
|
40
48
|
}
|
|
41
|
-
let prayers;
|
|
49
|
+
let prayers: PrayerTimes | null = null;
|
|
42
50
|
|
|
43
51
|
if (item) {
|
|
44
52
|
prayers = JSON.parse(item);
|
|
45
53
|
} else {
|
|
46
54
|
try {
|
|
47
|
-
|
|
55
|
+
const data = await getData(cityId);
|
|
56
|
+
prayers = parsePrayerTimesFromResponse(data);
|
|
48
57
|
localStorage.setItem(storageKey, JSON.stringify(prayers));
|
|
49
58
|
} catch (ex) {
|
|
50
|
-
//TODO: Use a more
|
|
59
|
+
//TODO: Use a more descriptive error message
|
|
51
60
|
console.error("Something went wrong!");
|
|
52
61
|
console.log(ex);
|
|
53
|
-
// console.log(ex);
|
|
54
62
|
return;
|
|
55
63
|
}
|
|
56
64
|
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const API_URL = "https://www.habous.gov.ma/prieres/horaire-api.php";
|
|
2
|
+
|
|
3
|
+
export const BANNER = ``;
|
|
4
|
+
|
|
5
|
+
export const NOT_FOUND_ERROR = `
|
|
6
|
+
Your city was not found in the list
|
|
7
|
+
Using the default city
|
|
8
|
+
----------------------
|
|
9
|
+
You may need to check the spelling
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_CITY = "Marrakech";
|
|
13
|
+
export const LOCAL_STORAGE_PATH = "./storage";
|