mlbserver 2022.8.8 → 2022.8.23
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/Dockerfile +24 -0
- package/README.md +77 -6
- package/docker-compose.yml +29 -0
- package/index.js +46 -38
- package/package.json +1 -1
- package/session.js +107 -74
package/Dockerfile
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
FROM node:16-alpine
|
|
2
|
+
|
|
3
|
+
RUN apk update && apk add tzdata
|
|
4
|
+
|
|
5
|
+
# Create app directory
|
|
6
|
+
WORKDIR /mlbserver
|
|
7
|
+
|
|
8
|
+
# Add data directory
|
|
9
|
+
VOLUME /mlbserver/data_directory
|
|
10
|
+
|
|
11
|
+
# Install app dependencies
|
|
12
|
+
# A wildcard is used to ensure both package.json AND package-lock.json are copied
|
|
13
|
+
# where available (npm@5+)
|
|
14
|
+
COPY package*.json ./
|
|
15
|
+
|
|
16
|
+
RUN npm install
|
|
17
|
+
# If you are building your code for production
|
|
18
|
+
# RUN npm ci --only=production
|
|
19
|
+
|
|
20
|
+
# Bundle app source
|
|
21
|
+
COPY . .
|
|
22
|
+
|
|
23
|
+
EXPOSE 9999 10000
|
|
24
|
+
CMD [ "node", "index.js", "--env" ]
|
package/README.md
CHANGED
|
@@ -1,24 +1,94 @@
|
|
|
1
1
|
# mlbserver
|
|
2
2
|
|
|
3
|
-
Current version 2022.08.
|
|
3
|
+
Current version 2022.08.23
|
|
4
4
|
|
|
5
5
|
Credit to https://github.com/tonycpsu/streamglob and https://github.com/mafintosh/hls-decryptor
|
|
6
6
|
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### node-cli
|
|
7
10
|
```
|
|
8
11
|
npm install -g mlbserver
|
|
9
12
|
```
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
### docker
|
|
15
|
+
```
|
|
16
|
+
docker pull tonywagner/mlbserver
|
|
17
|
+
```
|
|
18
|
+
|
|
12
19
|
|
|
13
|
-
Launch
|
|
20
|
+
## Launch
|
|
14
21
|
|
|
22
|
+
### node-cli (follow the prompts on first run, or see below for possible command line options)
|
|
15
23
|
```
|
|
16
24
|
mlbserver
|
|
17
25
|
```
|
|
26
|
+
or in application directory:
|
|
27
|
+
```
|
|
28
|
+
node index.js
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### docker-compose
|
|
32
|
+
Update the environment variables below and save it as docker-compose.yml:
|
|
33
|
+
```
|
|
34
|
+
version: "3"
|
|
35
|
+
services:
|
|
36
|
+
mlbserver:
|
|
37
|
+
image: tonywagner/mlbserver:latest
|
|
38
|
+
container_name: mlbserver
|
|
39
|
+
environment:
|
|
40
|
+
- TZ=America/New York
|
|
41
|
+
- data_directory=/mlbserver/data_directory
|
|
42
|
+
- account_username=your.account.email@example.com
|
|
43
|
+
- account_password=youraccountpassword
|
|
44
|
+
- zip_code=0
|
|
45
|
+
- fav_teams=0
|
|
46
|
+
#- zip_code=00000
|
|
47
|
+
#- fav_teams=ARI,ATL
|
|
48
|
+
#- debug=false
|
|
49
|
+
#- port=9999
|
|
50
|
+
#- multiview_port=10000
|
|
51
|
+
#- multiview_path=
|
|
52
|
+
#- ffmpeg_path=
|
|
53
|
+
#- ffmpeg_encoder=
|
|
54
|
+
#- page_username=
|
|
55
|
+
#- page_password=
|
|
56
|
+
#- content_protect=
|
|
57
|
+
#- gamechanger_delay=0
|
|
58
|
+
ports:
|
|
59
|
+
- 9999:9999
|
|
60
|
+
- 10000:10000
|
|
61
|
+
volumes:
|
|
62
|
+
- /mlbserver/data_directory
|
|
63
|
+
```
|
|
64
|
+
Then launch it with ```docker-compose up --detach```
|
|
65
|
+
|
|
66
|
+
### docker-cli
|
|
67
|
+
Update the environment variables in the command below and run it:
|
|
68
|
+
```
|
|
69
|
+
docker run -d \
|
|
70
|
+
--name mlbserver \
|
|
71
|
+
--env TZ="America/New_York" \
|
|
72
|
+
--env data_directory=/mlbserver/data_directory \
|
|
73
|
+
--env account_username=your.account.email@example.com \
|
|
74
|
+
--env account_password=youraccountpassword \
|
|
75
|
+
--env zip_code=0 \
|
|
76
|
+
--env fav_teams=0 \
|
|
77
|
+
-p 9999:9999 \
|
|
78
|
+
-p 10000:10000 \
|
|
79
|
+
--volume /mlbserver/data_directory \
|
|
80
|
+
tonywagner/mlbserver
|
|
81
|
+
```
|
|
82
|
+
Subsequent runs can be launched with ```docker start mlbserver```
|
|
83
|
+
|
|
84
|
+
Docker installs may require further configuration to get multiview streaming to work.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Usage
|
|
18
88
|
|
|
19
|
-
|
|
89
|
+
After launching the server or Docker container, you can access it at http://localhost:9999 on the same machine, or substitute your computer's IP address for localhost to access it from a different device. Load that address in a web browser to start using the server and to see more documentation.
|
|
20
90
|
|
|
21
|
-
Basic command line options:
|
|
91
|
+
Basic command line or Docker environment options:
|
|
22
92
|
|
|
23
93
|
```
|
|
24
94
|
--port or -p (primary port to run on; defaults to 9999 if not specified)
|
|
@@ -27,9 +97,10 @@ Basic command line options:
|
|
|
27
97
|
--logout or -l (logs out and clears session)
|
|
28
98
|
--session or -s (clears session)
|
|
29
99
|
--cache or -c (clears cache)
|
|
100
|
+
--env or -e (use environment variables instead of command line arguments; necessary for Docker)
|
|
30
101
|
```
|
|
31
102
|
|
|
32
|
-
Advanced command line options:
|
|
103
|
+
Advanced command line or Docker environment options:
|
|
33
104
|
|
|
34
105
|
```
|
|
35
106
|
--account_username (email address, default will use stored credentials or prompt user to enter them)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
services:
|
|
3
|
+
mlbserver:
|
|
4
|
+
image: tonywagner/mlbserver:latest
|
|
5
|
+
container_name: mlbserver
|
|
6
|
+
environment:
|
|
7
|
+
- TZ=America/New York
|
|
8
|
+
- data_directory=/mlbserver/data_directory
|
|
9
|
+
- account_username=your.account.email@example.com
|
|
10
|
+
- account_password=youraccountpassword
|
|
11
|
+
- zip_code=0
|
|
12
|
+
- fav_teams=0
|
|
13
|
+
#- zip_code=00000
|
|
14
|
+
#- fav_teams=ARI,ATL
|
|
15
|
+
#- debug=false
|
|
16
|
+
#- port=9999
|
|
17
|
+
#- multiview_port=10000
|
|
18
|
+
#- multiview_path=
|
|
19
|
+
#- ffmpeg_path=
|
|
20
|
+
#- ffmpeg_encoder=
|
|
21
|
+
#- page_username=
|
|
22
|
+
#- page_password=
|
|
23
|
+
#- content_protect=
|
|
24
|
+
#- gamechanger_delay=0
|
|
25
|
+
ports:
|
|
26
|
+
- 9999:9999
|
|
27
|
+
- 10000:10000
|
|
28
|
+
volumes:
|
|
29
|
+
- /mlbserver/data_directory
|
package/index.js
CHANGED
|
@@ -104,9 +104,10 @@ const GAMECHANGER_RESPONSE_HEADERS = {"statusCode":200,"headers":{"content-type"
|
|
|
104
104
|
// --account_password (default will use stored credentials or prompt user to enter them)
|
|
105
105
|
// --zip_code (optional, for USA blackout labels, will prompt if not set or stored)
|
|
106
106
|
// --fav_teams (optional, comma-separated list of favorite team abbreviations, will prompt if not set or stored)
|
|
107
|
+
// --data_directory (defaults to app directory, must already exist if set to something else; should match storage volume for Docker)
|
|
107
108
|
// --free (optional, free account, highlights free games)
|
|
108
109
|
// --multiview_port (port for multiview streaming; defaults to 1 more than primary port, or 10000)
|
|
109
|
-
// --multiview_path (where to create the folder for multiview encoded files; defaults to
|
|
110
|
+
// --multiview_path (where to create the folder for multiview encoded files; defaults to data directory)
|
|
110
111
|
// --ffmpeg_path (path to ffmpeg binary to use for multiview encoding; default downloads a binary using ffmpeg-static)
|
|
111
112
|
// --ffmpeg_encoder (ffmpeg video encoder to use for multiview; default is the software encoder libx264)
|
|
112
113
|
// --ffmpeg_logging (if present, logs all ffmpeg output -- useful for experimenting or troubleshooting)
|
|
@@ -125,7 +126,7 @@ var argv = minimist(process.argv, {
|
|
|
125
126
|
e: 'env'
|
|
126
127
|
},
|
|
127
128
|
boolean: ['ffmpeg_logging', 'debug', 'logout', 'session', 'cache', 'version', 'free', 'env'],
|
|
128
|
-
string: ['port', 'account_username', 'account_password', 'multiview_port', 'multiview_path', 'ffmpeg_path', 'ffmpeg_encoder', 'page_username', 'page_password', 'content_protect', 'gamechanger_delay']
|
|
129
|
+
string: ['port', 'account_username', 'account_password', 'multiview_port', 'multiview_path', 'ffmpeg_path', 'ffmpeg_encoder', 'page_username', 'page_password', 'content_protect', 'gamechanger_delay', 'data_directory']
|
|
129
130
|
})
|
|
130
131
|
|
|
131
132
|
if (argv.env) argv = process.env
|
|
@@ -359,20 +360,18 @@ app.get('/stream.m3u8', async function(req, res) {
|
|
|
359
360
|
}
|
|
360
361
|
})
|
|
361
362
|
|
|
362
|
-
// Store previous keys, for return without decoding
|
|
363
|
-
var prevKeys = {}
|
|
364
363
|
var getKey = function(url, headers, cb) {
|
|
365
|
-
if (
|
|
366
|
-
return cb(null, prevKeys[url]
|
|
364
|
+
if ( session.temp_cache.prevKeys[url] ) {
|
|
365
|
+
return cb(null, session.temp_cache.prevKeys[url])
|
|
367
366
|
}
|
|
368
367
|
|
|
369
|
-
if ( typeof prevKeys[url] === 'undefined' ) prevKeys[url] = {}
|
|
370
|
-
|
|
371
368
|
session.debuglog('key request : ' + url)
|
|
372
369
|
requestRetry(url, headers, function(err, response) {
|
|
373
370
|
if (err) return cb(err)
|
|
374
|
-
|
|
375
|
-
|
|
371
|
+
let key = response.body
|
|
372
|
+
session.debuglog('key returned ' + key)
|
|
373
|
+
session.temp_cache.prevKeys[url] = key
|
|
374
|
+
cb(null, key)
|
|
376
375
|
})
|
|
377
376
|
}
|
|
378
377
|
|
|
@@ -582,7 +581,13 @@ function getMasterPlaylist(streamURL, req, res, options = {}) {
|
|
|
582
581
|
// if user specified "none" for video track
|
|
583
582
|
if ( resolution == VALID_RESOLUTIONS[VALID_RESOLUTIONS.length-1] ) {
|
|
584
583
|
audio_track_matched = true
|
|
585
|
-
audio_output = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="' + key + '",
|
|
584
|
+
audio_output = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="' + key + '",LANGUAGE="'
|
|
585
|
+
if ( key == ALTERNATE_AUDIO_TRACKS[1] ) {
|
|
586
|
+
audio_output += 'es'
|
|
587
|
+
} else {
|
|
588
|
+
audio_output += 'en'
|
|
589
|
+
}
|
|
590
|
+
audio_output += '",AUTOSELECT=YES,DEFAULT=YES' + "\n" + '#EXT-X-STREAM-INF:BANDWIDTH=50000,CODECS="mp4a.40.2",AUDIO="aac"' + "\n" + newurl
|
|
586
591
|
} else {
|
|
587
592
|
if (audio_output != '') audio_output += "\n"
|
|
588
593
|
audio_output += '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="' + key + '",AUTOSELECT=YES,DEFAULT='
|
|
@@ -768,13 +773,16 @@ app.get('/playlist', async function(req, res) {
|
|
|
768
773
|
session.debuglog('key line : ' + line)
|
|
769
774
|
var parsed = line.match(/URI="([^"]+)"(?:,IV=(.+))?$/)
|
|
770
775
|
if ( parsed ) {
|
|
771
|
-
if ( parsed[1].
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
if ( key.startsWith('data:;base64,') ) {
|
|
776
|
+
if ( parsed[1].startsWith('http') ) {
|
|
777
|
+
key = parsed[1]
|
|
778
|
+
session.debuglog('key url : ' + key)
|
|
779
|
+
} else if ( key.startsWith('data:;base64,') ) {
|
|
775
780
|
let newparsed = key.split(',')
|
|
776
781
|
key = newparsed[1]
|
|
777
|
-
session.debuglog('found
|
|
782
|
+
session.debuglog('found key data : ' + key)
|
|
783
|
+
} else {
|
|
784
|
+
key = url.resolve(u, parsed[1])
|
|
785
|
+
session.debuglog('resolved key url : ' + key)
|
|
778
786
|
}
|
|
779
787
|
if (parsed[2]) iv = parsed[2].slice(2).toLowerCase()
|
|
780
788
|
}
|
|
@@ -783,8 +791,10 @@ app.get('/playlist', async function(req, res) {
|
|
|
783
791
|
|
|
784
792
|
if (line[0] === '#') return line
|
|
785
793
|
|
|
786
|
-
|
|
787
|
-
|
|
794
|
+
let newline = '/ts?url='+encodeURIComponent(url.resolve(u, line.trim())) + content_protect + referer_parameter
|
|
795
|
+
if ( key ) newline += '&key='+encodeURIComponent(key) + '&iv='+encodeURIComponent(iv)
|
|
796
|
+
|
|
797
|
+
return newline
|
|
788
798
|
})
|
|
789
799
|
.filter(function(line) {
|
|
790
800
|
return line
|
|
@@ -849,19 +859,8 @@ app.get('/ts', async function(req, res) {
|
|
|
849
859
|
if (!req.query.key) return respond(response, res, response.body)
|
|
850
860
|
|
|
851
861
|
try {
|
|
852
|
-
//var ku = url.resolve(manifest, req.query.key)
|
|
853
862
|
var ku = req.query.key
|
|
854
|
-
if ( ku.
|
|
855
|
-
var iv = Buffer.from(req.query.iv, 'hex')
|
|
856
|
-
session.debuglog('iv : 0x'+req.query.iv)
|
|
857
|
-
|
|
858
|
-
let key = Buffer.from(ku, "base64")
|
|
859
|
-
|
|
860
|
-
var dc = crypto.createDecipheriv('aes-128-cbc', key, iv)
|
|
861
|
-
var buffer = Buffer.concat([dc.update(response.body), dc.final()])
|
|
862
|
-
|
|
863
|
-
respond(response, res, buffer)
|
|
864
|
-
} else {
|
|
863
|
+
if ( ku.startsWith('http') ) {
|
|
865
864
|
getKey(ku, headers, function(err, key) {
|
|
866
865
|
if (err) return res.error(err)
|
|
867
866
|
|
|
@@ -873,6 +872,16 @@ app.get('/ts', async function(req, res) {
|
|
|
873
872
|
|
|
874
873
|
respond(response, res, buffer)
|
|
875
874
|
})
|
|
875
|
+
} else {
|
|
876
|
+
var iv = Buffer.from(req.query.iv, 'hex')
|
|
877
|
+
session.debuglog('iv : 0x'+req.query.iv)
|
|
878
|
+
|
|
879
|
+
let key = Buffer.from(ku, "base64")
|
|
880
|
+
|
|
881
|
+
var dc = crypto.createDecipheriv('aes-128-cbc', key, iv)
|
|
882
|
+
var buffer = Buffer.concat([dc.update(response.body), dc.final()])
|
|
883
|
+
|
|
884
|
+
respond(response, res, buffer)
|
|
876
885
|
}
|
|
877
886
|
} catch (e) {
|
|
878
887
|
session.log('key decode error : ' + e.message)
|
|
@@ -1267,7 +1276,7 @@ app.get('/', async function(req, res) {
|
|
|
1267
1276
|
body += 'function makeGETRequest(url, callback){var request=new XMLHttpRequest();request.onreadystatechange=function(){if (request.readyState==4 && request.status==200){callback(request.responseText)}};request.open("GET", url);request.send();}' + "\n"
|
|
1268
1277
|
|
|
1269
1278
|
// Multiview functions
|
|
1270
|
-
body += 'function parsemultiviewresponse(responsetext){if (responsetext == "started"){setTimeout(function(){document.getElementById("startmultiview").innerHTML="Restart";document.getElementById("stopmultiview").innerHTML="Stop"},15000)}else if (responsetext == "stopped"){setTimeout(function(){document.getElementById("stopmultiview").innerHTML="Stopped";document.getElementById("startmultiview").innerHTML="Start"},3000)}else{alert(responsetext)}}function addmultiview(e){for(var i=1;i<=4;i++){var valuefound = false;var oldvalue="";
|
|
1279
|
+
body += 'var excludeTeams=[];function parsemultiviewresponse(responsetext){if (responsetext == "started"){setTimeout(function(){document.getElementById("startmultiview").innerHTML="Restart";document.getElementById("stopmultiview").innerHTML="Stop"},15000)}else if (responsetext == "stopped"){setTimeout(function(){document.getElementById("stopmultiview").innerHTML="Stopped";document.getElementById("startmultiview").innerHTML="Start"},3000)}else{alert(responsetext)}}function addmultiview(e, teams=[], excludes=[]){var newvalue=e.value;for(var i=1;i<=4;i++){var valuefound = false;var oldvalue="";if(!e.checked){oldvalue=e.value;newvalue=""}if ((document.getElementById("multiview" + i).value == oldvalue) || ((oldvalue != "") && (document.getElementById("multiview" + i).value.startsWith(oldvalue)))){if ((newvalue != "") && (excludes.length > 0)){newvalue+="&excludeTeams="+excludeTeams.toString()}document.getElementById("multiview" + i).value=newvalue;valuefound=true;break}}if(e.checked && !valuefound){e.checked=false}for(var i=0;i<teams.length;i++){if(e.checked){excludeTeams.push(teams[i])}else{var index=excludeTeams.indexOf(teams[i]);if (index !== -1){excludeTeams.splice(index,1)}}}}function startmultiview(e){var count=0;var getstr="";for(var i=1;i<=4;i++){if (document.getElementById("multiview"+i).value != ""){count++;getstr+="streams="+encodeURIComponent(document.getElementById("multiview"+i).value)+"&sync="+encodeURIComponent(document.getElementById("sync"+i).value)+"&"}}if((count >= 1) && (count <= 4)){if (document.getElementById("faster").checked){getstr+="faster=true&dvr=true&"}else if (document.getElementById("dvr").checked){getstr+="dvr=true&"}if (document.getElementById("reencode").checked){getstr+="reencode=true&"}if (document.getElementById("audio_url").value != ""){getstr+="audio_url="+encodeURIComponent(document.getElementById("audio_url").value)+"&";if (document.getElementById("audio_url_seek").value != "0"){getstr+="audio_url_seek="+encodeURIComponent(document.getElementById("audio_url_seek").value)}}e.innerHTML="starting...";makeGETRequest("/multiview?"+getstr, parsemultiviewresponse)}else{alert("Multiview requires between 1-4 streams to be selected")}return false}function stopmultiview(e){e.innerHTML="stopping...";makeGETRequest("/multiview", parsemultiviewresponse);return false}' + "\n"
|
|
1271
1280
|
|
|
1272
1281
|
// Function to switch URLs to stream URLs, where necessary
|
|
1273
1282
|
body += 'function stream_substitution(url){return url.replace(/\\/([a-zA-Z]+\.html)/,"/stream.m3u8")}' + "\n"
|
|
@@ -1429,15 +1438,14 @@ app.get('/', async function(req, res) {
|
|
|
1429
1438
|
body += '<tr><td><span class="tooltip">' + compareStart.toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) + ' - ' + compareEnd.toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) + '<span class="tooltiptext">The game changer stream will automatically switch between the highest leverage active live non-blackout games, and should be available whenever there are such games available. Does not support adaptive bitrate switching, will default to best resolution if not specified.</span></span></td><td>'
|
|
1430
1439
|
if ( (currentDate >= compareStart) && (currentDate < compareEnd) ) {
|
|
1431
1440
|
let streamURL = server + '/gamechanger.m3u8'
|
|
1432
|
-
|
|
1433
|
-
multiviewquerystring
|
|
1434
|
-
if ( resolution != VALID_RESOLUTIONS[0] ) streamURL += '
|
|
1435
|
-
streamURL += content_protect_b
|
|
1441
|
+
streamURL += content_protect_a
|
|
1442
|
+
let multiviewquerystring = streamURL + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1443
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) streamURL += '&resolution=' + resolution
|
|
1436
1444
|
if ( linkType != VALID_LINK_TYPES[1] ) {
|
|
1437
1445
|
streamURL = thislink + '?src=' + encodeURIComponent(streamURL) + '&startFrom=' + VALID_START_FROM[1] + content_protect_b
|
|
1438
1446
|
}
|
|
1439
1447
|
body += '<a href="' + streamURL + '">Game Changer</a>'
|
|
1440
|
-
body += '<input type="checkbox" value="' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1448
|
+
body += '<input type="checkbox" value="' + multiviewquerystring + '" onclick="addmultiview(this, [], excludeTeams)">'
|
|
1441
1449
|
} else {
|
|
1442
1450
|
body += 'Game Changer'
|
|
1443
1451
|
}
|
|
@@ -1733,7 +1741,7 @@ app.get('/', async function(req, res) {
|
|
|
1733
1741
|
body += stationlink
|
|
1734
1742
|
}
|
|
1735
1743
|
if ( mediaType == 'MLBTV' ) {
|
|
1736
|
-
body += '<input type="checkbox" value="' + server + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1744
|
+
body += '<input type="checkbox" value="' + server + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this, [\'' + awayteam + '\', \'' + hometeam + '\'])">'
|
|
1737
1745
|
}
|
|
1738
1746
|
if ( resumeStatus ) {
|
|
1739
1747
|
body += '('
|
|
@@ -2632,4 +2640,4 @@ app.get('/kodi.strm', async function(req, res) {
|
|
|
2632
2640
|
session.log('kodi.strm request error : ' + e.message)
|
|
2633
2641
|
res.end('kodi.strm request error, check log')
|
|
2634
2642
|
}
|
|
2635
|
-
})
|
|
2643
|
+
})
|
package/package.json
CHANGED
package/session.js
CHANGED
|
@@ -9,17 +9,8 @@ const readlineSync = require('readline-sync')
|
|
|
9
9
|
const FileCookieStore = require('tough-cookie-filestore')
|
|
10
10
|
const parseString = require('xml2js').parseString
|
|
11
11
|
|
|
12
|
-
// Define some file paths and names
|
|
13
|
-
const DATA_DIRECTORY = path.join(__dirname, 'data')
|
|
14
|
-
const CACHE_DIRECTORY = path.join(__dirname, 'cache')
|
|
15
12
|
const MULTIVIEW_DIRECTORY_NAME = 'multiview'
|
|
16
13
|
|
|
17
|
-
const CREDENTIALS_FILE = path.join(__dirname, 'credentials.json')
|
|
18
|
-
const PROTECTION_FILE = path.join(__dirname, 'protection.json')
|
|
19
|
-
const COOKIE_FILE = path.join(DATA_DIRECTORY, 'cookies.json')
|
|
20
|
-
const DATA_FILE = path.join(DATA_DIRECTORY, 'data.json')
|
|
21
|
-
const CACHE_FILE = path.join(CACHE_DIRECTORY, 'cache.json')
|
|
22
|
-
|
|
23
14
|
// Default user agent to use for API requests
|
|
24
15
|
const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:87.0) Gecko/20100101 Firefox/87.0'
|
|
25
16
|
|
|
@@ -824,8 +815,23 @@ class sessionClass {
|
|
|
824
815
|
constructor(argv = {}) {
|
|
825
816
|
this.debug = argv.debug
|
|
826
817
|
|
|
818
|
+
let dirname = __dirname
|
|
819
|
+
if ( argv.data_directory ) {
|
|
820
|
+
dirname = argv.data_directory
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Define some file paths and names
|
|
824
|
+
this.DATA_DIRECTORY = path.join(dirname, 'data')
|
|
825
|
+
this.CACHE_DIRECTORY = path.join(dirname, 'cache')
|
|
826
|
+
|
|
827
|
+
this.CREDENTIALS_FILE = path.join(dirname, 'credentials.json')
|
|
828
|
+
this.PROTECTION_FILE = path.join(dirname, 'protection.json')
|
|
829
|
+
this.COOKIE_FILE = path.join(this.DATA_DIRECTORY, 'cookies.json')
|
|
830
|
+
this.DATA_FILE = path.join(this.DATA_DIRECTORY, 'data.json')
|
|
831
|
+
this.CACHE_FILE = path.join(this.CACHE_DIRECTORY, 'cache.json')
|
|
832
|
+
|
|
827
833
|
// Read credentials from file, if present
|
|
828
|
-
this.credentials = this.readFileToJson(CREDENTIALS_FILE) || {}
|
|
834
|
+
this.credentials = this.readFileToJson(this.CREDENTIALS_FILE) || {}
|
|
829
835
|
|
|
830
836
|
// Check if account credentials were provided and if they are different from the stored credentials
|
|
831
837
|
if ( argv.account_username && argv.account_password && ((argv.account_username != this.credentials.account_username) || (argv.account_password != this.credentials.account_password)) ) {
|
|
@@ -850,7 +856,7 @@ class sessionClass {
|
|
|
850
856
|
this.protection = {}
|
|
851
857
|
if ( argv.page_username && argv.page_password ) {
|
|
852
858
|
// Read protection data from file, if present
|
|
853
|
-
this.protection = this.readFileToJson(PROTECTION_FILE) || {}
|
|
859
|
+
this.protection = this.readFileToJson(this.PROTECTION_FILE) || {}
|
|
854
860
|
|
|
855
861
|
// Check if content_protect key was provided and if it is different from the stored one
|
|
856
862
|
if ( argv.content_protect && (argv.content_protect != this.protection.content_protect) ) {
|
|
@@ -869,39 +875,41 @@ class sessionClass {
|
|
|
869
875
|
}
|
|
870
876
|
|
|
871
877
|
// Create storage directory if it doesn't already exist
|
|
872
|
-
this.createDirectory(DATA_DIRECTORY)
|
|
878
|
+
this.createDirectory(this.DATA_DIRECTORY)
|
|
873
879
|
|
|
874
880
|
// Set multiview path
|
|
875
881
|
if ( argv.multiview_path ) {
|
|
876
|
-
this.multiview_path = path.join(argv.multiview_path, path.basename(
|
|
882
|
+
this.multiview_path = path.join(argv.multiview_path, path.basename(dirname))
|
|
877
883
|
this.createDirectory(this.multiview_path)
|
|
878
884
|
this.multiview_path = path.join(this.multiview_path, MULTIVIEW_DIRECTORY_NAME)
|
|
879
885
|
} else {
|
|
880
|
-
this.multiview_path = path.join(
|
|
886
|
+
this.multiview_path = path.join(dirname, MULTIVIEW_DIRECTORY_NAME)
|
|
881
887
|
}
|
|
882
888
|
this.createDirectory(this.multiview_path)
|
|
883
889
|
|
|
884
890
|
// Create cookie storage file if it doesn't already exist
|
|
885
|
-
this.createFile(COOKIE_FILE)
|
|
891
|
+
this.createFile(this.COOKIE_FILE)
|
|
886
892
|
// Verify its contents are valid
|
|
887
|
-
let cookieStr = fs.readFileSync(COOKIE_FILE)
|
|
893
|
+
let cookieStr = fs.readFileSync(this.COOKIE_FILE)
|
|
888
894
|
if ( (cookieStr != '') && !this.isValidJson(cookieStr) ) {
|
|
889
895
|
this.log('invalid cookie storage file contents, resetting')
|
|
890
|
-
fs.unlinkSync(COOKIE_FILE)
|
|
891
|
-
this.createFile(COOKIE_FILE)
|
|
896
|
+
fs.unlinkSync(this.COOKIE_FILE)
|
|
897
|
+
this.createFile(this.COOKIE_FILE)
|
|
892
898
|
}
|
|
893
899
|
|
|
894
900
|
// Set up http requests with the cookie jar
|
|
895
901
|
this.request = require('request-promise')
|
|
896
|
-
this.jar = this.request.jar(new FileCookieStore(COOKIE_FILE))
|
|
902
|
+
this.jar = this.request.jar(new FileCookieStore(this.COOKIE_FILE))
|
|
897
903
|
this.request = this.request.defaults({timeout:15000, agent:false, jar: this.request.jar()})
|
|
898
904
|
|
|
899
905
|
// Load session data and cache from files
|
|
900
|
-
this.data = this.readFileToJson(DATA_FILE) || {}
|
|
901
|
-
this.cache = this.readFileToJson(CACHE_FILE) || {}
|
|
906
|
+
this.data = this.readFileToJson(this.DATA_FILE) || {}
|
|
907
|
+
this.cache = this.readFileToJson(this.CACHE_FILE) || {}
|
|
902
908
|
|
|
903
|
-
// Define empty temporary cache (for skip and
|
|
909
|
+
// Define empty temporary cache (for skip, gamechanger, and key data)
|
|
904
910
|
this.temp_cache = {}
|
|
911
|
+
// Store previous keys, for return without retrieval
|
|
912
|
+
this.temp_cache.prevKeys = {}
|
|
905
913
|
|
|
906
914
|
// Default scan_mode and linkType values
|
|
907
915
|
if ( !this.data.scan_mode ) {
|
|
@@ -1222,7 +1230,7 @@ class sessionClass {
|
|
|
1222
1230
|
|
|
1223
1231
|
logout() {
|
|
1224
1232
|
try {
|
|
1225
|
-
fs.unlinkSync(CREDENTIALS_FILE)
|
|
1233
|
+
fs.unlinkSync(this.CREDENTIALS_FILE)
|
|
1226
1234
|
} catch(e){
|
|
1227
1235
|
this.debuglog('credentials cannot be cleared or do not exist yet : ' + e.message)
|
|
1228
1236
|
}
|
|
@@ -1230,8 +1238,8 @@ class sessionClass {
|
|
|
1230
1238
|
|
|
1231
1239
|
clear_session_data() {
|
|
1232
1240
|
try {
|
|
1233
|
-
fs.unlinkSync(COOKIE_FILE)
|
|
1234
|
-
fs.unlinkSync(DATA_FILE)
|
|
1241
|
+
fs.unlinkSync(this.COOKIE_FILE)
|
|
1242
|
+
fs.unlinkSync(this.DATA_FILE)
|
|
1235
1243
|
} catch(e){
|
|
1236
1244
|
this.debuglog('session cannot be cleared or does not exist yet : ' + e.message)
|
|
1237
1245
|
}
|
|
@@ -1239,7 +1247,7 @@ class sessionClass {
|
|
|
1239
1247
|
|
|
1240
1248
|
clear_cache() {
|
|
1241
1249
|
try {
|
|
1242
|
-
fs.unlinkSync(CACHE_FILE)
|
|
1250
|
+
fs.unlinkSync(this.CACHE_FILE)
|
|
1243
1251
|
} catch(e){
|
|
1244
1252
|
this.debuglog('cache cannot be cleared or does not exist yet : ' + e.message)
|
|
1245
1253
|
}
|
|
@@ -1268,30 +1276,30 @@ class sessionClass {
|
|
|
1268
1276
|
}
|
|
1269
1277
|
|
|
1270
1278
|
save_credentials() {
|
|
1271
|
-
this.writeJsonToFile(JSON.stringify(this.credentials), CREDENTIALS_FILE)
|
|
1279
|
+
this.writeJsonToFile(JSON.stringify(this.credentials), this.CREDENTIALS_FILE)
|
|
1272
1280
|
this.debuglog('credentials saved to file')
|
|
1273
1281
|
}
|
|
1274
1282
|
|
|
1275
1283
|
save_protection() {
|
|
1276
|
-
this.writeJsonToFile(JSON.stringify(this.protection), PROTECTION_FILE)
|
|
1284
|
+
this.writeJsonToFile(JSON.stringify(this.protection), this.PROTECTION_FILE)
|
|
1277
1285
|
this.debuglog('protection data saved to file')
|
|
1278
1286
|
}
|
|
1279
1287
|
|
|
1280
1288
|
save_session_data() {
|
|
1281
|
-
this.createDirectory(DATA_DIRECTORY)
|
|
1282
|
-
this.writeJsonToFile(JSON.stringify(this.data), DATA_FILE)
|
|
1289
|
+
this.createDirectory(this.DATA_DIRECTORY)
|
|
1290
|
+
this.writeJsonToFile(JSON.stringify(this.data), this.DATA_FILE)
|
|
1283
1291
|
this.debuglog('session data saved to file')
|
|
1284
1292
|
}
|
|
1285
1293
|
|
|
1286
1294
|
save_cache_data() {
|
|
1287
|
-
this.createDirectory(CACHE_DIRECTORY)
|
|
1288
|
-
this.writeJsonToFile(JSON.stringify(this.cache), CACHE_FILE)
|
|
1295
|
+
this.createDirectory(this.CACHE_DIRECTORY)
|
|
1296
|
+
this.writeJsonToFile(JSON.stringify(this.cache), this.CACHE_FILE)
|
|
1289
1297
|
this.debuglog('cache data saved to file')
|
|
1290
1298
|
}
|
|
1291
1299
|
|
|
1292
1300
|
save_json_cache_file(cache_name, cache_data) {
|
|
1293
|
-
this.createDirectory(CACHE_DIRECTORY)
|
|
1294
|
-
this.writeJsonToFile(JSON.stringify(cache_data), path.join(CACHE_DIRECTORY, cache_name+'.json'))
|
|
1301
|
+
this.createDirectory(this.CACHE_DIRECTORY)
|
|
1302
|
+
this.writeJsonToFile(JSON.stringify(cache_data), path.join(this.CACHE_DIRECTORY, cache_name+'.json'))
|
|
1295
1303
|
this.debuglog('cache file saved')
|
|
1296
1304
|
}
|
|
1297
1305
|
|
|
@@ -1312,7 +1320,7 @@ class sessionClass {
|
|
|
1312
1320
|
}
|
|
1313
1321
|
|
|
1314
1322
|
// Generic http GET request function
|
|
1315
|
-
httpGet(reqObj) {
|
|
1323
|
+
httpGet(reqObj, exit=true) {
|
|
1316
1324
|
reqObj.jar = this.jar
|
|
1317
1325
|
return new Promise((resolve, reject) => {
|
|
1318
1326
|
this.request.get(reqObj)
|
|
@@ -1322,7 +1330,11 @@ class sessionClass {
|
|
|
1322
1330
|
.catch(function(e) {
|
|
1323
1331
|
console.log('http get failed : ' + e.message)
|
|
1324
1332
|
console.log(reqObj)
|
|
1325
|
-
|
|
1333
|
+
if ( exit ) {
|
|
1334
|
+
process.exit(1)
|
|
1335
|
+
} else {
|
|
1336
|
+
resolve(false)
|
|
1337
|
+
}
|
|
1326
1338
|
})
|
|
1327
1339
|
})
|
|
1328
1340
|
}
|
|
@@ -1548,7 +1560,7 @@ class sessionClass {
|
|
|
1548
1560
|
gzip: true
|
|
1549
1561
|
}
|
|
1550
1562
|
var response = await this.httpGet(reqObj)
|
|
1551
|
-
if ( this.isValidJson(response) ) {
|
|
1563
|
+
if ( response && this.isValidJson(response) ) {
|
|
1552
1564
|
this.debuglog('getStreamURL response : ' + response)
|
|
1553
1565
|
let obj = JSON.parse(response)
|
|
1554
1566
|
if ( obj.errors && (obj.errors[0] == 'blackout') ) {
|
|
@@ -1655,7 +1667,7 @@ class sessionClass {
|
|
|
1655
1667
|
gzip: true
|
|
1656
1668
|
}
|
|
1657
1669
|
var response = await this.httpGet(reqObj)
|
|
1658
|
-
if ( this.isValidJson(response) ) {
|
|
1670
|
+
if ( response && this.isValidJson(response) ) {
|
|
1659
1671
|
this.debuglog('getDeviceId response : ' + response)
|
|
1660
1672
|
let obj = JSON.parse(response)
|
|
1661
1673
|
this.debuglog('getDeviceId : ' + obj.device.id)
|
|
@@ -1865,7 +1877,7 @@ class sessionClass {
|
|
|
1865
1877
|
|
|
1866
1878
|
let cache_data
|
|
1867
1879
|
let cache_name = gameDate
|
|
1868
|
-
let cache_file = path.join(CACHE_DIRECTORY, gameDate+'.json')
|
|
1880
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, gameDate+'.json')
|
|
1869
1881
|
let currentDate = new Date()
|
|
1870
1882
|
cache_data = await this.getDayData(gameDate)
|
|
1871
1883
|
|
|
@@ -1985,7 +1997,7 @@ class sessionClass {
|
|
|
1985
1997
|
|
|
1986
1998
|
let cache_data
|
|
1987
1999
|
let cache_name = 'h' + gamePk
|
|
1988
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name+'.json')
|
|
2000
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name+'.json')
|
|
1989
2001
|
let currentDate = new Date()
|
|
1990
2002
|
if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.highlights || !this.cache.highlights[cache_name] || !this.cache.highlights[cache_name].highlightsCacheExpiry || (currentDate > new Date(this.cache.highlights[cache_name].highlightsCacheExpiry)) ) {
|
|
1991
2003
|
let reqObj = {
|
|
@@ -1998,8 +2010,8 @@ class sessionClass {
|
|
|
1998
2010
|
},
|
|
1999
2011
|
gzip: true
|
|
2000
2012
|
}
|
|
2001
|
-
var response = await this.httpGet(reqObj)
|
|
2002
|
-
if ( this.isValidJson(response) ) {
|
|
2013
|
+
var response = await this.httpGet(reqObj, false)
|
|
2014
|
+
if ( response && this.isValidJson(response) ) {
|
|
2003
2015
|
//this.debuglog(response)
|
|
2004
2016
|
cache_data = JSON.parse(response)
|
|
2005
2017
|
this.save_json_cache_file(cache_name, cache_data)
|
|
@@ -2081,7 +2093,7 @@ class sessionClass {
|
|
|
2081
2093
|
} else {
|
|
2082
2094
|
this.debuglog('getDayData for date ' + dateString)
|
|
2083
2095
|
}
|
|
2084
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name+'.json')
|
|
2096
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name+'.json')
|
|
2085
2097
|
let currentDate = new Date()
|
|
2086
2098
|
if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.dates || !this.cache.dates[cache_name] || !this.cache.dates[cache_name].dateCacheExpiry || (currentDate > new Date(this.cache.dates[cache_name].dateCacheExpiry)) ) {
|
|
2087
2099
|
let reqObj = {
|
|
@@ -2094,8 +2106,8 @@ class sessionClass {
|
|
|
2094
2106
|
},
|
|
2095
2107
|
gzip: true
|
|
2096
2108
|
}
|
|
2097
|
-
var response = await this.httpGet(reqObj)
|
|
2098
|
-
if ( this.isValidJson(response) ) {
|
|
2109
|
+
var response = await this.httpGet(reqObj, false)
|
|
2110
|
+
if ( response && this.isValidJson(response) ) {
|
|
2099
2111
|
//this.debuglog(response)
|
|
2100
2112
|
cache_data = JSON.parse(response)
|
|
2101
2113
|
this.save_json_cache_file(cache_name, cache_data)
|
|
@@ -2164,7 +2176,7 @@ class sessionClass {
|
|
|
2164
2176
|
|
|
2165
2177
|
let cache_data
|
|
2166
2178
|
let cache_name = 'week'
|
|
2167
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name + '.json')
|
|
2179
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name + '.json')
|
|
2168
2180
|
let currentDate = new Date()
|
|
2169
2181
|
if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.weekCacheExpiry || (currentDate > new Date(this.cache.weekCacheExpiry)) ) {
|
|
2170
2182
|
let startDate = this.liveDate(utcHours)
|
|
@@ -2181,8 +2193,8 @@ class sessionClass {
|
|
|
2181
2193
|
},
|
|
2182
2194
|
gzip: true
|
|
2183
2195
|
}
|
|
2184
|
-
var response = await this.httpGet(reqObj)
|
|
2185
|
-
if ( this.isValidJson(response) ) {
|
|
2196
|
+
var response = await this.httpGet(reqObj, false)
|
|
2197
|
+
if ( response && this.isValidJson(response) ) {
|
|
2186
2198
|
//this.debuglog(response)
|
|
2187
2199
|
cache_data = JSON.parse(response)
|
|
2188
2200
|
this.save_json_cache_file(cache_name, cache_data)
|
|
@@ -2597,7 +2609,7 @@ class sessionClass {
|
|
|
2597
2609
|
// Get image from cache or request
|
|
2598
2610
|
async getImage(teamId) {
|
|
2599
2611
|
this.debuglog('getImage ' + teamId)
|
|
2600
|
-
let imagePath = path.join(CACHE_DIRECTORY, teamId + '.svg')
|
|
2612
|
+
let imagePath = path.join(this.CACHE_DIRECTORY, teamId + '.svg')
|
|
2601
2613
|
if ( fs.existsSync(imagePath) ) {
|
|
2602
2614
|
this.debuglog('using cached image for ' + teamId)
|
|
2603
2615
|
return fs.readFileSync(imagePath)
|
|
@@ -2614,7 +2626,7 @@ class sessionClass {
|
|
|
2614
2626
|
'origin': 'https://www.mlb.com'
|
|
2615
2627
|
}
|
|
2616
2628
|
}
|
|
2617
|
-
var response = await this.httpGet(reqObj)
|
|
2629
|
+
var response = await this.httpGet(reqObj, false)
|
|
2618
2630
|
if ( response ) {
|
|
2619
2631
|
this.debuglog('getImage response : ' + response)
|
|
2620
2632
|
fs.writeFileSync(imagePath, response)
|
|
@@ -2641,7 +2653,7 @@ class sessionClass {
|
|
|
2641
2653
|
} else {
|
|
2642
2654
|
this.debuglog('getAiringsData for content ' + contentId)
|
|
2643
2655
|
}
|
|
2644
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name+'.json')
|
|
2656
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name+'.json')
|
|
2645
2657
|
let currentDate = new Date()
|
|
2646
2658
|
if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.airings || !this.cache.airings[cache_name] || !this.cache.airings[cache_name].airingsCacheExpiry || (currentDate > new Date(this.cache.airings[cache_name].airingsCacheExpiry)) ) {
|
|
2647
2659
|
let reqObj = {
|
|
@@ -2659,7 +2671,7 @@ class sessionClass {
|
|
|
2659
2671
|
gzip: true
|
|
2660
2672
|
}
|
|
2661
2673
|
var response = await this.httpGet(reqObj)
|
|
2662
|
-
if ( this.isValidJson(response) ) {
|
|
2674
|
+
if ( response && this.isValidJson(response) ) {
|
|
2663
2675
|
this.debuglog(response)
|
|
2664
2676
|
cache_data = JSON.parse(response)
|
|
2665
2677
|
this.save_json_cache_file(cache_name, cache_data)
|
|
@@ -2710,7 +2722,7 @@ class sessionClass {
|
|
|
2710
2722
|
|
|
2711
2723
|
let cache_data
|
|
2712
2724
|
let cache_name = 'g' + gamePk
|
|
2713
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name+'.json')
|
|
2725
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name+'.json')
|
|
2714
2726
|
let currentDate = new Date()
|
|
2715
2727
|
if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.gameday || !this.cache.gameday[cache_name] || !this.cache.gameday[cache_name].gamedayCacheExpiry || (currentDate > new Date(this.cache.gameday[cache_name].gamedayCacheExpiry)) ) {
|
|
2716
2728
|
let reqObj = {
|
|
@@ -2723,8 +2735,8 @@ class sessionClass {
|
|
|
2723
2735
|
},
|
|
2724
2736
|
gzip: true
|
|
2725
2737
|
}
|
|
2726
|
-
var response = await this.httpGet(reqObj)
|
|
2727
|
-
if ( this.isValidJson(response) ) {
|
|
2738
|
+
var response = await this.httpGet(reqObj, false)
|
|
2739
|
+
if ( response && this.isValidJson(response) ) {
|
|
2728
2740
|
this.debuglog(response)
|
|
2729
2741
|
cache_data = JSON.parse(response)
|
|
2730
2742
|
this.save_json_cache_file(cache_name, cache_data)
|
|
@@ -2910,6 +2922,19 @@ class sessionClass {
|
|
|
2910
2922
|
continue
|
|
2911
2923
|
} else {
|
|
2912
2924
|
let break_end = ((new Date(cache_data.liveData.plays.allPlays[i].playEvents[action_index].startTime) - broadcast_start_timestamp) / 1000) + EVENT_START_PADDING
|
|
2925
|
+
|
|
2926
|
+
// attempt to fix erroneous timestamps, like NYY-SEA 2022-08-09, bottom 11
|
|
2927
|
+
if ( break_end < break_start ) {
|
|
2928
|
+
this.debuglog('getSkipMarkers adjusting break start')
|
|
2929
|
+
break_start = break_end - 10
|
|
2930
|
+
|
|
2931
|
+
let prev_break = skip_markers.length-1
|
|
2932
|
+
if ( (prev_break > 0) && (break_start < skip_markers[prev_break].break_end) && (skip_markers[prev_break].break_start < (skip_markers[prev_break].break_end - 40)) ) {
|
|
2933
|
+
this.debuglog('getSkipMarkers adjusting previous break end')
|
|
2934
|
+
skip_markers[prev_break].break_end = skip_markers[prev_break].break_start + 30
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2913
2938
|
// if the break duration should be greater than than our specified minimum
|
|
2914
2939
|
// and if skip type is not 1 (inning breaks) or the inning has changed
|
|
2915
2940
|
// then we'll add the skip marker
|
|
@@ -2977,7 +3002,7 @@ class sessionClass {
|
|
|
2977
3002
|
},
|
|
2978
3003
|
gzip: true
|
|
2979
3004
|
}
|
|
2980
|
-
var response = await this.httpGet(reqObj)
|
|
3005
|
+
var response = await this.httpGet(reqObj, false)
|
|
2981
3006
|
if ( response ) {
|
|
2982
3007
|
// disabled because it's very big!
|
|
2983
3008
|
//this.debuglog(response)
|
|
@@ -3089,11 +3114,12 @@ class sessionClass {
|
|
|
3089
3114
|
|
|
3090
3115
|
let cache_data
|
|
3091
3116
|
let cache_name = 'events'
|
|
3092
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name + '.json')
|
|
3117
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name + '.json')
|
|
3093
3118
|
let currentDate = new Date()
|
|
3094
3119
|
if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.eventURLCacheExpiry || (currentDate > new Date(this.cache.eventURLCacheExpiry)) ) {
|
|
3095
3120
|
let reqObj = {
|
|
3096
|
-
url: 'https://dapi.cms.mlbinfra.com/v2/content/en-us/sel-mlbtv-featured-svod-video-list',
|
|
3121
|
+
//url: 'https://dapi.cms.mlbinfra.com/v2/content/en-us/sel-mlbtv-featured-svod-video-list',
|
|
3122
|
+
url: 'https://dapi.mlbinfra.com/v2/content/en-us/vsmcontents/mlb-tv-welcome-center-big-inning-show',
|
|
3097
3123
|
headers: {
|
|
3098
3124
|
'User-Agent': USER_AGENT,
|
|
3099
3125
|
'Origin': 'https://www.mlb.com',
|
|
@@ -3103,8 +3129,8 @@ class sessionClass {
|
|
|
3103
3129
|
},
|
|
3104
3130
|
gzip: true
|
|
3105
3131
|
}
|
|
3106
|
-
var response = await this.httpGet(reqObj)
|
|
3107
|
-
if ( this.isValidJson(response) ) {
|
|
3132
|
+
var response = await this.httpGet(reqObj, false)
|
|
3133
|
+
if ( response && this.isValidJson(response) ) {
|
|
3108
3134
|
this.debuglog(response)
|
|
3109
3135
|
cache_data = JSON.parse(response)
|
|
3110
3136
|
this.save_json_cache_file(cache_name, cache_data)
|
|
@@ -3140,19 +3166,26 @@ class sessionClass {
|
|
|
3140
3166
|
|
|
3141
3167
|
let cache_data = await this.getEventData()
|
|
3142
3168
|
|
|
3169
|
+
let eventList
|
|
3143
3170
|
if ( cache_data && cache_data.items ) {
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3171
|
+
eventList = cache_data.items
|
|
3172
|
+
} else if ( cache_data && cache_data.references && cache_data.references.video ) {
|
|
3173
|
+
eventList = cache_data.references.video
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
if ( eventList ) {
|
|
3177
|
+
for (var i=0; i<eventList.length; i++) {
|
|
3178
|
+
if ( eventList[i].fields && eventList[i].fields.blurb && eventList[i].fields.url ) {
|
|
3179
|
+
if ( !eventList[i].fields.blurb.startsWith('LIVE') ) {
|
|
3147
3180
|
break
|
|
3148
3181
|
} else {
|
|
3149
|
-
if (
|
|
3150
|
-
if ( (eventName == 'BIGINNING') &&
|
|
3182
|
+
if ( eventList[i].title ) {
|
|
3183
|
+
if ( (eventName == 'BIGINNING') && eventList[i].title.startsWith('LIVE') && eventList[i].title.includes('Big Inning') ) {
|
|
3151
3184
|
this.debuglog('active big inning url')
|
|
3152
|
-
return
|
|
3153
|
-
} else if (
|
|
3185
|
+
return eventList[i].fields.url
|
|
3186
|
+
} else if ( eventList[i].title.toUpperCase().endsWith(' VS. ' + eventName) ) {
|
|
3154
3187
|
this.debuglog('active ' + eventName + ' url')
|
|
3155
|
-
return
|
|
3188
|
+
return eventList[i].fields.url
|
|
3156
3189
|
}
|
|
3157
3190
|
}
|
|
3158
3191
|
}
|
|
@@ -3190,7 +3223,7 @@ class sessionClass {
|
|
|
3190
3223
|
gzip: true
|
|
3191
3224
|
}
|
|
3192
3225
|
var response = await this.httpGet(reqObj)
|
|
3193
|
-
if ( this.isValidJson(response) ) {
|
|
3226
|
+
if ( response && this.isValidJson(response) ) {
|
|
3194
3227
|
this.debuglog('getEventStreamURL response : ' + response)
|
|
3195
3228
|
let obj = JSON.parse(response)
|
|
3196
3229
|
if ( obj.success && (obj.success == true) ) {
|
|
@@ -3227,8 +3260,8 @@ class sessionClass {
|
|
|
3227
3260
|
'Referer': 'https://www.mlb.com/'
|
|
3228
3261
|
}
|
|
3229
3262
|
}
|
|
3230
|
-
var response = await this.httpGet(reqObj)
|
|
3231
|
-
if ( this.isValidJson(response) ) {
|
|
3263
|
+
var response = await this.httpGet(reqObj, false)
|
|
3264
|
+
if ( response && this.isValidJson(response) ) {
|
|
3232
3265
|
this.debuglog('getBlackoutTeams response : ' + response)
|
|
3233
3266
|
let obj = JSON.parse(response)
|
|
3234
3267
|
if ( obj.teams ) {
|
|
@@ -3380,7 +3413,7 @@ class sessionClass {
|
|
|
3380
3413
|
try {
|
|
3381
3414
|
let cache_data
|
|
3382
3415
|
let cache_name = 'gamechanger'
|
|
3383
|
-
let cache_file = path.join(CACHE_DIRECTORY, cache_name + '.json')
|
|
3416
|
+
let cache_file = path.join(this.CACHE_DIRECTORY, cache_name + '.json')
|
|
3384
3417
|
let currentDate = new Date()
|
|
3385
3418
|
if ( !this.temp_cache.gamechanger.cache_data || !this.temp_cache.gamechangerCacheExpiry || (currentDate > new Date(this.temp_cache.gamechangerCacheExpiry)) ) {
|
|
3386
3419
|
this.debuglog(game_changer_title + 'fetching new gamechanger data')
|
|
@@ -3398,8 +3431,8 @@ class sessionClass {
|
|
|
3398
3431
|
},
|
|
3399
3432
|
gzip: true
|
|
3400
3433
|
}
|
|
3401
|
-
var response = await this.httpGet(reqObj)
|
|
3402
|
-
if ( this.isValidJson(response) ) {
|
|
3434
|
+
var response = await this.httpGet(reqObj, false)
|
|
3435
|
+
if ( response && this.isValidJson(response) ) {
|
|
3403
3436
|
this.debuglog(game_changer_title + 'valid json response')
|
|
3404
3437
|
this.debuglog(response)
|
|
3405
3438
|
this.temp_cache.gamechanger.cache_data = JSON.parse(response)
|