Skip to content

Commit aa4e66d

Browse files
author
ssysm
committed
v2 init
1 parent f6b9547 commit aa4e66d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2322
-385
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,5 @@ testem.log
3737
# System Files
3838
.DS_Store
3939
Thumbs.db
40+
41+
release-builds/

angular.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
"build": {
1818
"builder": "@angular-devkit/build-angular:browser",
1919
"options": {
20-
"outputPath": "dist/StreamGetter-electron",
20+
"outputPath": "dist/",
2121
"index": "src/index.html",
2222
"main": "src/main.ts",
2323
"polyfills": "src/polyfills.ts",
2424
"tsConfig": "src/tsconfig.app.json",
2525
"assets": [
2626
"src/favicon.ico",
27-
"src/assets"
27+
"src/assets",
28+
"src/manifest.json"
2829
],
2930
"styles": [
3031
"src/styles.scss"
@@ -54,7 +55,8 @@
5455
"maximumWarning": "2mb",
5556
"maximumError": "5mb"
5657
}
57-
]
58+
],
59+
"serviceWorker": true
5860
}
5961
}
6062
},
@@ -88,7 +90,8 @@
8890
"scripts": [],
8991
"assets": [
9092
"src/favicon.ico",
91-
"src/assets"
93+
"src/assets",
94+
"src/manifest.json"
9295
]
9396
}
9497
},

electron-main.js

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
const {app, BrowserWindow,Menu} = require('electron');
2+
const ipc = require('electron').ipcMain;
3+
const axios = require('axios');
4+
const cheerio = require('cheerio');
5+
const WebSocket = require('ws');
6+
const path = require('path')
7+
const url = require('url')
8+
9+
let win,socket;
10+
11+
function createWindow () {
12+
win = new BrowserWindow({
13+
width: 1280,
14+
height: 720,
15+
webPreferences: {
16+
devTools: false
17+
}
18+
});
19+
20+
// load the dist folder from Angular
21+
win.loadURL(url.format({
22+
pathname: path.join(__dirname, 'dist/index.html'),
23+
protocol: 'file:',
24+
slashes: true
25+
}))
26+
27+
// Open the DevTools optionally:
28+
// win.webContents.openDevTools()
29+
30+
win.on('closed', () => {
31+
win = null
32+
})
33+
}
34+
35+
app.on('ready', createWindow)
36+
37+
38+
app.on('window-all-closed', () => {
39+
if (process.platform !== 'darwin') {
40+
app.quit()
41+
}
42+
})
43+
44+
app.on('activate', () => {
45+
if (win === null) {
46+
createWindow()
47+
}
48+
})
49+
50+
/////////////////Set Menu //////////////////
51+
52+
const template = [
53+
{
54+
label: 'Edit',
55+
submenu: [
56+
{ role: 'undo' },
57+
{ role: 'redo' },
58+
{ type: 'separator' },
59+
{ role: 'cut' },
60+
{ role: 'copy' },
61+
{ role: 'paste' },
62+
{ role: 'pasteandmatchstyle' },
63+
{ role: 'delete' },
64+
{ role: 'selectall' }
65+
]
66+
},
67+
{
68+
label: 'View',
69+
submenu: [
70+
{ role: 'reload' },
71+
{ role: 'forcereload' },
72+
{ type: 'separator' },
73+
{ role: 'resetzoom' },
74+
{ role: 'zoomin' },
75+
{ role: 'zoomout' },
76+
{ type: 'separator' },
77+
]
78+
},
79+
{
80+
role: 'window',
81+
submenu: [
82+
{ role: 'minimize' },
83+
{ role: 'close' }
84+
]
85+
}
86+
]
87+
88+
if (process.platform === 'darwin') {
89+
template.unshift({
90+
label: app.getName(),
91+
submenu: [
92+
{ role: 'about' },
93+
{ type: 'separator' },
94+
{ role: 'services', submenu: [] },
95+
{ type: 'separator' },
96+
{ role: 'hide' },
97+
{ role: 'hideothers' },
98+
{ role: 'unhide' },
99+
{ type: 'separator' },
100+
{ role: 'quit' }
101+
]
102+
})
103+
104+
// Edit menu
105+
template[1].submenu.push(
106+
{ type: 'separator' },
107+
{
108+
label: 'Speech',
109+
submenu: [
110+
{ role: 'startspeaking' },
111+
{ role: 'stopspeaking' }
112+
]
113+
}
114+
)
115+
116+
// Window menu
117+
template[3].submenu = [
118+
{ role: 'close' },
119+
{ role: 'minimize' },
120+
{ role: 'zoom' },
121+
{ type: 'separator' },
122+
{ role: 'front' }
123+
]
124+
}
125+
126+
const menu = Menu.buildFromTemplate(template)
127+
Menu.setApplicationMenu(menu)
128+
129+
/////////////////Nico Nico /////////////////
130+
131+
132+
ipc.on('niconico_requestLink',requestLink);
133+
ipc.on('niconico_stopAlive',stopAlive);
134+
135+
function requestLink(event,args) {
136+
console.log(args.videoId.videoId);
137+
axios.get('http://live2.nicovideo.jp/watch/lv'+args.videoId.videoId)
138+
.then(res => res.data)
139+
.then(data => {
140+
//parse HTML
141+
const $ = cheerio.load(data);
142+
//获取页面配置
143+
const config = JSON.parse($('#embedded-data').attr('data-props'));
144+
createSocket({
145+
//Socket链接
146+
socketURL: config.site.relive.webSocketUrl,
147+
//广播ID
148+
broadcastId: config.program.broadcastId
149+
});
150+
})
151+
//Promise错误
152+
.catch(e => {
153+
win.webContents.send('niconico_failed',{});
154+
console.error(e+"promise failed");
155+
});
156+
}
157+
158+
function createSocket({ socketURL, broadcastId }){
159+
socket = new WebSocket(socketURL);
160+
socket.on('open', () => {
161+
console.log('Socket Opened');
162+
socket.send(JSON.stringify({
163+
type: 'watch',
164+
body: {
165+
command: 'getpermit',
166+
requirement: {
167+
broadcastId,
168+
route: '',
169+
stream: {
170+
protocol: 'hls',
171+
requireNewStream: true,
172+
priorStreamQuality: 'high',
173+
isLowLatency: true
174+
},
175+
room: {
176+
isCommentable: true,
177+
protocol: 'webSocket'
178+
}
179+
}
180+
}
181+
}));
182+
});
183+
socket.on('message', (data) => {
184+
data = JSON.parse(data);
185+
//just for debug
186+
//console.log(data);
187+
if (data.type === "ping") {
188+
//应答心跳包
189+
socket.send(JSON.stringify({
190+
type: 'pong',
191+
body: {}
192+
}));
193+
console.log('Heartbeat packet sent');
194+
} else if (data.type) {
195+
switch (data.body.command) {
196+
//回响时间
197+
case 'servertime':
198+
socket.send(JSON.stringify({
199+
type: 'watch',
200+
body: {
201+
command: 'watching',
202+
params: [broadcastId, '-1', '0']
203+
}
204+
}));
205+
console.log('Time response answered');
206+
break;
207+
//Console出m3u8播放列表
208+
case 'currentstream':
209+
win.webContents.send('niconico_responseStream', data.body.currentStream.uri);
210+
console.log('Got stream playlist at ' + data.body.currentStream.uri);
211+
break;
212+
}
213+
}
214+
});
215+
}
216+
217+
function stopAlive() {
218+
socket.terminate();
219+
console.log('Socket service terminated.Have a good night.');
220+
win.webContents.send('niconico_socketClosed',true);
221+
}

