hfbcast 1.0.0 → 1.0.2
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/.vscode/tasks.json +28 -0
- package/README.md +30 -30
- package/assets/database.sqlite.gz +0 -0
- package/dist/demo.js +28 -60
- package/dist/index.html +12 -12
- package/dist/rfdfhfbroadcast.js +27 -59
- package/package.json +1 -1
- package/release +1 -0
- package/scripts/build.js +19 -0
- package/scripts/cicd/jobs.sh +14 -0
- package/scripts/local/publish.bat +11 -0
- package/sources/shortwave_AOKI.html +10191 -10065
- package/sources/shortwave_EIBI.html +16279 -19087
- package/sources/shortwave_HFCC.html +5594 -5171
- package/sqlite/build.ts +127 -127
- package/sqlite/data-source.ts +17 -17
- package/sqlite/entity/Broadcast.ts +38 -38
- package/sqlite/entity/Site.ts +26 -26
- package/sqlite/package-lock.json +2303 -0
- package/sqlite/package.json +17 -17
- package/src/demo.html +12 -12
- package/src/demo.js +6 -6
- package/src/index.d.ts +33 -33
- package/src/index.js +84 -83
- package/tsconfig.json +14 -14
- package/webpack.config.js +27 -27
- package/dist/database.sqlite.gz +0 -0
package/sqlite/build.ts
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as url from 'url';
|
|
3
|
-
import { AppDataSource } from "./data-source";
|
|
4
|
-
import {Site} from "./entity/Site";
|
|
5
|
-
import {Broadcast} from "./entity/Broadcast";
|
|
6
|
-
import {JSDOM} from "jsdom";
|
|
7
|
-
const jquery = require("jquery");
|
|
8
|
-
|
|
9
|
-
function parseBroadcasts(sourceName) {
|
|
10
|
-
|
|
11
|
-
return new Promise(resolve => {
|
|
12
|
-
|
|
13
|
-
const broadcasts = [];
|
|
14
|
-
const sites = [];
|
|
15
|
-
|
|
16
|
-
fs.readFile(`../sources/shortwave_${sourceName}.html`, 'utf8', async function(err, testHTML) {
|
|
17
|
-
|
|
18
|
-
global.document = new JSDOM( testHTML );
|
|
19
|
-
const $ = jquery(global.document.window);
|
|
20
|
-
const rows = $('table.results tr');
|
|
21
|
-
|
|
22
|
-
rows.each(async (i, row) => {
|
|
23
|
-
|
|
24
|
-
// if (i===0 || i>100) return false;
|
|
25
|
-
if (i===0) return false;
|
|
26
|
-
if (i%1000 === 0) console.log(sourceName, i);
|
|
27
|
-
|
|
28
|
-
const cells = $(row).find('td');
|
|
29
|
-
|
|
30
|
-
const fq = Number.parseFloat($(cells[0]).html());
|
|
31
|
-
const startStopTime = $(cells[1]).html().split('-');
|
|
32
|
-
const station = $(cells[2]).html();
|
|
33
|
-
const country = $(cells[3]).html();
|
|
34
|
-
const language = $(cells[4]).html();
|
|
35
|
-
const days = $(cells[5]).html();
|
|
36
|
-
const link = $(cells[6]).html();
|
|
37
|
-
let lon=0, lat=0, siteName='unknown';
|
|
38
|
-
try {
|
|
39
|
-
const a = $(link);
|
|
40
|
-
// console.log(a.length);
|
|
41
|
-
siteName = a.length === 1 ? a.html() : link;
|
|
42
|
-
const coordString = (new url.URL(a.attr('href'))).searchParams.get('center').split(',');
|
|
43
|
-
lat = Number.parseFloat(coordString[0]);
|
|
44
|
-
lon = Number.parseFloat(coordString[1]);
|
|
45
|
-
}
|
|
46
|
-
catch (e) {
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const startHour = Number.parseInt(startStopTime[0].substring(0,2));
|
|
50
|
-
const startMin = Number.parseInt(startStopTime[0].substring(2,4));
|
|
51
|
-
const stopHour = Number.parseInt(startStopTime[1].substring(0,2));
|
|
52
|
-
const stopMin = Number.parseInt(startStopTime[1].substring(2,4));
|
|
53
|
-
|
|
54
|
-
let daysInteger = 0;
|
|
55
|
-
for (let i = 0; i < days.length; i++) {
|
|
56
|
-
const dayInt = parseInt(days.charAt(i));
|
|
57
|
-
if (!isNaN(dayInt)) {
|
|
58
|
-
daysInteger += Math.pow(2, dayInt-1);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// console.log(fq, lon, lat, startStopTime, startHour, stopHour, days);
|
|
63
|
-
|
|
64
|
-
const site = new Site();
|
|
65
|
-
site.name = siteName;
|
|
66
|
-
site.power = 0;
|
|
67
|
-
site.lon = lon;
|
|
68
|
-
site.lat = lat;
|
|
69
|
-
|
|
70
|
-
const broadcast = new Broadcast();
|
|
71
|
-
broadcast.frequency = fq;
|
|
72
|
-
broadcast.site = site;
|
|
73
|
-
broadcast.days = daysInteger;
|
|
74
|
-
broadcast.startTime = startMin + 60*startHour;
|
|
75
|
-
broadcast.endTime = stopMin + 60*stopHour;
|
|
76
|
-
broadcast.station = station;
|
|
77
|
-
broadcast.country = country;
|
|
78
|
-
broadcast.language = language;
|
|
79
|
-
broadcast.source = sourceName;
|
|
80
|
-
|
|
81
|
-
sites.push(site);
|
|
82
|
-
broadcasts.push(broadcast);
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
resolve(broadcasts);
|
|
86
|
-
});
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
AppDataSource.initialize().then(async () => {
|
|
91
|
-
|
|
92
|
-
console.log('PARSING HTML ...');
|
|
93
|
-
|
|
94
|
-
const broadcasts1: any = await parseBroadcasts('AOKI');
|
|
95
|
-
console.log('...', broadcasts1.length, 'BROADCASTS FOUND IN AOKI');
|
|
96
|
-
const broadcasts2: any = await parseBroadcasts('EIBI');
|
|
97
|
-
console.log('...', broadcasts2.length, 'BROADCASTS FOUND IN EIBI');
|
|
98
|
-
const broadcasts3: any = await parseBroadcasts('HFCC');
|
|
99
|
-
console.log('...', broadcasts3.length, 'BROADCASTS FOUND IN HFCC');
|
|
100
|
-
|
|
101
|
-
const broadcasts = [... broadcasts1, ... broadcasts2, ... broadcasts3]
|
|
102
|
-
|
|
103
|
-
console.log(broadcasts.length, 'BROADCASTS FOUND IN TOTAL');
|
|
104
|
-
|
|
105
|
-
console.log('POPULATING DATABASE ...');
|
|
106
|
-
|
|
107
|
-
for (let i=0; i<broadcasts.length; i++) {
|
|
108
|
-
try {
|
|
109
|
-
if (i%1000 === 0) console.log(i);
|
|
110
|
-
// await siteRepository.save(broadcasts[i].site);
|
|
111
|
-
|
|
112
|
-
const siteName = broadcasts[i].site.name;
|
|
113
|
-
const site = await AppDataSource.manager.findOne(Site, {where: {name: siteName}});
|
|
114
|
-
if (site) {
|
|
115
|
-
broadcasts[i].site = site;
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
await AppDataSource.manager.save(broadcasts[i].site);
|
|
119
|
-
}
|
|
120
|
-
await AppDataSource.manager.save(broadcasts[i]);
|
|
121
|
-
}
|
|
122
|
-
catch (e) {
|
|
123
|
-
console.log(i, 'NOT UNIQUE', broadcasts[i]);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
}).catch(error => console.log(error))
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as url from 'url';
|
|
3
|
+
import { AppDataSource } from "./data-source";
|
|
4
|
+
import {Site} from "./entity/Site";
|
|
5
|
+
import {Broadcast} from "./entity/Broadcast";
|
|
6
|
+
import {JSDOM} from "jsdom";
|
|
7
|
+
const jquery = require("jquery");
|
|
8
|
+
|
|
9
|
+
function parseBroadcasts(sourceName) {
|
|
10
|
+
|
|
11
|
+
return new Promise(resolve => {
|
|
12
|
+
|
|
13
|
+
const broadcasts = [];
|
|
14
|
+
const sites = [];
|
|
15
|
+
|
|
16
|
+
fs.readFile(`../sources/shortwave_${sourceName}.html`, 'utf8', async function(err, testHTML) {
|
|
17
|
+
|
|
18
|
+
global.document = new JSDOM( testHTML );
|
|
19
|
+
const $ = jquery(global.document.window);
|
|
20
|
+
const rows = $('table.results tr');
|
|
21
|
+
|
|
22
|
+
rows.each(async (i, row) => {
|
|
23
|
+
|
|
24
|
+
// if (i===0 || i>100) return false;
|
|
25
|
+
if (i===0) return false;
|
|
26
|
+
if (i%1000 === 0) console.log(sourceName, i);
|
|
27
|
+
|
|
28
|
+
const cells = $(row).find('td');
|
|
29
|
+
|
|
30
|
+
const fq = Number.parseFloat($(cells[0]).html());
|
|
31
|
+
const startStopTime = $(cells[1]).html().split('-');
|
|
32
|
+
const station = $(cells[2]).html();
|
|
33
|
+
const country = $(cells[3]).html();
|
|
34
|
+
const language = $(cells[4]).html();
|
|
35
|
+
const days = $(cells[5]).html();
|
|
36
|
+
const link = $(cells[6]).html();
|
|
37
|
+
let lon=0, lat=0, siteName='unknown';
|
|
38
|
+
try {
|
|
39
|
+
const a = $(link);
|
|
40
|
+
// console.log(a.length);
|
|
41
|
+
siteName = a.length === 1 ? a.html() : link;
|
|
42
|
+
const coordString = (new url.URL(a.attr('href'))).searchParams.get('center').split(',');
|
|
43
|
+
lat = Number.parseFloat(coordString[0]);
|
|
44
|
+
lon = Number.parseFloat(coordString[1]);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const startHour = Number.parseInt(startStopTime[0].substring(0,2));
|
|
50
|
+
const startMin = Number.parseInt(startStopTime[0].substring(2,4));
|
|
51
|
+
const stopHour = Number.parseInt(startStopTime[1].substring(0,2));
|
|
52
|
+
const stopMin = Number.parseInt(startStopTime[1].substring(2,4));
|
|
53
|
+
|
|
54
|
+
let daysInteger = 0;
|
|
55
|
+
for (let i = 0; i < days.length; i++) {
|
|
56
|
+
const dayInt = parseInt(days.charAt(i));
|
|
57
|
+
if (!isNaN(dayInt)) {
|
|
58
|
+
daysInteger += Math.pow(2, dayInt-1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// console.log(fq, lon, lat, startStopTime, startHour, stopHour, days);
|
|
63
|
+
|
|
64
|
+
const site = new Site();
|
|
65
|
+
site.name = siteName;
|
|
66
|
+
site.power = 0;
|
|
67
|
+
site.lon = lon;
|
|
68
|
+
site.lat = lat;
|
|
69
|
+
|
|
70
|
+
const broadcast = new Broadcast();
|
|
71
|
+
broadcast.frequency = fq;
|
|
72
|
+
broadcast.site = site;
|
|
73
|
+
broadcast.days = daysInteger;
|
|
74
|
+
broadcast.startTime = startMin + 60*startHour;
|
|
75
|
+
broadcast.endTime = stopMin + 60*stopHour;
|
|
76
|
+
broadcast.station = station;
|
|
77
|
+
broadcast.country = country;
|
|
78
|
+
broadcast.language = language;
|
|
79
|
+
broadcast.source = sourceName;
|
|
80
|
+
|
|
81
|
+
sites.push(site);
|
|
82
|
+
broadcasts.push(broadcast);
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
resolve(broadcasts);
|
|
86
|
+
});
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
AppDataSource.initialize().then(async () => {
|
|
91
|
+
|
|
92
|
+
console.log('PARSING HTML ...');
|
|
93
|
+
|
|
94
|
+
const broadcasts1: any = await parseBroadcasts('AOKI');
|
|
95
|
+
console.log('...', broadcasts1.length, 'BROADCASTS FOUND IN AOKI');
|
|
96
|
+
const broadcasts2: any = await parseBroadcasts('EIBI');
|
|
97
|
+
console.log('...', broadcasts2.length, 'BROADCASTS FOUND IN EIBI');
|
|
98
|
+
const broadcasts3: any = await parseBroadcasts('HFCC');
|
|
99
|
+
console.log('...', broadcasts3.length, 'BROADCASTS FOUND IN HFCC');
|
|
100
|
+
|
|
101
|
+
const broadcasts = [... broadcasts1, ... broadcasts2, ... broadcasts3]
|
|
102
|
+
|
|
103
|
+
console.log(broadcasts.length, 'BROADCASTS FOUND IN TOTAL');
|
|
104
|
+
|
|
105
|
+
console.log('POPULATING DATABASE ...');
|
|
106
|
+
|
|
107
|
+
for (let i=0; i<broadcasts.length; i++) {
|
|
108
|
+
try {
|
|
109
|
+
if (i%1000 === 0) console.log(i);
|
|
110
|
+
// await siteRepository.save(broadcasts[i].site);
|
|
111
|
+
|
|
112
|
+
const siteName = broadcasts[i].site.name;
|
|
113
|
+
const site = await AppDataSource.manager.findOne(Site, {where: {name: siteName}});
|
|
114
|
+
if (site) {
|
|
115
|
+
broadcasts[i].site = site;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
await AppDataSource.manager.save(broadcasts[i].site);
|
|
119
|
+
}
|
|
120
|
+
await AppDataSource.manager.save(broadcasts[i]);
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
console.log(i, 'NOT UNIQUE', broadcasts[i]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
}).catch(error => console.log(error))
|
package/sqlite/data-source.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import "reflect-metadata"
|
|
2
|
-
import { DataSource } from "typeorm"
|
|
3
|
-
import { Site } from "./entity/Site"
|
|
4
|
-
import { Broadcast } from "./entity/Broadcast"
|
|
5
|
-
|
|
6
|
-
const currentTime = new Date();
|
|
7
|
-
|
|
8
|
-
export const AppDataSource = new DataSource({
|
|
9
|
-
type: "sqlite",
|
|
10
|
-
// database: `database_${currentTime.getFullYear()}-${currentTime.getMonth()}-${currentTime.getDate()}_${currentTime.getHours()}${currentTime.getMinutes()}${currentTime.getSeconds()}.sqlite`,
|
|
11
|
-
database: `database.sqlite`,
|
|
12
|
-
synchronize: true,
|
|
13
|
-
logging: false,
|
|
14
|
-
entities: [Site, Broadcast],
|
|
15
|
-
migrations: [],
|
|
16
|
-
subscribers: [],
|
|
17
|
-
})
|
|
1
|
+
import "reflect-metadata"
|
|
2
|
+
import { DataSource } from "typeorm"
|
|
3
|
+
import { Site } from "./entity/Site"
|
|
4
|
+
import { Broadcast } from "./entity/Broadcast"
|
|
5
|
+
|
|
6
|
+
const currentTime = new Date();
|
|
7
|
+
|
|
8
|
+
export const AppDataSource = new DataSource({
|
|
9
|
+
type: "sqlite",
|
|
10
|
+
// database: `database_${currentTime.getFullYear()}-${currentTime.getMonth()}-${currentTime.getDate()}_${currentTime.getHours()}${currentTime.getMinutes()}${currentTime.getSeconds()}.sqlite`,
|
|
11
|
+
database: `database.sqlite`,
|
|
12
|
+
synchronize: true,
|
|
13
|
+
logging: false,
|
|
14
|
+
entities: [Site, Broadcast],
|
|
15
|
+
migrations: [],
|
|
16
|
+
subscribers: [],
|
|
17
|
+
})
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Unique} from "typeorm";
|
|
2
|
-
import {Site} from "./Site";
|
|
3
|
-
|
|
4
|
-
@Entity()
|
|
5
|
-
@Unique(['frequency', 'days', 'startTime', 'endTime', 'station', 'country', 'language', 'site'])
|
|
6
|
-
export class Broadcast {
|
|
7
|
-
|
|
8
|
-
@PrimaryGeneratedColumn()
|
|
9
|
-
id: number;
|
|
10
|
-
|
|
11
|
-
@Column({nullable: true})
|
|
12
|
-
frequency: number;
|
|
13
|
-
|
|
14
|
-
@Column({nullable: true})
|
|
15
|
-
days: number;
|
|
16
|
-
|
|
17
|
-
@Column({nullable: true})
|
|
18
|
-
startTime: number;
|
|
19
|
-
|
|
20
|
-
@Column({nullable: true})
|
|
21
|
-
endTime: number;
|
|
22
|
-
|
|
23
|
-
@Column({nullable: true})
|
|
24
|
-
station: string;
|
|
25
|
-
|
|
26
|
-
@Column({nullable: true})
|
|
27
|
-
country: string;
|
|
28
|
-
|
|
29
|
-
@Column({nullable: true})
|
|
30
|
-
language: string;
|
|
31
|
-
|
|
32
|
-
@Column({nullable: true})
|
|
33
|
-
source: string;
|
|
34
|
-
|
|
35
|
-
@ManyToOne(type => Site)
|
|
36
|
-
@JoinColumn()
|
|
37
|
-
site: Site;
|
|
38
|
-
}
|
|
1
|
+
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Unique} from "typeorm";
|
|
2
|
+
import {Site} from "./Site";
|
|
3
|
+
|
|
4
|
+
@Entity()
|
|
5
|
+
@Unique(['frequency', 'days', 'startTime', 'endTime', 'station', 'country', 'language', 'site'])
|
|
6
|
+
export class Broadcast {
|
|
7
|
+
|
|
8
|
+
@PrimaryGeneratedColumn()
|
|
9
|
+
id: number;
|
|
10
|
+
|
|
11
|
+
@Column({nullable: true})
|
|
12
|
+
frequency: number;
|
|
13
|
+
|
|
14
|
+
@Column({nullable: true})
|
|
15
|
+
days: number;
|
|
16
|
+
|
|
17
|
+
@Column({nullable: true})
|
|
18
|
+
startTime: number;
|
|
19
|
+
|
|
20
|
+
@Column({nullable: true})
|
|
21
|
+
endTime: number;
|
|
22
|
+
|
|
23
|
+
@Column({nullable: true})
|
|
24
|
+
station: string;
|
|
25
|
+
|
|
26
|
+
@Column({nullable: true})
|
|
27
|
+
country: string;
|
|
28
|
+
|
|
29
|
+
@Column({nullable: true})
|
|
30
|
+
language: string;
|
|
31
|
+
|
|
32
|
+
@Column({nullable: true})
|
|
33
|
+
source: string;
|
|
34
|
+
|
|
35
|
+
@ManyToOne(type => Site)
|
|
36
|
+
@JoinColumn()
|
|
37
|
+
site: Site;
|
|
38
|
+
}
|
package/sqlite/entity/Site.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import {Entity, PrimaryGeneratedColumn, Column, Unique, OneToMany} from "typeorm";
|
|
2
|
-
import {Broadcast} from "./Broadcast";
|
|
3
|
-
|
|
4
|
-
@Entity()
|
|
5
|
-
@Unique(['name'])
|
|
6
|
-
export class Site {
|
|
7
|
-
|
|
8
|
-
@PrimaryGeneratedColumn()
|
|
9
|
-
id: number;
|
|
10
|
-
|
|
11
|
-
@Column()
|
|
12
|
-
name: string;
|
|
13
|
-
|
|
14
|
-
@Column()
|
|
15
|
-
power: number;
|
|
16
|
-
|
|
17
|
-
@Column()
|
|
18
|
-
lon: number;
|
|
19
|
-
|
|
20
|
-
@Column()
|
|
21
|
-
lat: number;
|
|
22
|
-
|
|
23
|
-
@OneToMany(type => Broadcast, broadcasts => broadcasts.site)
|
|
24
|
-
broadcasts: Broadcast[];
|
|
25
|
-
|
|
26
|
-
}
|
|
1
|
+
import {Entity, PrimaryGeneratedColumn, Column, Unique, OneToMany} from "typeorm";
|
|
2
|
+
import {Broadcast} from "./Broadcast";
|
|
3
|
+
|
|
4
|
+
@Entity()
|
|
5
|
+
@Unique(['name'])
|
|
6
|
+
export class Site {
|
|
7
|
+
|
|
8
|
+
@PrimaryGeneratedColumn()
|
|
9
|
+
id: number;
|
|
10
|
+
|
|
11
|
+
@Column()
|
|
12
|
+
name: string;
|
|
13
|
+
|
|
14
|
+
@Column()
|
|
15
|
+
power: number;
|
|
16
|
+
|
|
17
|
+
@Column()
|
|
18
|
+
lon: number;
|
|
19
|
+
|
|
20
|
+
@Column()
|
|
21
|
+
lat: number;
|
|
22
|
+
|
|
23
|
+
@OneToMany(type => Broadcast, broadcasts => broadcasts.site)
|
|
24
|
+
broadcasts: Broadcast[];
|
|
25
|
+
|
|
26
|
+
}
|