hoffmation-base 0.1.33 → 0.1.35
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/lib/index.js +4 -1
- package/lib/models/actuatorSettings.d.ts +2 -1
- package/lib/models/actuatorSettings.js +3 -1
- package/lib/models/deviceSettings.d.ts +2 -0
- package/lib/models/deviceSettings.js +6 -0
- package/lib/models/ledSettings.d.ts +2 -1
- package/lib/models/ledSettings.js +3 -1
- package/lib/models/logSource.d.ts +4 -0
- package/lib/models/logSource.js +8 -0
- package/lib/models/rooms/RoomBase.d.ts +3 -0
- package/lib/models/rooms/RoomBase.js +6 -1
- package/lib/server/config/iConfig.d.ts +7 -0
- package/lib/server/devices/device-cluster-type.d.ts +18 -15
- package/lib/server/devices/device-cluster-type.js +18 -15
- package/lib/server/devices/device-cluster.d.ts +2 -0
- package/lib/server/devices/device-cluster.js +87 -0
- package/lib/server/devices/deviceType.d.ts +1 -0
- package/lib/server/devices/deviceType.js +1 -0
- package/lib/server/devices/devices.js +4 -0
- package/lib/server/devices/groups/heatGroup.d.ts +5 -1
- package/lib/server/devices/groups/heatGroup.js +12 -3
- package/lib/server/devices/hmIPDevices/hmIpHeizgruppe.d.ts +6 -4
- package/lib/server/devices/hmIPDevices/hmIpHeizgruppe.js +4 -7
- package/lib/server/devices/hmIPDevices/hmIpHeizung.d.ts +1 -1
- package/lib/server/devices/hmIPDevices/hmIpHeizung.js +1 -1
- package/lib/server/devices/iHeater.d.ts +11 -0
- package/lib/server/devices/iHeater.js +2 -0
- package/lib/server/devices/iHumiditySensor.d.ts +5 -0
- package/lib/server/devices/iHumiditySensor.js +2 -0
- package/lib/server/devices/iTemperaturSensor.d.ts +5 -0
- package/lib/server/devices/iTemperaturSensor.js +2 -0
- package/lib/server/devices/index.d.ts +3 -0
- package/lib/server/devices/index.js +3 -0
- package/lib/server/devices/zigbee/index.d.ts +1 -0
- package/lib/server/devices/zigbee/index.js +1 -0
- package/lib/server/devices/zigbee/zigbeeBlitzShp.js +2 -2
- package/lib/server/devices/zigbee/zigbeeMagnetContact.d.ts +2 -0
- package/lib/server/devices/zigbee/zigbeeMagnetContact.js +11 -3
- package/lib/server/devices/zigbee/zigbeeSonoffTemp.d.ts +17 -0
- package/lib/server/devices/zigbee/zigbeeSonoffTemp.js +46 -0
- package/lib/server/services/Sonos/polly-service.d.ts +1 -1
- package/lib/server/services/Sonos/polly-service.js +3 -2
- package/lib/server/services/https-service.d.ts +6 -0
- package/lib/server/services/https-service.js +12 -0
- package/lib/server/services/log-service/log-filter-data.d.ts +2 -0
- package/lib/server/services/log-service/log-service.js +6 -0
- package/lib/server/services/news-service.d.ts +35 -5
- package/lib/server/services/news-service.js +130 -31
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -12
|
@@ -12,6 +12,8 @@ class ZigbeeMagnetContact extends zigbeeDevice_1.ZigbeeDevice {
|
|
|
12
12
|
constructor(pInfo, deviceType) {
|
|
13
13
|
super(pInfo, deviceType);
|
|
14
14
|
this.position = MagnetPosition_1.MagnetPosition.closed;
|
|
15
|
+
this.telegramOnOpen = false;
|
|
16
|
+
this.speakOnOpen = false;
|
|
15
17
|
this._closedCallback = [];
|
|
16
18
|
this._openCallback = [];
|
|
17
19
|
this.minutesOpen = 0;
|
|
@@ -46,7 +48,9 @@ class ZigbeeMagnetContact extends zigbeeDevice_1.ZigbeeDevice {
|
|
|
46
48
|
}
|
|
47
49
|
// const message: string = `Die Tür wurde nach ${this.minutesOpen} Minuten geschlossen!`;
|
|
48
50
|
this.log(logLevel_1.LogLevel.Info, message);
|
|
49
|
-
|
|
51
|
+
if (this.telegramOnOpen) {
|
|
52
|
+
telegram_service_1.TelegramService.inform(message);
|
|
53
|
+
}
|
|
50
54
|
this.minutesOpen = 0;
|
|
51
55
|
this._iOpenTimeout = undefined;
|
|
52
56
|
}
|
|
@@ -54,8 +58,12 @@ class ZigbeeMagnetContact extends zigbeeDevice_1.ZigbeeDevice {
|
|
|
54
58
|
}
|
|
55
59
|
else if (this._iOpenTimeout === undefined) {
|
|
56
60
|
const message = res_1.Res.wasOpened(this.info.customName);
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
if (this.telegramOnOpen) {
|
|
62
|
+
telegram_service_1.TelegramService.inform(message);
|
|
63
|
+
}
|
|
64
|
+
if (this.speakOnOpen) {
|
|
65
|
+
sonos_service_1.SonosService.speakOnAll(message, 40);
|
|
66
|
+
}
|
|
59
67
|
this._iOpenTimeout = utils_1.Utils.guardedInterval(() => {
|
|
60
68
|
this.minutesOpen++;
|
|
61
69
|
const message = `Contact is ${MagnetPosition_1.MagnetPosition[this.position]} since ${this.minutesOpen} minutes`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="iobroker" />
|
|
2
|
+
import { ZigbeeDevice } from './zigbeeDevice';
|
|
3
|
+
import { iTemperaturSensor } from '../iTemperaturSensor';
|
|
4
|
+
import { iHumiditySensor } from '../iHumiditySensor';
|
|
5
|
+
import { DeviceInfo } from '../DeviceInfo';
|
|
6
|
+
export declare class ZigbeeSonoffTemp extends ZigbeeDevice implements iTemperaturSensor, iHumiditySensor {
|
|
7
|
+
private _humidity;
|
|
8
|
+
private _humidityCallbacks;
|
|
9
|
+
private _temperatur;
|
|
10
|
+
constructor(pInfo: DeviceInfo);
|
|
11
|
+
update(idSplit: string[], state: ioBroker.State, initial?: boolean): void;
|
|
12
|
+
get humidity(): number;
|
|
13
|
+
private set humidity(value);
|
|
14
|
+
get iTemperatur(): number;
|
|
15
|
+
get sTemperatur(): string;
|
|
16
|
+
addHumidityCallback(pCallback: (pValue: number) => void): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZigbeeSonoffTemp = void 0;
|
|
4
|
+
const zigbeeDevice_1 = require("./zigbeeDevice");
|
|
5
|
+
const deviceType_1 = require("../deviceType");
|
|
6
|
+
class ZigbeeSonoffTemp extends zigbeeDevice_1.ZigbeeDevice {
|
|
7
|
+
constructor(pInfo) {
|
|
8
|
+
super(pInfo, deviceType_1.DeviceType.ZigbeeSonoffTemp);
|
|
9
|
+
this._humidity = -99;
|
|
10
|
+
this._humidityCallbacks = [];
|
|
11
|
+
this._temperatur = -99;
|
|
12
|
+
}
|
|
13
|
+
update(idSplit, state, initial = false) {
|
|
14
|
+
super.update(idSplit, state, initial, true);
|
|
15
|
+
switch (idSplit[3]) {
|
|
16
|
+
case 'humidity':
|
|
17
|
+
this.humidity = state.val;
|
|
18
|
+
break;
|
|
19
|
+
case 'temperatur':
|
|
20
|
+
this._temperatur = state.val;
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get humidity() {
|
|
25
|
+
return this._humidity;
|
|
26
|
+
}
|
|
27
|
+
set humidity(val) {
|
|
28
|
+
this._humidity = val;
|
|
29
|
+
for (const cb of this._humidityCallbacks) {
|
|
30
|
+
cb(val);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
get iTemperatur() {
|
|
34
|
+
return this._temperatur;
|
|
35
|
+
}
|
|
36
|
+
get sTemperatur() {
|
|
37
|
+
return `${this._temperatur}°C`;
|
|
38
|
+
}
|
|
39
|
+
addHumidityCallback(pCallback) {
|
|
40
|
+
this._humidityCallbacks.push(pCallback);
|
|
41
|
+
if (this._humidity > 0) {
|
|
42
|
+
pCallback(this._humidity);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.ZigbeeSonoffTemp = ZigbeeSonoffTemp;
|
|
@@ -6,7 +6,7 @@ export declare class PollyService {
|
|
|
6
6
|
static polly: AWS.Polly;
|
|
7
7
|
static voice: string;
|
|
8
8
|
static initialize(config: iPollySettings): void;
|
|
9
|
-
static getDuration(
|
|
9
|
+
static getDuration(filename: string): number;
|
|
10
10
|
static preloadTTS(text: string): void;
|
|
11
11
|
static tts(text: string, cb: (fileLink: string, duration: number) => void): void;
|
|
12
12
|
}
|
|
@@ -31,6 +31,7 @@ const get_mp3_duration_1 = __importDefault(require("get-mp3-duration"));
|
|
|
31
31
|
const crypto_1 = __importDefault(require("crypto"));
|
|
32
32
|
const log_service_1 = require("../log-service/log-service");
|
|
33
33
|
const logLevel_1 = require("../../../models/logLevel");
|
|
34
|
+
const path_1 = __importDefault(require("path"));
|
|
34
35
|
class PollyService {
|
|
35
36
|
static initialize(config) {
|
|
36
37
|
this.active = true;
|
|
@@ -45,8 +46,8 @@ class PollyService {
|
|
|
45
46
|
});
|
|
46
47
|
this.voice = config.voiceID;
|
|
47
48
|
}
|
|
48
|
-
static getDuration(
|
|
49
|
-
const fPath = this._mp3Path
|
|
49
|
+
static getDuration(filename) {
|
|
50
|
+
const fPath = path_1.default.join(this._mp3Path, filename);
|
|
50
51
|
try {
|
|
51
52
|
if (fs.existsSync(fPath)) {
|
|
52
53
|
const duration = (0, get_mp3_duration_1.default)(fs.readFileSync(fPath));
|
|
@@ -2,5 +2,11 @@ import { HTTPSOptions } from './HTTPSOptions';
|
|
|
2
2
|
export declare class HTTPSService {
|
|
3
3
|
private static defaultCallback;
|
|
4
4
|
static request(options: HTTPSOptions, postData?: string, retryOnError?: number, responseCallback?: (data: string, statuscode: number) => void): void;
|
|
5
|
+
/**
|
|
6
|
+
* Downloads a file from a given url to the given location.
|
|
7
|
+
* If the location doesn't exist, it will be created quietly.
|
|
8
|
+
* @param url URL to download file from
|
|
9
|
+
* @param filePath Path to save file to
|
|
10
|
+
*/
|
|
5
11
|
static downloadFile(url: string, filePath: string): Promise<boolean>;
|
|
6
12
|
}
|
|
@@ -28,6 +28,7 @@ const https_1 = __importDefault(require("https"));
|
|
|
28
28
|
const log_service_1 = require("./log-service/log-service");
|
|
29
29
|
const utils_1 = require("./utils/utils");
|
|
30
30
|
const logLevel_1 = require("../../models/logLevel");
|
|
31
|
+
const path_1 = __importDefault(require("path"));
|
|
31
32
|
class HTTPSService {
|
|
32
33
|
static defaultCallback(data, statuscode) {
|
|
33
34
|
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.DeepTrace, `Response statusCode:"${statuscode}"\nData:"${data}"`);
|
|
@@ -59,8 +60,19 @@ class HTTPSService {
|
|
|
59
60
|
}
|
|
60
61
|
req.end();
|
|
61
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Downloads a file from a given url to the given location.
|
|
65
|
+
* If the location doesn't exist, it will be created quietly.
|
|
66
|
+
* @param url URL to download file from
|
|
67
|
+
* @param filePath Path to save file to
|
|
68
|
+
*/
|
|
62
69
|
static async downloadFile(url, filePath) {
|
|
63
70
|
return new Promise((resolve, reject) => {
|
|
71
|
+
// if directory structure doesn't exist yet, create it
|
|
72
|
+
const fileDir = path_1.default.dirname(filePath);
|
|
73
|
+
if (!fs.existsSync(fileDir)) {
|
|
74
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
75
|
+
}
|
|
64
76
|
const file = fs.createWriteStream(filePath);
|
|
65
77
|
let fileInfo = null;
|
|
66
78
|
const request = https_1.default.get(url, (response) => {
|
|
@@ -6,6 +6,7 @@ const logLevel_1 = require("../../../models/logLevel");
|
|
|
6
6
|
const deviceType_1 = require("../../devices/deviceType");
|
|
7
7
|
const ringstorage_1 = require("../utils/ringstorage");
|
|
8
8
|
const log_object_1 = require("./log-object");
|
|
9
|
+
const logSource_1 = require("../../../models/logSource");
|
|
9
10
|
class ServerLogService {
|
|
10
11
|
static getLog(amount = 5000) {
|
|
11
12
|
return this.storage.readAmount(amount);
|
|
@@ -14,6 +15,7 @@ class ServerLogService {
|
|
|
14
15
|
this.settings = logSettings;
|
|
15
16
|
}
|
|
16
17
|
static writeLog(pLevel, pMessage, additionalLogInfo) {
|
|
18
|
+
var _a;
|
|
17
19
|
const now = Date.now();
|
|
18
20
|
if (pLevel > this.storageLevel && pLevel > ServerLogService.settings.logLevel) {
|
|
19
21
|
return;
|
|
@@ -29,6 +31,10 @@ class ServerLogService {
|
|
|
29
31
|
else if (additionalLogInfo === null || additionalLogInfo === void 0 ? void 0 : additionalLogInfo.room) {
|
|
30
32
|
message += `"${additionalLogInfo.room}": `;
|
|
31
33
|
}
|
|
34
|
+
const logSource = (_a = additionalLogInfo === null || additionalLogInfo === void 0 ? void 0 : additionalLogInfo.source) !== null && _a !== void 0 ? _a : 0;
|
|
35
|
+
if (logSource > 0) {
|
|
36
|
+
message += `${logSource_1.LogSource[logSource]}: `;
|
|
37
|
+
}
|
|
32
38
|
message += pMessage;
|
|
33
39
|
console.log(message);
|
|
34
40
|
if (pLevel <= ServerLogService.telegramLevel) {
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import { OwnSonosDevice } from './Sonos/sonos-service';
|
|
2
|
+
import { iNewsSettings } from '../config/iConfig';
|
|
2
3
|
export declare class NewsService {
|
|
3
|
-
static
|
|
4
|
-
static
|
|
5
|
-
private static
|
|
6
|
-
static
|
|
4
|
+
static lastNewsAudioFile: string;
|
|
5
|
+
private static interval;
|
|
6
|
+
private static requestInterval;
|
|
7
|
+
private static keepMaxAge;
|
|
8
|
+
private static rssUrl;
|
|
9
|
+
private static lastFetchedPubDate;
|
|
10
|
+
static initialize(config?: Partial<iNewsSettings>): void;
|
|
11
|
+
/**
|
|
12
|
+
* Stops the regular check for new news feed items.
|
|
13
|
+
* @deprecated Use stopInterval instead
|
|
14
|
+
*/
|
|
7
15
|
static stopHourlyInterval(): void;
|
|
8
|
-
static
|
|
16
|
+
static startInterval(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Stops the regular check for new news feed items.
|
|
19
|
+
*/
|
|
20
|
+
static stopInterval(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Checks if there are newer news than the one currently available on disk and downloads the file for playing.
|
|
23
|
+
*/
|
|
24
|
+
static getLatestNews(): void;
|
|
25
|
+
private static downloadLatestFileFromFeed;
|
|
26
|
+
/**
|
|
27
|
+
* Deletes all files in the given directory that are older than the given age.
|
|
28
|
+
* @param rootDir Directory to search in
|
|
29
|
+
* @param keepMaxAge Maximum age in minutes until a file gets deleted
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
private static cleanOldFiles;
|
|
33
|
+
/**
|
|
34
|
+
* Plays the latest news on a sonos device
|
|
35
|
+
* @param ownSonosDevice Sonos device to play from
|
|
36
|
+
* @param volume volume to play at
|
|
37
|
+
* @param retries Number of times playing should be tried if there is currently no audio file available
|
|
38
|
+
*/
|
|
9
39
|
static playLastNews(ownSonosDevice: OwnSonosDevice, volume?: number, retries?: number): void;
|
|
10
40
|
}
|
|
@@ -18,6 +18,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
18
|
__setModuleDefault(result, mod);
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
+
};
|
|
21
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
25
|
exports.NewsService = void 0;
|
|
23
26
|
const fs = __importStar(require("fs"));
|
|
@@ -27,68 +30,164 @@ const log_service_1 = require("./log-service/log-service");
|
|
|
27
30
|
const sonos_service_1 = require("./Sonos/sonos-service");
|
|
28
31
|
const polly_service_1 = require("./Sonos/polly-service");
|
|
29
32
|
const settings_service_1 = require("./settings-service");
|
|
30
|
-
const HTTPSOptions_1 = require("./HTTPSOptions");
|
|
31
33
|
const logLevel_1 = require("../../models/logLevel");
|
|
34
|
+
const path_1 = __importDefault(require("path"));
|
|
35
|
+
const rss_parser_1 = __importDefault(require("rss-parser"));
|
|
36
|
+
const logSource_1 = require("../../models/logSource");
|
|
32
37
|
class NewsService {
|
|
33
|
-
static initialize() {
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
static initialize(config) {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
if (config === undefined) {
|
|
41
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Warn, `Service disabled.`, { source: logSource_1.LogSource.News });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
NewsService.keepMaxAge = (_a = config.keepMaxAge) !== null && _a !== void 0 ? _a : 120;
|
|
45
|
+
NewsService.requestInterval = (_b = config.requestInterval) !== null && _b !== void 0 ? _b : 30;
|
|
46
|
+
NewsService.rssUrl = config.rssUrl;
|
|
47
|
+
NewsService.startInterval();
|
|
36
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Stops the regular check for new news feed items.
|
|
51
|
+
* @deprecated Use stopInterval instead
|
|
52
|
+
*/
|
|
37
53
|
static stopHourlyInterval() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
NewsService.stopInterval();
|
|
55
|
+
}
|
|
56
|
+
static startInterval() {
|
|
57
|
+
var _a;
|
|
58
|
+
if (NewsService.interval !== undefined) {
|
|
59
|
+
clearInterval(NewsService.interval);
|
|
60
|
+
}
|
|
61
|
+
NewsService.interval = utils_1.Utils.guardedInterval(() => {
|
|
62
|
+
NewsService.getLatestNews();
|
|
63
|
+
}, ((_a = NewsService.requestInterval) !== null && _a !== void 0 ? _a : 30) * 60 * 1000, undefined, true);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Stops the regular check for new news feed items.
|
|
67
|
+
*/
|
|
68
|
+
static stopInterval() {
|
|
69
|
+
if (NewsService.interval === undefined) {
|
|
70
|
+
return;
|
|
41
71
|
}
|
|
72
|
+
clearInterval(NewsService.interval);
|
|
73
|
+
NewsService.interval = undefined;
|
|
42
74
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Checks if there are newer news than the one currently available on disk and downloads the file for playing.
|
|
77
|
+
*/
|
|
78
|
+
static getLatestNews() {
|
|
79
|
+
if (settings_service_1.SettingsService.settings.mp3Server === undefined) {
|
|
80
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Warn, `Not checking for newest news file, no download directory defined.`, {
|
|
81
|
+
source: logSource_1.LogSource.News,
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
NewsService.cleanOldFiles(settings_service_1.SettingsService.settings.mp3Server.path, NewsService.keepMaxAge);
|
|
86
|
+
if (NewsService.rssUrl === undefined) {
|
|
87
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Warn, `No rss feed set, not searching for new news.`, {
|
|
88
|
+
source: logSource_1.LogSource.News,
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
NewsService.downloadLatestFileFromFeed(NewsService.rssUrl, settings_service_1.SettingsService.settings.mp3Server.path);
|
|
93
|
+
}
|
|
94
|
+
static downloadLatestFileFromFeed(rssUrl, targetDir) {
|
|
95
|
+
const parser = new rss_parser_1.default();
|
|
96
|
+
parser.parseURL(rssUrl).then((feed) => {
|
|
46
97
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `NewsService: Die aktuelle News ist "${target}"`);
|
|
54
|
-
if (fs.existsSync(filePath)) {
|
|
55
|
-
NewsService.lastNewsName = fileName.split('.mp3')[0];
|
|
56
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `Wir haben bereits die neuste WDR Nachrichten heruntergeladen.`);
|
|
98
|
+
const currentFeedItem = feed.items[0];
|
|
99
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `Most recent news on ${feed.title} is "${currentFeedItem.title}"`);
|
|
100
|
+
if (currentFeedItem.enclosure === undefined) {
|
|
101
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Warn, `Couldn't find audio in last item of the rss feed.`, {
|
|
102
|
+
source: logSource_1.LogSource.News,
|
|
103
|
+
});
|
|
57
104
|
return;
|
|
58
105
|
}
|
|
59
|
-
|
|
106
|
+
const filePath = path_1.default.join(targetDir, path_1.default.basename(currentFeedItem.enclosure.url));
|
|
107
|
+
// check for both path and pubdate in case the file name is always the same one
|
|
108
|
+
if (fs.existsSync(filePath) && NewsService.lastFetchedPubDate == currentFeedItem.pubDate) {
|
|
109
|
+
NewsService.lastNewsAudioFile = path_1.default.basename(filePath);
|
|
110
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `Newest file already downloaded.`, { source: logSource_1.LogSource.News });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
https_service_1.HTTPSService.downloadFile(currentFeedItem.enclosure.url, filePath)
|
|
60
114
|
.then((success) => {
|
|
61
115
|
if (!success) {
|
|
62
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `
|
|
116
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `Error while downloading audio file.`, {
|
|
117
|
+
source: logSource_1.LogSource.News,
|
|
118
|
+
});
|
|
63
119
|
return;
|
|
64
120
|
}
|
|
65
|
-
NewsService.
|
|
121
|
+
NewsService.lastNewsAudioFile = path_1.default.basename(filePath);
|
|
66
122
|
})
|
|
67
123
|
.catch((reason) => {
|
|
68
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Error, `
|
|
124
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Error, `Error while downloading feed audio: ${reason.message}`, {
|
|
125
|
+
source: logSource_1.LogSource.News,
|
|
126
|
+
});
|
|
69
127
|
});
|
|
70
128
|
}
|
|
71
129
|
catch (e) {
|
|
72
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `
|
|
73
|
-
return;
|
|
130
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Debug, `Error while parsing feed: ${e}`, { source: logSource_1.LogSource.News });
|
|
74
131
|
}
|
|
75
132
|
});
|
|
76
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Deletes all files in the given directory that are older than the given age.
|
|
136
|
+
* @param rootDir Directory to search in
|
|
137
|
+
* @param keepMaxAge Maximum age in minutes until a file gets deleted
|
|
138
|
+
* @private
|
|
139
|
+
*/
|
|
140
|
+
static cleanOldFiles(rootDir, keepMaxAge) {
|
|
141
|
+
let deleteCount = 0;
|
|
142
|
+
fs.readdir(rootDir, (err, files) => {
|
|
143
|
+
if (err)
|
|
144
|
+
return;
|
|
145
|
+
files.forEach((file) => {
|
|
146
|
+
fs.stat(path_1.default.join(rootDir, file), (err, stat) => {
|
|
147
|
+
if (err)
|
|
148
|
+
return;
|
|
149
|
+
const now = new Date().getTime();
|
|
150
|
+
const maxSurvivingTime = new Date(stat.ctime).getTime() + keepMaxAge * 60 * 1000;
|
|
151
|
+
if (now <= maxSurvivingTime) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
fs.unlink(path_1.default.join(rootDir, file), (err) => {
|
|
155
|
+
if (err) {
|
|
156
|
+
return console.error(err);
|
|
157
|
+
}
|
|
158
|
+
deleteCount++;
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
if (deleteCount > 0) {
|
|
164
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Info, `Deleted ${deleteCount} old file/s.`, { source: logSource_1.LogSource.News });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Plays the latest news on a sonos device
|
|
169
|
+
* @param ownSonosDevice Sonos device to play from
|
|
170
|
+
* @param volume volume to play at
|
|
171
|
+
* @param retries Number of times playing should be tried if there is currently no audio file available
|
|
172
|
+
*/
|
|
77
173
|
static playLastNews(ownSonosDevice, volume = 30, retries = 5) {
|
|
78
|
-
if (!NewsService.
|
|
174
|
+
if (!NewsService.lastNewsAudioFile) {
|
|
79
175
|
if (retries > 0) {
|
|
80
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Warn, `
|
|
176
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Warn, `Service not ready yet --> waiting, remaining tries: ${retries - 1}`, {
|
|
177
|
+
source: logSource_1.LogSource.News,
|
|
178
|
+
});
|
|
81
179
|
utils_1.Utils.guardedTimeout(() => {
|
|
82
180
|
NewsService.playLastNews(ownSonosDevice, volume, retries - 1);
|
|
83
181
|
}, 1000);
|
|
84
182
|
}
|
|
85
183
|
else {
|
|
86
|
-
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Error, `
|
|
184
|
+
log_service_1.ServerLogService.writeLog(logLevel_1.LogLevel.Error, `Service not ready despite waiting --> Abort.`, {
|
|
185
|
+
source: logSource_1.LogSource.News,
|
|
186
|
+
});
|
|
87
187
|
}
|
|
88
188
|
return;
|
|
89
189
|
}
|
|
90
|
-
sonos_service_1.SonosService.playOnDevice(ownSonosDevice, NewsService.
|
|
190
|
+
sonos_service_1.SonosService.playOnDevice(ownSonosDevice, path_1.default.basename(NewsService.lastNewsAudioFile, path_1.default.extname(NewsService.lastNewsAudioFile)), polly_service_1.PollyService.getDuration(NewsService.lastNewsAudioFile), volume);
|
|
91
191
|
}
|
|
92
192
|
}
|
|
93
193
|
exports.NewsService = NewsService;
|
|
94
|
-
NewsService.oneDay = 1000 * 60 * 60 * 24;
|