external/niconico_keepalive.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
const axios = require('axios');
2+
const cheerio = require('cheerio');
3+
const WebSocket = require('ws');
4+
const ipc = require('electron').ipcMain;
5+
const { remote } = require('electron');
6+
let socket = null,win;
7+
8+
ipc.on('niconico_requestLink',requestLink);
9+
ipc.on('niconico_stopAlive',stopAlive);
10+
11+
function requestLink(event,args) {
12+
win = remote.getCurrentWindow() ;
13+
axios.get('http://live2.nicovideo.jp/watch/lv'+args.videoId)
14+
.then(res => res.data)
15+
.then(data => {
16+
//parse HTML
17+
const $ = cheerio.load(data);
18+
//获取页面配置
19+
const config = JSON.parse($('#embedded-data').attr('data-props'));
20+
createSocket({
21+
//Socket链接
22+
socketURL: config.site.relive.webSocketUrl,
23+
//广播ID
24+
broadcastId: config.program.broadcastId
25+
});
26+
})
27+
//Promise错误
28+
.catch(e => {
29+
win.send('niconico_failed',{e});
30+
console.error(e);
31+
});
32+
}
33+
34+
function createSocket({ socketURL, broadcastId }){
35+
socket = new WebSocket(socketURL);
36+
socket.on('open', () => {
37+
console.log('Socket Opened');
38+
socket.send(JSON.stringify({
39+
type: 'watch',
40+
body: {
41+
command: 'getpermit',
42+
requirement: {
43+
broadcastId,
44+
route: '',
45+
stream: {
46+
protocol: 'hls',
47+
requireNewStream: true,
48+
priorStreamQuality: 'high',
49+
isLowLatency: true
50+
},
51+
room: {
52+
isCommentable: true,
53+
protocol: 'webSocket'
54+
}
55+
}
56+
}
57+
}));
58+
});
59+
socket.on('message', (data) => {
60+
data = JSON.parse(data);
61+
//just for debug
62+
//console.log(data);
63+
if (data.type === "ping") {
64+
//应答心跳包
65+
socket.send(JSON.stringify({
66+
type: 'pong',
67+
body: {}
68+
}));
69+
console.log('Heartbeat packet sent');
70+
} else if (data.type) {
71+
switch (data.body.command) {
72+
//回响时间
73+
case 'servertime':
74+
socket.send(JSON.stringify({
75+
type: 'watch',
76+
body: {
77+
command: 'watching',
78+
params: [broadcastId, '-1', '0']
79+
}
80+
}));
81+
console.log('Time response answered');
82+
break;
83+
//Console出m3u8播放列表
84+
case 'currentstream':
85+
win.webContents.send('niconico_responseStream', data.body.currentStream.uri);
86+
console.log('Got stream playlist at ' + data.body.currentStream.uri);
87+
break;
88+
}
89+
}
90+
});
91+
}
92+
93+
function stopAlive() {
94+
socket.close();
95+
win.webContents.send('niconico_socketClosed',true);
96+
}
97+

ngsw-config.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"index": "/index.html",
3+
"assetGroups": [
4+
{
5+
"name": "app",
6+
"installMode": "prefetch",
7+
"resources": {
8+
"files": [
9+
"/favicon.ico",
10+
"/index.html",
11+
"/*.css",
12+
"/*.js"
13+
]
14+
}
15+
}, {
16+
"name": "assets",
17+
"installMode": "lazy",
18+
"updateMode": "prefetch",
19+
"resources": {
20+
"files": [
21+
"/assets/**"
22+
]
23+
}
24+
}
25+
]
26+
}

0 commit comments

Comments
 (0)