mlbserver 2026.3.15 → 2026.3.27-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/Dockerfile +40 -5
- package/index.js +22 -9
- package/package.json +2 -1
- package/session.js +168 -53
package/Dockerfile
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
# --- Build Stage ---
|
|
2
|
+
FROM node:18-alpine AS build
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
# Set environment variable to skip the automatic Chromium download by Puppeteer
|
|
5
|
+
ENV PUPPETEER_SKIP_DOWNLOAD=true
|
|
6
|
+
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
|
7
|
+
|
|
8
|
+
# Install system-level dependencies for Chromium on Alpine
|
|
9
|
+
RUN apk update && apk add --no-cache \
|
|
10
|
+
tzdata \
|
|
11
|
+
udev \
|
|
12
|
+
ttf-freefont \
|
|
13
|
+
chromium \
|
|
14
|
+
nss \
|
|
15
|
+
freetype \
|
|
16
|
+
harfbuzz \
|
|
17
|
+
ca-certificates
|
|
4
18
|
|
|
5
19
|
# Create app directory
|
|
6
20
|
WORKDIR /mlbserver
|
|
7
21
|
|
|
8
|
-
# Add data directory
|
|
9
|
-
VOLUME /mlbserver/data_directory
|
|
10
|
-
|
|
11
22
|
# Install app dependencies
|
|
12
23
|
# A wildcard is used to ensure both package.json AND package-lock.json are copied
|
|
13
24
|
# where available (npm@5+)
|
|
@@ -20,5 +31,29 @@ RUN npm install
|
|
|
20
31
|
# Bundle app source
|
|
21
32
|
COPY . .
|
|
22
33
|
|
|
34
|
+
# --- Runtime Stage ---
|
|
35
|
+
FROM node:20-alpine AS runtime
|
|
36
|
+
|
|
37
|
+
# Install only the necessary runtime dependencies again
|
|
38
|
+
RUN apk add --no-cache \
|
|
39
|
+
tzdata \
|
|
40
|
+
udev \
|
|
41
|
+
ttf-freefont \
|
|
42
|
+
chromium \
|
|
43
|
+
nss \
|
|
44
|
+
freetype \
|
|
45
|
+
harfbuzz \
|
|
46
|
+
ca-certificates
|
|
47
|
+
|
|
48
|
+
# Set the executable path for Puppeteer
|
|
49
|
+
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
|
50
|
+
|
|
51
|
+
WORKDIR /mlbserver
|
|
52
|
+
# Copy built application from the build stage
|
|
53
|
+
COPY --from=build /mlbserver .
|
|
54
|
+
|
|
55
|
+
# Add data directory
|
|
56
|
+
VOLUME /mlbserver/data_directory
|
|
57
|
+
|
|
23
58
|
EXPOSE 9999 10000
|
|
24
59
|
CMD [ "node", "index.js", "--env", "--port", "9999", "--multiview_port", "10000", "--data_directory", "/mlbserver/data_directory" ]
|
package/index.js
CHANGED
|
@@ -431,7 +431,7 @@ var getKey = function(url, headers, cb) {
|
|
|
431
431
|
requestRetry(url, headers, function(err, response) {
|
|
432
432
|
if (err) return cb(err)
|
|
433
433
|
let key = response.body
|
|
434
|
-
session.debuglog('key returned ' + key)
|
|
434
|
+
session.debuglog('key returned ' + Buffer.from(key, 'binary').toString('base64'))
|
|
435
435
|
session.temp_cache.prevKeys[url] = key
|
|
436
436
|
cb(null, key)
|
|
437
437
|
})
|
|
@@ -1262,15 +1262,28 @@ app.get('/gamechangerplaylist.m3u8', async function(req, res) {
|
|
|
1262
1262
|
let new_segments_complete = false
|
|
1263
1263
|
let segment_count = 0
|
|
1264
1264
|
for (var i=(body.length-1); i>=0; i--) {
|
|
1265
|
-
if ( body[i].startsWith('#
|
|
1266
|
-
let
|
|
1267
|
-
|
|
1268
|
-
|
|
1265
|
+
if ( body[i].startsWith('#EXT-X-KEY') ) {
|
|
1266
|
+
let key = url.resolve(u, body[i].match('URI="([^"]+)"')[1])
|
|
1267
|
+
let iv = body[i].match('IV=0x(.*)$')[1]
|
|
1268
|
+
let ts
|
|
1269
|
+
let extinf
|
|
1270
|
+
for (var j=1; j<=4; j++) {
|
|
1271
|
+
if ( body[i+j] ) {
|
|
1272
|
+
if ( !extinf && body[i+j].startsWith('#EXTINF') ) {
|
|
1273
|
+
extinf = body[i+j]
|
|
1274
|
+
} else if ( !ts && !body[i+j].startsWith('#') ) {
|
|
1275
|
+
ts = url.resolve(u, body[i+j])
|
|
1276
|
+
}
|
|
1277
|
+
if ( extinf && ts ) break;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
if ( key && iv && extinf && ts && !new_segments_complete ) {
|
|
1281
|
+
session.debuglog(game_changer_title + 'found segment ' + ts)
|
|
1269
1282
|
if ( discontinuity ) {
|
|
1270
1283
|
session.debuglog(game_changer_title + 'only getting newest segment after stream change')
|
|
1271
|
-
new_segments.unshift({'extinf':
|
|
1284
|
+
new_segments.unshift({'key':key, 'iv':iv, 'extinf':extinf, 'ts':ts, 'streamURLToken':streamURLToken})
|
|
1272
1285
|
new_segments_complete = true
|
|
1273
|
-
} else if ( !discontinuity && (session.temp_cache.gamechanger[id].segments.length > 0) && (
|
|
1286
|
+
} else if ( !discontinuity && (session.temp_cache.gamechanger[id].segments.length > 0) && (ts == session.temp_cache.gamechanger[id].segments[session.temp_cache.gamechanger[id].segments.length-1].ts) ) {
|
|
1274
1287
|
session.debuglog(game_changer_title + 'found previous last segment')
|
|
1275
1288
|
new_segments_complete = true
|
|
1276
1289
|
} else if ( segment_count == GAMECHANGER_LIST_SIZE ) {
|
|
@@ -1281,7 +1294,7 @@ app.get('/gamechangerplaylist.m3u8', async function(req, res) {
|
|
|
1281
1294
|
}
|
|
1282
1295
|
new_segments_complete = true
|
|
1283
1296
|
} else {
|
|
1284
|
-
new_segments.unshift({'extinf':
|
|
1297
|
+
new_segments.unshift({'key':key, 'iv':iv, 'extinf':extinf, 'ts':ts, 'streamURLToken':streamURLToken})
|
|
1285
1298
|
}
|
|
1286
1299
|
}
|
|
1287
1300
|
segment_count++
|
|
@@ -1314,7 +1327,7 @@ app.get('/gamechangerplaylist.m3u8', async function(req, res) {
|
|
|
1314
1327
|
if ( session.temp_cache.gamechanger[id].segments[i].discontinuity ) {
|
|
1315
1328
|
session.temp_cache.gamechanger[id].playlist[resolution] += '#EXT-X-DISCONTINUITY' + '\n'
|
|
1316
1329
|
}
|
|
1317
|
-
session.temp_cache.gamechanger[id].playlist[resolution] += session.temp_cache.gamechanger[id].segments[i].extinf + '\n' + http_root + '/segment.ts?url=' + encodeURIComponent(session.temp_cache.gamechanger[id].segments[i].ts) + '&streamURLToken='+encodeURIComponent(session.temp_cache.gamechanger[id].segments[i].streamURLToken) + content_protect + '\n'
|
|
1330
|
+
session.temp_cache.gamechanger[id].playlist[resolution] += session.temp_cache.gamechanger[id].segments[i].extinf + '\n' + http_root + '/segment.ts?url=' + encodeURIComponent(session.temp_cache.gamechanger[id].segments[i].ts) + '&streamURLToken='+encodeURIComponent(session.temp_cache.gamechanger[id].segments[i].streamURLToken) + '&key='+encodeURIComponent(session.temp_cache.gamechanger[id].segments[i].key) + '&iv='+encodeURIComponent(session.temp_cache.gamechanger[id].segments[i].iv) + content_protect + '\n'
|
|
1318
1331
|
}
|
|
1319
1332
|
|
|
1320
1333
|
session.debuglog(game_changer_title + 'playlist ' + session.temp_cache.gamechanger[id].playlist[resolution])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mlbserver",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.27-2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"http": "0.0.1-security",
|
|
14
14
|
"http-attach": "^1.0.0",
|
|
15
15
|
"minimist": "^1.2.8",
|
|
16
|
+
"puppeteer": "^24.40.0",
|
|
16
17
|
"readline-sync": "^1.4.10",
|
|
17
18
|
"request": "^2.88.2",
|
|
18
19
|
"request-promise": "^4.2.6",
|
package/session.js
CHANGED
|
@@ -8,6 +8,7 @@ const path = require('path')
|
|
|
8
8
|
const readlineSync = require('readline-sync')
|
|
9
9
|
const FileCookieStore = require('tough-cookie-filestore')
|
|
10
10
|
const parseString = require('xml2js').parseString
|
|
11
|
+
const puppeteer = require('puppeteer')
|
|
11
12
|
|
|
12
13
|
const MULTIVIEW_DIRECTORY_NAME = 'multiview'
|
|
13
14
|
|
|
@@ -28,7 +29,7 @@ const LIDOM_TEAM_IDS = { 'AGU': '667', 'TOR': '668', 'EST': '669', 'GIG': '670',
|
|
|
28
29
|
|
|
29
30
|
const LMP_TEAM_IDS = { 'MXC': '673', 'JAL': '674', 'MOC': '675', 'HER': '677', 'CUL': '678', 'MAZ': '679', 'OBR': '680', 'GSV': '5482', 'NAY': '6483', 'TBC': '6484' }
|
|
30
31
|
|
|
31
|
-
const AFFILIATE_TEAM_IDS = {
|
|
32
|
+
const AFFILIATE_TEAM_IDS = {"ATH":"237,400,499,524","ATL":"431,432,478,6325","AZ":"419,516,2310,5368","BAL":"418,493,548,568","BOS":"414,428,533,546","CHC":"451,521,550,553","CIN":"416,450,459,498","CLE":"402,437,445,481","COL":"259,342,486,538","CWS":"247,487,494,580","DET":"106,512,570,582","HOU":"482,573,3712,5434","KC":"541,565,1350,3705","LAA":"460,526,559,561","LAD":"238,260,456,6482","MIA":"479,554,564,4124","MIL":"249,556,572,5015","MIN":"492,509,1960,3898","NYM":"453,505,507,552","NYY":"531,537,587,1956","PHI":"427,522,566,1410","PIT":"452,477,484,3390","SD":"103,510,584,4904","SEA":"401,403,529,574","SF":"105,461,476,3410","STL":"235,279,440,443","TB":"233,234,421,2498","TEX":"102,448,540,6324","TOR":"422,424,435,463","WSH":"426,436,534,547"}
|
|
32
33
|
|
|
33
34
|
// First is default level, last should be All (also used as default org)
|
|
34
35
|
const LEVELS = { 'MLB': '1', 'AAA': '11', 'AA': '12', 'A+': '13', 'A': '14', 'WINTER': '17', 'All': '1,11,12,13,14,17' }
|
|
@@ -864,6 +865,8 @@ class sessionClass {
|
|
|
864
865
|
constructor(argv = {}) {
|
|
865
866
|
this.debug = argv.debug
|
|
866
867
|
|
|
868
|
+
this.executablePath = argv.PUPPETEER_EXECUTABLE_PATH
|
|
869
|
+
|
|
867
870
|
let dirname = __dirname
|
|
868
871
|
if ( argv.data_directory ) {
|
|
869
872
|
dirname = argv.data_directory
|
|
@@ -2368,8 +2371,8 @@ class sessionClass {
|
|
|
2368
2371
|
stream = server + '/stream.m3u8?event=' + encodeURIComponent(cache_data.dates[i].games[j].teams['home'].team.shortName.toUpperCase())
|
|
2369
2372
|
}
|
|
2370
2373
|
stream += '&league_id=' + league_id
|
|
2374
|
+
stream += '&mediaType=' + streamMediaType
|
|
2371
2375
|
}
|
|
2372
|
-
stream += '&mediaType=' + streamMediaType
|
|
2373
2376
|
stream += '&level=' + encodeURIComponent(this.getLevelNameFromSportId(sportId))
|
|
2374
2377
|
stream += '&resolution=' + resolution
|
|
2375
2378
|
if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
|
|
@@ -3319,6 +3322,7 @@ class sessionClass {
|
|
|
3319
3322
|
async getSkipMarkers(gamePk, skip_type, start_inning, start_inning_half, streamURL, streamURLToken, skip_adjust, broadcast_start_timestamp=false) {
|
|
3320
3323
|
try {
|
|
3321
3324
|
this.debuglog('getSkipMarkers')
|
|
3325
|
+
let variantPlaylist;
|
|
3322
3326
|
|
|
3323
3327
|
if ( skip_adjust != 0 ) this.log('manual adjustment of ' + skip_adjust + ' seconds being applied')
|
|
3324
3328
|
|
|
@@ -3342,7 +3346,7 @@ class sessionClass {
|
|
|
3342
3346
|
|
|
3343
3347
|
// Get the broadcast start time first, if necessary -- event times will be relative to this
|
|
3344
3348
|
if ( !broadcast_start_timestamp ) {
|
|
3345
|
-
|
|
3349
|
+
variantPlaylist = await this.getVariantPlaylist(streamURL, streamURLToken)
|
|
3346
3350
|
broadcast_start_timestamp = await this.getBroadcastStart(variantPlaylist)
|
|
3347
3351
|
}
|
|
3348
3352
|
|
|
@@ -3488,6 +3492,10 @@ class sessionClass {
|
|
|
3488
3492
|
// if skipping commercials, look at the variant playlist to detect insertions
|
|
3489
3493
|
if ( skip_type == 4 ) {
|
|
3490
3494
|
this.debuglog('detecting commercial breaks')
|
|
3495
|
+
if (!variantPlaylist) {
|
|
3496
|
+
this.debuglog('variantPlaylist missing, fetching...')
|
|
3497
|
+
variantPlaylist = await this.getVariantPlaylist(streamURL, streamURLToken)
|
|
3498
|
+
}
|
|
3491
3499
|
let body = variantPlaylist
|
|
3492
3500
|
let break_active = false
|
|
3493
3501
|
let break_end = 0
|
|
@@ -3538,62 +3546,118 @@ class sessionClass {
|
|
|
3538
3546
|
let currentDate = new Date()
|
|
3539
3547
|
if ( !this.cache || !this.cache.bigInningScheduleCacheExpiry || (currentDate > new Date(this.cache.bigInningScheduleCacheExpiry)) ) {
|
|
3540
3548
|
if ( !this.cache.bigInningSchedule ) this.cache.bigInningSchedule = {}
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
'
|
|
3547
|
-
'
|
|
3548
|
-
'
|
|
3549
|
-
'
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3549
|
+
|
|
3550
|
+
const browser = await puppeteer.launch({
|
|
3551
|
+
headless: 'new',
|
|
3552
|
+
executablePath: this.executablePath,
|
|
3553
|
+
args: [
|
|
3554
|
+
'--no-sandbox',
|
|
3555
|
+
'--disable-gpu',
|
|
3556
|
+
'--disable-setuid-sandbox',
|
|
3557
|
+
'--disable-dev-shm-usage'
|
|
3558
|
+
],
|
|
3559
|
+
})
|
|
3560
|
+
const page = await browser.newPage()
|
|
3561
|
+
await page.setUserAgent(USER_AGENT)
|
|
3562
|
+
await page.goto('https://support.mlb.com/s/article/What-Is-MLB-Big-Inning?language=en_US', { waitUntil: 'networkidle0' })
|
|
3563
|
+
const response = await page.content()
|
|
3564
|
+
await browser.close()
|
|
3565
|
+
|
|
3566
|
+
// break HTML into array based on table rows
|
|
3567
|
+
var rows = response.split('<tr ')
|
|
3568
|
+
// start iterating at 2 (after header row)
|
|
3569
|
+
for (var i=2; i<rows.length; i++) {
|
|
3570
|
+
// split HTML row into array with columns
|
|
3571
|
+
let cols = rows[i].split('<td ')
|
|
3572
|
+
|
|
3573
|
+
// define some variables that persist for each row
|
|
3574
|
+
let parts
|
|
3575
|
+
let year
|
|
3576
|
+
let month
|
|
3577
|
+
let day
|
|
3578
|
+
let this_datestring
|
|
3579
|
+
let add_date = 0
|
|
3580
|
+
let d
|
|
3581
|
+
|
|
3582
|
+
// start iterating at 2 (after DOW column)
|
|
3583
|
+
for (var j=2; j<cols.length; j++) {
|
|
3584
|
+
// split on brackets to get column text at resulting array index 0
|
|
3585
|
+
let col = cols[j].split('>')[1].split('<')
|
|
3586
|
+
switch(j){
|
|
3587
|
+
// first column is date
|
|
3588
|
+
case 2:
|
|
3589
|
+
// split date into array
|
|
3590
|
+
// old date format (January 1, 1970) (disabled)
|
|
3591
|
+
/*parts = col[0].split(' ')
|
|
3592
|
+
year = parts[2]
|
|
3593
|
+
// get month index, zero-based
|
|
3594
|
+
month = new Date(Date.parse(parts[0] +" 1, 2021")).getMonth()
|
|
3595
|
+
day = parts[1].substring(0,parts[1].length-3)*/
|
|
3596
|
+
// new date format (01/01/70)
|
|
3597
|
+
parts = col[0].split('/')
|
|
3598
|
+
year = parts[2]
|
|
3599
|
+
if ( year.length == 2 ) {
|
|
3600
|
+
year = '20' + parts[2]
|
|
3601
|
+
}
|
|
3602
|
+
// get month index, zero-based
|
|
3603
|
+
month = parseInt(parts[0]) - 1
|
|
3604
|
+
day = parts[1]
|
|
3605
|
+
this_datestring = new Date(year, month, day).toISOString().substring(0,10)
|
|
3606
|
+
this.cache.bigInningSchedule[this_datestring] = {}
|
|
3607
|
+
// increment month index (not zero-based)
|
|
3608
|
+
month += 1
|
|
3609
|
+
break
|
|
3610
|
+
// remaining columns are times
|
|
3611
|
+
default:
|
|
3612
|
+
let hour
|
|
3613
|
+
let minute = '00'
|
|
3614
|
+
let ampm
|
|
3615
|
+
// if time has colon, split into array on that to get hour and minute parts
|
|
3616
|
+
if ( col[0].indexOf(':') > 0 ) {
|
|
3617
|
+
parts = col[0].split(':')
|
|
3618
|
+
hour = parseInt(parts[0])
|
|
3619
|
+
minute = parts[1].substring(0,2)
|
|
3620
|
+
} else {
|
|
3621
|
+
hour = parseInt(col[0].substring(0,col[0].length-2))
|
|
3622
|
+
}
|
|
3623
|
+
ampm = col[0].substring(col[0].length-2,col[0].length)
|
|
3624
|
+
// convert hour to 24-hour format
|
|
3625
|
+
if ( (ampm == 'PM') || ((hour == 12) && (ampm == 'AM')) ) {
|
|
3626
|
+
hour += 12
|
|
3627
|
+
}
|
|
3628
|
+
// these times are EDT so add 4 for UTC
|
|
3629
|
+
hour += 4
|
|
3630
|
+
// if hour is beyond 23, note we will have to add 1 day
|
|
3631
|
+
if ( hour > 23 ) {
|
|
3632
|
+
add_date = 1
|
|
3633
|
+
hour -= 24
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
d = new Date(this_datestring + 'T' + hour.toString().padStart(2, '0') + ':' + minute.toString().padStart(2, '0') + ':00.000+00:00')
|
|
3637
|
+
d.setDate(d.getDate()+add_date)
|
|
3638
|
+
switch(j){
|
|
3639
|
+
// 3rd column is start time
|
|
3640
|
+
case 3:
|
|
3641
|
+
this.cache.bigInningSchedule[this_datestring].start = d
|
|
3642
|
+
break
|
|
3643
|
+
// 3rd column is end time
|
|
3644
|
+
case 4:
|
|
3645
|
+
this.cache.bigInningSchedule[this_datestring].end = d
|
|
3579
3646
|
break
|
|
3580
|
-
}
|
|
3581
3647
|
}
|
|
3582
|
-
|
|
3648
|
+
break
|
|
3583
3649
|
}
|
|
3584
3650
|
}
|
|
3585
|
-
|
|
3651
|
+
}
|
|
3652
|
+
this.debuglog(JSON.stringify(this.cache.bigInningSchedule))
|
|
3586
3653
|
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3654
|
+
// Default cache period is 1 day from now
|
|
3655
|
+
let oneDayFromNow = new Date()
|
|
3656
|
+
oneDayFromNow.setDate(oneDayFromNow.getDate()+1)
|
|
3657
|
+
let cacheExpiry = oneDayFromNow
|
|
3658
|
+
this.cache.bigInningScheduleCacheExpiry = cacheExpiry
|
|
3592
3659
|
|
|
3593
|
-
|
|
3594
|
-
} else {
|
|
3595
|
-
this.log('error : invalid response from url ' + reqObj.url)
|
|
3596
|
-
}
|
|
3660
|
+
this.save_cache_data()
|
|
3597
3661
|
} else {
|
|
3598
3662
|
this.debuglog('using cached big inning schedule')
|
|
3599
3663
|
}
|
|
@@ -4349,6 +4413,7 @@ class sessionClass {
|
|
|
4349
4413
|
if ( cache_data ) {
|
|
4350
4414
|
if ( cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
|
|
4351
4415
|
let team_data = this.temp_cache.gamechanger[id].streamFinderData.team_data
|
|
4416
|
+
let games_CLI = this.temp_cache.gamechanger[id].streamFinderData.games_CLI
|
|
4352
4417
|
|
|
4353
4418
|
var games = []
|
|
4354
4419
|
|
|
@@ -5615,6 +5680,56 @@ class sessionClass {
|
|
|
5615
5680
|
this.log('getComskipMarkers error : ' + e.message)
|
|
5616
5681
|
}
|
|
5617
5682
|
}
|
|
5683
|
+
|
|
5684
|
+
// generates AFFILIATE_TEAM_IDS, should be done each season
|
|
5685
|
+
async getAffiliates() {
|
|
5686
|
+
try {
|
|
5687
|
+
this.debuglog('getAffiliates')
|
|
5688
|
+
|
|
5689
|
+
let affiliates_data = {}
|
|
5690
|
+
let reqObj = {
|
|
5691
|
+
url: 'https://statsapi.mlb.com/api/v1/teams?sportIds=1,11,12,13,14&activeStatus=true&season=2026',
|
|
5692
|
+
headers: {
|
|
5693
|
+
'User-agent': USER_AGENT,
|
|
5694
|
+
'Origin': 'https://www.mlb.com',
|
|
5695
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
5696
|
+
'Content-type': 'application/json'
|
|
5697
|
+
},
|
|
5698
|
+
gzip: true
|
|
5699
|
+
}
|
|
5700
|
+
var response = await this.httpGet(reqObj, false)
|
|
5701
|
+
if ( response && this.isValidJson(response) ) {
|
|
5702
|
+
//this.debuglog(response)
|
|
5703
|
+
let teams_data = JSON.parse(response)
|
|
5704
|
+
|
|
5705
|
+
let parent_orgs = {}
|
|
5706
|
+
if ( teams_data && teams_data.teams ) {
|
|
5707
|
+
for (var i=0; i<teams_data.teams.length; i++) {
|
|
5708
|
+
if (teams_data.teams[i].sport.id == 1) {
|
|
5709
|
+
parent_orgs[teams_data.teams[i].id] = teams_data.teams[i].abbreviation
|
|
5710
|
+
affiliates_data[teams_data.teams[i].abbreviation] = []
|
|
5711
|
+
}
|
|
5712
|
+
}
|
|
5713
|
+
for (var i=0; i<teams_data.teams.length; i++) {
|
|
5714
|
+
if (teams_data.teams[i].sport.id != 1) {
|
|
5715
|
+
teams_data.teams[i].abbreviation
|
|
5716
|
+
affiliates_data[parent_orgs[teams_data.teams[i].parentOrgId]].push(teams_data.teams[i].id)
|
|
5717
|
+
affiliates_data[parent_orgs[teams_data.teams[i].parentOrgId]].sort((a, b) => a - b)
|
|
5718
|
+
}
|
|
5719
|
+
}
|
|
5720
|
+
for (const [key, value] of Object.entries(affiliates_data)) {
|
|
5721
|
+
affiliates_data[key] = value.join(',')
|
|
5722
|
+
}
|
|
5723
|
+
|
|
5724
|
+
console.log(JSON.stringify(this.sortObj(affiliates_data)))
|
|
5725
|
+
}
|
|
5726
|
+
} else {
|
|
5727
|
+
this.log('error : invalid json from url ' + reqObj.url)
|
|
5728
|
+
}
|
|
5729
|
+
} catch(e) {
|
|
5730
|
+
this.log('getAffiliates error : ' + e.message)
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5618
5733
|
}
|
|
5619
5734
|
|
|
5620
5735
|
module.exports = sessionClass
|