-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwhatson.ts
127 lines (104 loc) · 3.96 KB
/
whatson.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
const UPnPClient = require('node-upnp');
require('log-timestamp');
import axios from 'axios';
import {DOMParser} from 'xmldom';
import {SingleBar} from 'cli-progress';
import {SkyFinder} from './SkyFinder';
import {SKY_BROWSE_URN, SKY_PLAY_URN, decodeXml} from './Common';
const TV_LISTINGS = 'http://epgservices.sky.com/tvlistings-proxy/TVListingsProxy/init.json';
type ProgressHandler = (progress: number, total: number) => void;
type ItemListing = {
[k: string]: {
title: string,
description: string
}
};
type TvMap = {[channelID: number]: string};
/**
* Get all recorded items from a SkyBox.
* @param location URN of the SkyBrowse:2 UPnP service
* @param progressHandler
*/
async function getRecordedItems(location: string, progressHandler: ProgressHandler): Promise<ItemListing> {
console.log(`Getting recording data from ${location}`);
const client = new UPnPClient({
url: location,
userAgent: "SKY_skyplus"
});
const result: ItemListing = {};
do {
const response = await client.call('urn:nds-com:serviceId:SkyBrowse', 'Browse', {
ObjectID: 3,
BrowseFlag: 'BrowseDirectChildren',
Filter: '*',
StartingIndex: Object.keys(result).length,
RequestedCount: 25, // The apparent max
SortCriteria: null
});
const xmlContent = decodeXml(response.Result);
const contentDoc = new DOMParser().parseFromString(xmlContent);
Array.from(contentDoc.documentElement.getElementsByTagName('item')).map((element: Element) => {
const res = element.getElementsByTagName('res').item(0)?.textContent;
const title = element.getElementsByTagName('dc:title').item(0)?.textContent;
const description = element.getElementsByTagName('dc:description').item(0)?.textContent;
if (res && title && description) {
result[res] = {title, description};
}
});
progressHandler(Object.keys(result).length, response.TotalMatches);
if (Object.keys(result).length >= response.TotalMatches) {
return result;
}
} while (true);
}
/**
* Get a map of channelIDs to their Station Name.
*/
async function getTvListings(): Promise<TvMap> {
// Get the Channel listings
const response = await axios.get(TV_LISTINGS);
return Object.fromEntries(response.data.channels.map((rec:any) => {
const value = rec.title;
const id = rec.channelid;
return [id, value];
})) as TvMap;
}
// - Main -----
const skyFinder = new SkyFinder();
skyFinder.on('found', async (skyURNs) => {
const browseURN = skyURNs[SKY_BROWSE_URN];
let bar: SingleBar|null = null;
const listingP = getRecordedItems(browseURN, (done, totalTodo) => {
if (!bar) {
bar = new SingleBar({});
bar.start(totalTodo, done)
};
bar.update(done);
if (done == totalTodo) {
bar.stop();
}
});
const [listing, tvMap] = await Promise.all([listingP, getTvListings()]);
const playClient = new UPnPClient({
url: skyURNs[SKY_PLAY_URN],
userAgent: "SKY_skyplus"
});
playClient.on('AVTransportURI', (uriStr: any) => {
const url = new URL(uriStr)
switch(url.protocol) {
case 'xsi:':
const channelId = parseInt(url.host, 16);
console.log("Live TV, channel:", tvMap[channelId]);
break;
case 'file:':
console.log("Recording: ", listing[uriStr]);
break;
default:
console.log(url.toString());
}
}, {force: true}); // force required, as property description from SkyBox is incorrectly set to false
playClient.on('TransportState', (state: string) => {
console.log('TransportState: ', state);
}, {force: true}); // force required, as property description from SkyBox is incorrectly set to false
});
skyFinder.find();