-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.ts
211 lines (181 loc) · 5.19 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import axios from 'axios';
import * as Debug from 'debug';
import { discovery } from './discovery';
import Device from './Device';
import ServerInfo from './ServerInfo';
const debug = Debug('tablo-api:index');
const Axios = axios.create();
Axios.defaults.timeout = 5000;
import { version } from '../package.json';
Axios.defaults.headers.common = { 'User-Agent': `tablo-api-js/${version}` };
debug('Axios headers %O', Axios.defaults.headers);
export default class Tablo {
private devices: Device[];
private airingsCache: [];
private device: Device;
/**
* Utilizes HTTP discovery with UDP broadcast fallback to find local Tablo devices
*/
async discover() {
let discoverData: Device[] = [];
discoverData = await discovery.http();
debug('discover.http:');
debug(discoverData);
if (Object.keys(discoverData).length === 0) {
discoverData = await discovery.broadcast();
debug('discover.broadcast:');
debug(discoverData);
}
debug('Devices Found: ', Object.keys(discoverData).length);
if (Object.keys(discoverData).length === 0) {
return [];
}
// TODO: a nicety when testing, should probably remove
this.devices = discoverData;
this.device = this.devices[0];
return discoverData;
}
/**
* Pre-flight check
* @throws Error when no device has been selected
*/
private isReady() {
if (typeof this.device === 'undefined' || !this.device || !this.device.private_ip) {
const msg = 'TabloAPI - No device selected.';
throw new Error(msg);
}
}
/**
* Returns server info reported by the Tablo
*/
async getServerInfo() {
this.isReady();
try {
const info: ServerInfo = await this.get('/server/info');
return info;
} catch (err) {
throw err;
}
}
/**
* Returns a count of the Recordings on the Tablo
* @param force whether or not to force reloading from the device or use cached airings
*/
async getRecordingsCount(force = false) {
this.isReady();
try {
if (!this.airingsCache || force) {
this.airingsCache = await this.get('/recordings/airings');
}
if (!this.airingsCache) {
return 0;
}
return this.airingsCache.length;
} catch (err) {
throw err;
}
}
/**
* Retrieves all Recordings from the Tablo
* @param force whether or not to force reloading from the device or use cached airings
* @param progressCallback function to receive a count of records processed
*/
async getRecordings(force = false, progressCallback: (num: number) => void) {
this.isReady();
try {
if (!this.airingsCache || force) {
this.airingsCache = await this.get('/recordings/airings');
}
if (!this.airingsCache) {
return null;
}
return this.batch(this.airingsCache, progressCallback);
} catch (error) {
throw error;
}
}
/**
* Deletes a
* @param path
*/
async delete(path: string) {
this.isReady();
const url = this.getUrl(path);
return Axios.delete(url);
}
/**
* Try to receive data from a specified path
* @param path
*/
async get<T>(path: string): Promise<T> {
this.isReady();
return new Promise(async (resolve, reject) => {
try {
const url = this.getUrl(path);
const response: { data: T } = await Axios.get(url);
resolve(response.data);
} catch (error) {
reject(error);
}
});
}
private getUrl(path: string) {
const newPath = path.replace(/^\/+/, '');
return `http://${this.device.private_ip}:8885/${newPath}`;
}
public async batch<T>(data: string[], progressCallback: (arg0: number) => void): Promise<T[]> {
this.isReady();
return new Promise(async (resolve, reject) => {
let chunk = [];
let idx = 0;
const size = 50;
let recs: T[] = [];
while (idx < data.length) {
chunk = data.slice(idx, size + idx);
idx += size;
let returned: T[];
try {
returned = await this.post('batch', chunk);
} catch (err) {
return reject(err);
}
const values = Object.keys(returned).map((el) => {
return returned[el];
});
recs = recs.concat(values);
if (typeof progressCallback === 'function') {
progressCallback(recs.length);
}
}
resolve(recs);
});
}
async post<T>(path = 'batch', strArray?: string[]): Promise<T[]> {
this.isReady();
const toPost = strArray ? strArray : null;
return new Promise(async (resolve, reject) => {
try {
const url = this.getUrl(path);
const returned: { data: T[] } = await Axios.post(url, toPost);
const { data } = returned;
resolve(data);
} catch (error) {
reject(error);
}
});
}
async patch<T>(path: string, patchData: string[] | object): Promise<T[]> {
this.isReady();
return new Promise(async (resolve, reject) => {
try {
const url = this.getUrl(path);
const returned: { data: T[] } = await Axios.patch(url, patchData);
const { data } = returned;
resolve(data);
} catch (error) {
reject(error);
}
});
}
}
export { Tablo };