mlbserver 2025.3.29 → 2025.4.0-1.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/index.js +94 -26
- package/package.json +1 -1
- package/session.js +169 -102
package/index.js
CHANGED
|
@@ -44,7 +44,7 @@ const VALID_SCAN_MODES = [ 'off', 'on' ]
|
|
|
44
44
|
|
|
45
45
|
const SAMPLE_STREAM_URL = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'
|
|
46
46
|
|
|
47
|
-
const SECONDS_PER_SEGMENT =
|
|
47
|
+
const SECONDS_PER_SEGMENT = 4
|
|
48
48
|
|
|
49
49
|
// for favorites: text, then background, based on https://teamcolors.jim-nielsen.com/
|
|
50
50
|
const TEAM_COLORS = { 'ATH': ['003831', 'EFB21E'], 'ATL': ['13274F', 'CE1141'], 'AZ': ['E3D4AD', 'A71930'], 'BAL': ['000000', 'DF4601'], 'BOS': ['0D2B56', 'BD3039'], 'CHC': ['CC3433', '0E3386'], 'CWS': ['000000', 'C4CED4'], 'CIN': ['FFFFFF', 'C6011F'], 'CLE': ['002B5C', 'E31937'], 'COL': ['C4CED4', '333366'], 'DET': ['0C2C56', 'FFFFFF'], 'HOU': ['002D62', 'EB6E1F'], 'KC': ['C09A5B', '004687'], 'LAA': ['FFFFFF', 'BA0021'], 'LAD': ['FFFFFF', '005A9C'], 'MIA': ['0077C8', 'FF6600'], 'MIL': ['0A2351', 'B6922E'], 'MIN': ['D31145', '002B5C'], 'NYM': ['002D72', 'FF5910'], 'NYY': ['FFFFFF', '003087'], 'OAK': ['003831', 'EFB21E'], 'PHI': ['284898', 'E81828'], 'PIT': ['000000', 'FDB827'], 'STL': ['FEDB00', 'C41E3A'], 'SD': ['FEC325', '7F411C'], 'SF': ['000000', 'FD5A1E'], 'SEA': ['C4CED4', '005C5C'], 'TB': ['092C5C', '8FBCE6'], 'TEX': ['003278', 'C0111F'], 'TOR': ['FFFFFF', '134A8E'], 'WSH': ['AB0003', '11225B'] }
|
|
@@ -863,26 +863,31 @@ app.get('/playlist.m3u8', async function(req, res) {
|
|
|
863
863
|
})
|
|
864
864
|
.join('\n')+'\n'
|
|
865
865
|
|
|
866
|
+
let end_tag = '#EXT-X-ENDLIST'
|
|
866
867
|
if ( pad != VALID_PAD[0] ) {
|
|
867
868
|
let body_array = body.trim().split('\n')
|
|
868
|
-
let
|
|
869
|
-
if ( body_array[
|
|
869
|
+
let segment_index = body_array.length-1
|
|
870
|
+
if ( body_array[segment_index] == end_tag ) {
|
|
870
871
|
session.debuglog('padding archive stream with extra segments')
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
last_segment_index--
|
|
872
|
+
while ( body_array[segment_index].startsWith('#') ) {
|
|
873
|
+
segment_index--
|
|
874
874
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
let pad_lines = '#EXT-X-DISCONTINUITY' + '\n' + '#EXTINF:' + SECONDS_PER_SEGMENT + '\n' + last_segment + '\n'
|
|
878
|
-
session.debuglog(pad_lines)
|
|
875
|
+
let last_segment = body_array[segment_index]
|
|
876
|
+
body_array.pop()
|
|
879
877
|
for (i=0; i<pad; i++) {
|
|
880
|
-
|
|
878
|
+
body_array.push('#EXT-X-DISCONTINUITY')
|
|
879
|
+
body_array.push('#EXTINF:' + SECONDS_PER_SEGMENT)
|
|
880
|
+
body_array.push(last_segment)
|
|
881
881
|
}
|
|
882
|
-
|
|
882
|
+
body_array.push(end_tag)
|
|
883
|
+
body = body_array.join('\n')
|
|
884
|
+
}
|
|
885
|
+
} else if ( force_vod != VALID_FORCE_VOD[0] ) {
|
|
886
|
+
let body_array = body.trim().split('\n')
|
|
887
|
+
if ( body_array[body_array.length-1] != end_tag ) {
|
|
888
|
+
body += end_tag + '\n'
|
|
883
889
|
}
|
|
884
890
|
}
|
|
885
|
-
if ( force_vod != VALID_FORCE_VOD[0] ) body += '#EXT-X-ENDLIST' + '\n'
|
|
886
891
|
session.debuglog(body)
|
|
887
892
|
respond(response, res, Buffer.from(body))
|
|
888
893
|
})
|
|
@@ -1041,7 +1046,7 @@ app.get('/gamechanger.m3u8', async function(req, res) {
|
|
|
1041
1046
|
|
|
1042
1047
|
for ( gamechanger_resolution in GAMECHANGER_RESOLUTIONS ) {
|
|
1043
1048
|
if ( resolution == gamechanger_resolution ) {
|
|
1044
|
-
body += '#EXT-X-STREAM-INF:BANDWIDTH=' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].bandwidth + '000,RESOLUTION=' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].resolution + ',FRAME-RATE=' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].frame_rate + ',CODECS="mp4a.40.2,avc1.' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].codec + '",CLOSED-CAPTIONS="cc",AUDIO="aac"' + '\n' + '/gamechangerplaylist?id=' + id + '&resolution=' + gamechanger_resolution + includeTeams + excludeTeams + content_protect + '\n'
|
|
1049
|
+
body += '#EXT-X-STREAM-INF:BANDWIDTH=' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].bandwidth + '000,RESOLUTION=' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].resolution + ',FRAME-RATE=' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].frame_rate + ',CODECS="mp4a.40.2,avc1.' + GAMECHANGER_RESOLUTIONS[gamechanger_resolution].codec + '",CLOSED-CAPTIONS="cc",AUDIO="aac"' + '\n' + '/gamechangerplaylist.m3u8?id=' + id + '&resolution=' + gamechanger_resolution + includeTeams + excludeTeams + content_protect + '\n'
|
|
1045
1050
|
break
|
|
1046
1051
|
}
|
|
1047
1052
|
}
|
|
@@ -1055,10 +1060,10 @@ app.get('/gamechanger.m3u8', async function(req, res) {
|
|
|
1055
1060
|
|
|
1056
1061
|
|
|
1057
1062
|
// Listen for gamechanger playlist requests
|
|
1058
|
-
app.get('/gamechangerplaylist', async function(req, res) {
|
|
1063
|
+
app.get('/gamechangerplaylist.m3u8', async function(req, res) {
|
|
1059
1064
|
if ( ! (await protect(req, res)) ) return
|
|
1060
1065
|
|
|
1061
|
-
session.requestlog('gamechangerplaylist', req, true)
|
|
1066
|
+
session.requestlog('gamechangerplaylist.m3u8', req, true)
|
|
1062
1067
|
|
|
1063
1068
|
let gamechangerAccess = new Date()
|
|
1064
1069
|
|
|
@@ -1562,11 +1567,11 @@ app.get('/', async function(req, res) {
|
|
|
1562
1567
|
|
|
1563
1568
|
let currentDate = new Date()
|
|
1564
1569
|
|
|
1570
|
+
let entitlements = await session.getEntitlements()
|
|
1565
1571
|
// MLB Network live stream for eligible USA subscribers
|
|
1566
1572
|
try {
|
|
1567
|
-
let entitlements = await session.getEntitlements()
|
|
1568
1573
|
if ( entitlements.includes('MLBN') || entitlements.includes('EXECMLB') || entitlements.includes('MLBTVMLBNADOBEPASS') ) {
|
|
1569
|
-
body += '<tr><td><span class="tooltip">MLB Network<span class="tooltiptext">MLB Network live stream is now available in the USA for paid MLBTV subscribers or as a paid add-on, in addition to authenticated TV subscribers. <a href="https://
|
|
1574
|
+
body += '<tr><td><span class="tooltip">MLB Network<span class="tooltiptext">MLB Network live stream is now available in the USA for paid MLBTV subscribers or as a paid add-on, in addition to authenticated TV subscribers. <a href="https://support.mlb.com/s/article/MLB-Network-Streaming-FAQ">See here for more information</a>.</span></span></td><td>'
|
|
1570
1575
|
let querystring = '?event=MLBN'
|
|
1571
1576
|
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1572
1577
|
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
@@ -1589,6 +1594,58 @@ app.get('/', async function(req, res) {
|
|
|
1589
1594
|
session.debuglog('MLB Network detect error : ' + e.message)
|
|
1590
1595
|
}
|
|
1591
1596
|
|
|
1597
|
+
// SNLA live stream for entitled subscribers
|
|
1598
|
+
try {
|
|
1599
|
+
if ( entitlements.includes('SNLA_119') ) {
|
|
1600
|
+
body += '<tr><td><span class="tooltip">SportsNet LA<span class="tooltiptext">SNLA live stream for entitled subscribers. <a href="https://support.mlb.com/s/article/SNLA-Plus-Subscription-Packages">See here for more information</a>.</span></span></td><td>'
|
|
1601
|
+
let querystring = '?event=SNLA'
|
|
1602
|
+
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1603
|
+
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
1604
|
+
if ( startFrom != VALID_START_FROM[0] ) querystring += '&startFrom=' + startFrom
|
|
1605
|
+
if ( controls != VALID_CONTROLS[0] ) querystring += '&controls=' + controls
|
|
1606
|
+
}
|
|
1607
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) querystring += '&resolution=' + resolution
|
|
1608
|
+
if ( linkType == VALID_LINK_TYPES[1] ) {
|
|
1609
|
+
if ( force_vod != VALID_FORCE_VOD[0] ) querystring += '&force_vod=' + force_vod
|
|
1610
|
+
} else if ( linkType == VALID_LINK_TYPES[4] ) {
|
|
1611
|
+
querystring += '&filename=' + gameDate + ' SNLA'
|
|
1612
|
+
}
|
|
1613
|
+
querystring += content_protect_b
|
|
1614
|
+
multiviewquerystring += content_protect_b
|
|
1615
|
+
body += '<a href="' + thislink + querystring + '">SNLA</a>'
|
|
1616
|
+
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1617
|
+
body += '</td></tr>' + "\n"
|
|
1618
|
+
} // end entitlements check
|
|
1619
|
+
} catch (e) {
|
|
1620
|
+
session.debuglog('SNLA detect error : ' + e.message)
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// SNY live stream for entitled subscribers
|
|
1624
|
+
try {
|
|
1625
|
+
if ( entitlements.includes('SNY_121') ) {
|
|
1626
|
+
body += '<tr><td><span class="tooltip">SNY<span class="tooltiptext">SNY live stream for entitled subscribers. <a href="https://support.mlb.com/s/article/SNY-In-Market-Offering">See here for more information</a>.</span></span></td><td>'
|
|
1627
|
+
let querystring = '?event=SNY'
|
|
1628
|
+
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1629
|
+
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
1630
|
+
if ( startFrom != VALID_START_FROM[0] ) querystring += '&startFrom=' + startFrom
|
|
1631
|
+
if ( controls != VALID_CONTROLS[0] ) querystring += '&controls=' + controls
|
|
1632
|
+
}
|
|
1633
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) querystring += '&resolution=' + resolution
|
|
1634
|
+
if ( linkType == VALID_LINK_TYPES[1] ) {
|
|
1635
|
+
if ( force_vod != VALID_FORCE_VOD[0] ) querystring += '&force_vod=' + force_vod
|
|
1636
|
+
} else if ( linkType == VALID_LINK_TYPES[4] ) {
|
|
1637
|
+
querystring += '&filename=' + gameDate + ' SNY'
|
|
1638
|
+
}
|
|
1639
|
+
querystring += content_protect_b
|
|
1640
|
+
multiviewquerystring += content_protect_b
|
|
1641
|
+
body += '<a href="' + thislink + querystring + '">SNY</a>'
|
|
1642
|
+
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1643
|
+
body += '</td></tr>' + "\n"
|
|
1644
|
+
} // end entitlements check
|
|
1645
|
+
} catch (e) {
|
|
1646
|
+
session.debuglog('SNY detect error : ' + e.message)
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1592
1649
|
if ( (mediaType == 'MLBTV') && ((level_ids == levels['MLB']) || level_ids.startsWith(levels['MLB'] + ',')) ) {
|
|
1593
1650
|
// Recap Rundown beginning in 2023, disabled because it stopped working
|
|
1594
1651
|
/*if ( (gameDate <= yesterday) && (gameDate >= '2023-03-31') && cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
|
|
@@ -1618,12 +1675,13 @@ app.get('/', async function(req, res) {
|
|
|
1618
1675
|
//big_inning = await session.generateBigInningSchedule(gameDate)
|
|
1619
1676
|
}
|
|
1620
1677
|
if ( big_inning && big_inning.start ) {
|
|
1621
|
-
body += '<tr><td><span class="tooltip">' + new Date(big_inning.start).toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) + ' - ' + new Date(big_inning.end).toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) + '<span class="tooltiptext">Big Inning is the live look-in and highlights show. <a href="https://
|
|
1678
|
+
body += '<tr><td><span class="tooltip">' + new Date(big_inning.start).toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) + ' - ' + new Date(big_inning.end).toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) + '<span class="tooltiptext">Big Inning is the live look-in and highlights show. <a href="https://support.mlb.com/s/article/What-Is-MLB-Big-Inning">See here for more information</a>.</span></span></td><td>'
|
|
1622
1679
|
let compareStart = new Date(big_inning.start)
|
|
1623
1680
|
compareStart.setMinutes(compareStart.getMinutes()-10)
|
|
1624
1681
|
let compareEnd = new Date(big_inning.end)
|
|
1625
1682
|
compareEnd.setHours(compareEnd.getHours()+1)
|
|
1626
1683
|
if ( (currentDate >= compareStart) && (currentDate < compareEnd) ) {
|
|
1684
|
+
body += '<tr><td><span class="tooltip">Big Inning<span class="tooltiptext">Big Inning is the live look-in and highlights show. <a href="https://support.mlb.com/s/article/What-Is-MLB-Big-Inning">See here for more information</a>.</span></span></td><td>'
|
|
1627
1685
|
let querystring = '?event=biginning'
|
|
1628
1686
|
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1629
1687
|
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
@@ -1659,15 +1717,15 @@ app.get('/', async function(req, res) {
|
|
|
1659
1717
|
compareEnd.setHours(compareEnd.getHours()+4)
|
|
1660
1718
|
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 720p60 resolution if not specified.</span></span></td><td>'
|
|
1661
1719
|
if ( (currentDate >= compareStart) && (currentDate < compareEnd) ) {
|
|
1662
|
-
let streamURL = server + '/gamechanger.m3u8'
|
|
1663
|
-
let multiviewquerystring = streamURL + '
|
|
1720
|
+
let streamURL = server + '/gamechanger.m3u8?'
|
|
1721
|
+
let multiviewquerystring = streamURL + 'resolution=' + DEFAULT_MULTIVIEW_RESOLUTION + content_protect_b
|
|
1664
1722
|
streamURL += content_protect_a
|
|
1665
|
-
if ( resolution != VALID_RESOLUTIONS[0] ) streamURL += '
|
|
1723
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) streamURL += 'resolution=' + resolution + '&'
|
|
1666
1724
|
if ( linkType != VALID_LINK_TYPES[1] ) {
|
|
1667
|
-
streamURL = thislink + '?src=' + encodeURIComponent(streamURL) + '
|
|
1725
|
+
streamURL = thislink + '?src=' + encodeURIComponent(streamURL) + 'startFrom=' + VALID_START_FROM[1] + content_protect_b + '&'
|
|
1668
1726
|
}
|
|
1669
1727
|
if ( linkType == VALID_LINK_TYPES[4] ) {
|
|
1670
|
-
streamURL += '
|
|
1728
|
+
streamURL += 'filename=' + gameDate + ' Game Changer' + '&'
|
|
1671
1729
|
}
|
|
1672
1730
|
body += '<a href="' + streamURL + '">Game Changer</a>'
|
|
1673
1731
|
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + multiviewquerystring + '" onclick="addmultiview(this, [], excludeTeams)">'
|
|
@@ -2196,7 +2254,7 @@ app.get('/', async function(req, res) {
|
|
|
2196
2254
|
resolution = 'best'
|
|
2197
2255
|
}
|
|
2198
2256
|
|
|
2199
|
-
body += '<p><span class="tooltip">All<span class="tooltiptext">Will include all live MLB broadcasts (
|
|
2257
|
+
body += '<p><span class="tooltip">All<span class="tooltiptext">Will include all entitled live MLB broadcasts (games plus Big Inning, Game Changer, and Multiview, as well as MLB Network, SNLA, and/or SNY as appropriate). If favorite team(s) have been provided, it will also include affiliate games for those organizations. Channels/games subject to blackout will be omitted by default. See below for an additional option to override that.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + content_protect_b + '">channels.m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + content_protect_b + '">guide.xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + content_protect_b + '">calendar.ics</a></p>' + "\n"
|
|
2200
2258
|
|
|
2201
2259
|
let include_teams = 'ath,national'
|
|
2202
2260
|
if ( session.credentials.fav_teams.length > 0 ) {
|
|
@@ -2211,7 +2269,17 @@ app.get('/', async function(req, res) {
|
|
|
2211
2269
|
|
|
2212
2270
|
body += '<p><span class="tooltip">Include (or exclude) LIDOM<span class="tooltiptext">Dominican Winter League, aka Liga de Beisbol Dominicano. Live stream only, does not support starting from the beginning or certain innings, skip options, etc.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=lidom' + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=lidom' + content_protect_b + '">xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=lidom' + content_protect_b + '">ics</a></p>' + "\n"
|
|
2213
2271
|
|
|
2214
|
-
|
|
2272
|
+
if ( entitlements.includes('MLBN') || entitlements.includes('EXECMLB') || entitlements.includes('MLBTVMLBNADOBEPASS') ) {
|
|
2273
|
+
body += '<p><span class="tooltip">Include (or exclude) MLB Network<span class="tooltiptext">MLB Network live stream is now available in the USA for paid MLBTV subscribers or as a paid add-on, in addition to authenticated TV subscribers. <a href="https://support.mlb.com/s/article/MLB-Network-Streaming-FAQ">See here for more information</a>.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=mlbn' + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=mlbn' + content_protect_b + '">xml</a></p>' + "\n"
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
if ( entitlements.includes('SNLA_119') ) {
|
|
2277
|
+
body += '<p><span class="tooltip">Include (or exclude) SportsNet LA<span class="tooltiptext">SNLA live stream for entitled subscribers. <a href="https://support.mlb.com/s/article/SNLA-Plus-Subscription-Packages">See here for more information</a>.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=snla' + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=snla' + content_protect_b + '">xml</a></p>' + "\n"
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
if ( entitlements.includes('SNY_121') ) {
|
|
2281
|
+
body += '<p><span class="tooltip">Include (or exclude) SNY<span class="tooltiptext">SNY live stream for entitled subscribers. <a href="https://support.mlb.com/s/article/SNLA-Plus-Subscription-Packages">See here for more information</a>.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=sny' + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=sny' + content_protect_b + '">xml</a></p>' + "\n"
|
|
2282
|
+
}
|
|
2215
2283
|
|
|
2216
2284
|
body += '<p><span class="tooltip">Include (or exclude) Big Inning<span class="tooltiptext">Big Inning is the live look-in and highlights show. <a href="https://www.mlb.com/live-stream-games/big-inning">See here for more information</a>.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=biginning' + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=biginning' + content_protect_b + '">xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=biginning' + content_protect_b + '">ics</a></p>' + "\n"
|
|
2217
2285
|
|
package/package.json
CHANGED
package/session.js
CHANGED
|
@@ -38,12 +38,16 @@ const WINTER_LEAGUES = [AFL_ID, LIDOM_ID]
|
|
|
38
38
|
const BREAK_TYPES = ['Game Advisory', 'Pitching Substitution', 'Offensive Substitution', 'Defensive Sub', 'Defensive Switch', 'Runner Placed On Base']
|
|
39
39
|
// These are the events to keep, in addition to the last event of each at-bat, if we're skipping pitches
|
|
40
40
|
const ACTION_TYPES = ['Wild Pitch', 'Passed Ball', 'Stolen Base', 'Caught Stealing', 'Pickoff', 'Error', 'Out', 'Balk', 'Defensive Indiff', 'Other Advance']
|
|
41
|
+
// These are some idle events to skip
|
|
42
|
+
const IDLE_TYPES = ['Mound Visit', 'Batter Timeout', 'Pitcher Step Off', 'challenge']
|
|
41
43
|
const EVENT_START_PADDING = -3
|
|
42
|
-
const PITCH_END_PADDING =
|
|
44
|
+
const PITCH_END_PADDING = 2
|
|
43
45
|
const ACTION_END_PADDING = 7
|
|
44
46
|
const MINIMUM_BREAK_DURATION = 5
|
|
45
47
|
// extra padding for MLB events (2025)
|
|
46
48
|
const MLB_PADDING = 39
|
|
49
|
+
// extra Game Changer padding for MLB (2025)
|
|
50
|
+
const MLB_GAMECHANGER_PADDING = 20
|
|
47
51
|
|
|
48
52
|
const LI_TABLE = {
|
|
49
53
|
1: {
|
|
@@ -1269,7 +1273,7 @@ class sessionClass {
|
|
|
1269
1273
|
this.save_cache_data()
|
|
1270
1274
|
}
|
|
1271
1275
|
|
|
1272
|
-
cacheStreamURL(mediaId, streamURL, streamURLToken='', streamURLExpiration='') {
|
|
1276
|
+
cacheStreamURL(mediaId, streamURL, streamURLToken='', streamURLExpiration='', rawStreamURL='') {
|
|
1273
1277
|
this.createMediaCache(mediaId)
|
|
1274
1278
|
this.cache.media[mediaId].streamURL = streamURL
|
|
1275
1279
|
if (streamURLToken != '') {
|
|
@@ -1282,6 +1286,7 @@ class sessionClass {
|
|
|
1282
1286
|
} else {
|
|
1283
1287
|
this.cache.media[mediaId].streamURLExpiry = new Date(streamURLExpiration)
|
|
1284
1288
|
}
|
|
1289
|
+
this.cache.media[mediaId].rawStreamURL = rawStreamURL
|
|
1285
1290
|
this.save_cache_data()
|
|
1286
1291
|
}
|
|
1287
1292
|
|
|
@@ -1572,6 +1577,9 @@ class sessionClass {
|
|
|
1572
1577
|
if ( this.cache.media && this.cache.media[mediaId] && this.cache.media[mediaId].streamURL && this.cache.media[mediaId].streamURLToken && this.cache.media[mediaId].streamURLExpiry && (Date.parse(this.cache.media[mediaId].streamURLExpiry) > new Date()) ) {
|
|
1573
1578
|
this.debuglog('using cached streamURL and token')
|
|
1574
1579
|
let streamInfo = {streamURL: this.cache.media[mediaId].streamURL, streamURLToken: this.cache.media[mediaId].streamURLToken}
|
|
1580
|
+
if ( this.cache.media[mediaId].rawStreamURL ) {
|
|
1581
|
+
streamInfo['rawStreamURL'] = this.cache.media[mediaId].rawStreamURL
|
|
1582
|
+
}
|
|
1575
1583
|
return streamInfo
|
|
1576
1584
|
} else if ( this.cache.media && this.cache.media[mediaId] && this.cache.media[mediaId].blackout && this.cache.media[mediaId].blackoutExpiry && (Date.parse(this.cache.media[mediaId].blackoutExpiry) > new Date()) ) {
|
|
1577
1585
|
this.log('mediaId recently blacked out, skipping')
|
|
@@ -1611,17 +1619,17 @@ class sessionClass {
|
|
|
1611
1619
|
var response = await this.httpPost(reqObj)
|
|
1612
1620
|
if ( response ) {
|
|
1613
1621
|
this.debuglog('getStreamURL response : ' + JSON.stringify(response))
|
|
1614
|
-
if ( response.data && response.data.initPlaybackSession && response.data.initPlaybackSession.playback && response.data.initPlaybackSession.playback.url
|
|
1622
|
+
if ( response.data && response.data.initPlaybackSession && response.data.initPlaybackSession.playback && response.data.initPlaybackSession.playback.url ) {
|
|
1615
1623
|
let rawStreamURL = response.data.initPlaybackSession.playback.url
|
|
1616
1624
|
this.debuglog('getStreamURL rawStreamURL : ' + rawStreamURL)
|
|
1617
1625
|
let streamURL = rawStreamURL.replace(/[\/]([A-Za-z0-9_]+)[\/]/, '/')
|
|
1618
|
-
|
|
1619
|
-
|
|
1626
|
+
let streamURLToken = response.data.initPlaybackSession.playback.token
|
|
1627
|
+
let streamURLExpiration = response.data.initPlaybackSession.playback.expiration
|
|
1620
1628
|
this.debuglog('getStreamURL streamURL : ' + streamURL)
|
|
1621
1629
|
this.debuglog('getStreamURL token : ' + streamURLToken)
|
|
1622
1630
|
this.debuglog('getStreamURL expiration : ' + streamURLExpiration)
|
|
1623
|
-
this.cacheStreamURL(mediaId, streamURL, streamURLToken, streamURLExpiration)
|
|
1624
|
-
let streamInfo = {streamURL: streamURL, streamURLToken: streamURLToken}
|
|
1631
|
+
this.cacheStreamURL(mediaId, streamURL, streamURLToken, streamURLExpiration, rawStreamURL)
|
|
1632
|
+
let streamInfo = {streamURL: streamURL, streamURLToken: streamURLToken, rawStreamURL: rawStreamURL}
|
|
1625
1633
|
return streamInfo
|
|
1626
1634
|
} else {
|
|
1627
1635
|
this.log('getStreamURL streamURL not found')
|
|
@@ -2588,9 +2596,10 @@ class sessionClass {
|
|
|
2588
2596
|
channels = this.sortObj(channels)
|
|
2589
2597
|
channels = Object.assign(channels, nationalChannels)
|
|
2590
2598
|
|
|
2599
|
+
|
|
2600
|
+
let entitlements = await this.getEntitlements()
|
|
2591
2601
|
// MLB Network live stream for eligible USA subscribers
|
|
2592
2602
|
try {
|
|
2593
|
-
let entitlements = await this.getEntitlements()
|
|
2594
2603
|
if ( (entitlements.includes('MLBN') || entitlements.includes('EXECMLB') || entitlements.includes('MLBTVMLBNADOBEPASS')) ) {
|
|
2595
2604
|
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2596
2605
|
if ( (excludeTeams.length > 0) && excludeTeams.includes('MLBN') ) {
|
|
@@ -2620,6 +2629,70 @@ class sessionClass {
|
|
|
2620
2629
|
} catch (e) {
|
|
2621
2630
|
this.debuglog('getTVData MLB Network detect error : ' + e.message)
|
|
2622
2631
|
}
|
|
2632
|
+
|
|
2633
|
+
// SNLA live stream for entitled subscribers
|
|
2634
|
+
try {
|
|
2635
|
+
if ( (entitlements.includes('SNLA_119')) ) {
|
|
2636
|
+
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2637
|
+
if ( (excludeTeams.length > 0) && excludeTeams.includes('SNLA') ) {
|
|
2638
|
+
// do nothing
|
|
2639
|
+
} else if ( (includeTeams.length == 0) || includeTeams.includes('SNLA') ) {
|
|
2640
|
+
this.debuglog('getTVData processing SNLA')
|
|
2641
|
+
let logo = 'https://img.mlbstatic.com/mlb-images/image/upload/t_w640/mlb/fnwk2k0kgn1j8r8vvx3d.png'
|
|
2642
|
+
let channelid = mediaType + '.SNLA'
|
|
2643
|
+
//if ( this.protection.content_protect ) logo += '&content_protect=' + this.protection.content_protect
|
|
2644
|
+
let stream = server + '/stream.m3u8?event=snla&mediaType=Video&resolution=' + resolution
|
|
2645
|
+
if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
|
|
2646
|
+
if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
|
|
2647
|
+
channels[channelid] = await this.create_channel_object(channelid, logo, stream, mediaType)
|
|
2648
|
+
|
|
2649
|
+
let title = 'SportsNet LA'
|
|
2650
|
+
let description = 'Live stream of SNLA'
|
|
2651
|
+
|
|
2652
|
+
let start = this.convertDateToXMLTV(new Date(cache_data.dates[0].date + ' 00:00:00'))
|
|
2653
|
+
let stop = this.convertDateToXMLTV(new Date(cache_data.dates[cache_data.dates.length-1].date + ' 00:00:00'))
|
|
2654
|
+
|
|
2655
|
+
// SNLA guide XML
|
|
2656
|
+
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertStringToAirDate(cache_data.dates[0].date))
|
|
2657
|
+
this.debuglog('getTVData completed SNLA')
|
|
2658
|
+
} // end includeTeams check
|
|
2659
|
+
} // end mediaType check
|
|
2660
|
+
} // end entitlements check
|
|
2661
|
+
} catch (e) {
|
|
2662
|
+
this.debuglog('getTVData SNLA detect error : ' + e.message)
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
// SNY live stream for entitled subscribers
|
|
2666
|
+
try {
|
|
2667
|
+
if ( (entitlements.includes('SNY_121')) ) {
|
|
2668
|
+
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2669
|
+
if ( (excludeTeams.length > 0) && excludeTeams.includes('SNY') ) {
|
|
2670
|
+
// do nothing
|
|
2671
|
+
} else if ( (includeTeams.length == 0) || includeTeams.includes('SNY') ) {
|
|
2672
|
+
this.debuglog('getTVData processing SNY')
|
|
2673
|
+
let logo = 'https://img.mlbstatic.com/mlb-images/image/upload/t_w640/mlb/le5jifzo6oylxtnuf0m1.png'
|
|
2674
|
+
let channelid = mediaType + '.SNY'
|
|
2675
|
+
//if ( this.protection.content_protect ) logo += '&content_protect=' + this.protection.content_protect
|
|
2676
|
+
let stream = server + '/stream.m3u8?event=sny&mediaType=Video&resolution=' + resolution
|
|
2677
|
+
if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
|
|
2678
|
+
if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
|
|
2679
|
+
channels[channelid] = await this.create_channel_object(channelid, logo, stream, mediaType)
|
|
2680
|
+
|
|
2681
|
+
let title = 'SNY'
|
|
2682
|
+
let description = 'Live stream of SNY'
|
|
2683
|
+
|
|
2684
|
+
let start = this.convertDateToXMLTV(new Date(cache_data.dates[0].date + ' 00:00:00'))
|
|
2685
|
+
let stop = this.convertDateToXMLTV(new Date(cache_data.dates[cache_data.dates.length-1].date + ' 00:00:00'))
|
|
2686
|
+
|
|
2687
|
+
// SNLA guide XML
|
|
2688
|
+
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertStringToAirDate(cache_data.dates[0].date))
|
|
2689
|
+
this.debuglog('getTVData completed SNY')
|
|
2690
|
+
} // end includeTeams check
|
|
2691
|
+
} // end mediaType check
|
|
2692
|
+
} // end entitlements check
|
|
2693
|
+
} catch (e) {
|
|
2694
|
+
this.debuglog('getTVData SNY detect error : ' + e.message)
|
|
2695
|
+
}
|
|
2623
2696
|
|
|
2624
2697
|
// Big Inning
|
|
2625
2698
|
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
@@ -2638,6 +2711,7 @@ class sessionClass {
|
|
|
2638
2711
|
let title = 'MLB Big Inning'
|
|
2639
2712
|
let description = 'Live look-ins and big moments from around the league'
|
|
2640
2713
|
|
|
2714
|
+
// disabled Big Inning schedule scraping March 2025
|
|
2641
2715
|
for (var i = 0; i < cache_data.dates.length; i++) {
|
|
2642
2716
|
// Scraped Big Inning schedule
|
|
2643
2717
|
if ( (cache_data.dates[i].date >= today) && cache_data.dates[i].games && (cache_data.dates[i].games.length > 1) && cache_data.dates[i].games[0] && (cache_data.dates[i].games[0].seriesDescription == 'Regular Season') ) {
|
|
@@ -2655,9 +2729,9 @@ class sessionClass {
|
|
|
2655
2729
|
let stop = this.convertDateToXMLTV(new Date(this.cache.bigInningSchedule[gameDate].end))
|
|
2656
2730
|
|
|
2657
2731
|
// Generated Big Inning schedule (disabled)
|
|
2658
|
-
|
|
2659
|
-
let start = this.convertDateToXMLTV(new Date(big_inning.start))
|
|
2660
|
-
let stop = this.convertDateToXMLTV(new Date(big_inning.end))
|
|
2732
|
+
//let big_inning = await this.generateBigInningSchedule(gameDate)
|
|
2733
|
+
//let start = this.convertDateToXMLTV(new Date(big_inning.start))
|
|
2734
|
+
//let stop = this.convertDateToXMLTV(new Date(big_inning.end))
|
|
2661
2735
|
|
|
2662
2736
|
// Big Inning calendar ICS
|
|
2663
2737
|
let prefix = 'Watch'
|
|
@@ -2670,6 +2744,12 @@ class sessionClass {
|
|
|
2670
2744
|
}
|
|
2671
2745
|
this.debuglog('getTVData completed Big Inning for date ' + cache_data.dates[i].date)
|
|
2672
2746
|
}
|
|
2747
|
+
|
|
2748
|
+
// generic Big Inning guide XML
|
|
2749
|
+
/*let start = this.convertDateToXMLTV(new Date(cache_data.dates[0].date + ' 00:00:00'))
|
|
2750
|
+
let stop = this.convertDateToXMLTV(new Date(cache_data.dates[cache_data.dates.length-1].date + ' 00:00:00'))
|
|
2751
|
+
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertStringToAirDate(cache_data.dates[0].date))*/
|
|
2752
|
+
|
|
2673
2753
|
this.debuglog('getTVData completed Big Inning')
|
|
2674
2754
|
}
|
|
2675
2755
|
}
|
|
@@ -3024,8 +3104,11 @@ class sessionClass {
|
|
|
3024
3104
|
event_end_padding = pitch_end_padding
|
|
3025
3105
|
}
|
|
3026
3106
|
let action_index
|
|
3027
|
-
// skip type 1 (breaks)
|
|
3028
|
-
if ((skip_type
|
|
3107
|
+
// skip type 1 (breaks) will look at all plays with an endTime
|
|
3108
|
+
if ((skip_type == 1) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime) {
|
|
3109
|
+
action_index = j
|
|
3110
|
+
// skip type 2 (idle time) will look at all non-idle plays with an endTime
|
|
3111
|
+
} else if ((skip_type == 2) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime && (!cache_data.liveData.plays.allPlays[i].playEvents[j].details || !cache_data.liveData.plays.allPlays[i].playEvents[j].details.description || !IDLE_TYPES.some(v => cache_data.liveData.plays.allPlays[i].playEvents[j].details.description.includes(v)))) {
|
|
3029
3112
|
action_index = j
|
|
3030
3113
|
} else if (skip_type == 3) {
|
|
3031
3114
|
// skip type 3 excludes non-action pitches (events that aren't last in the at-bat and don't fall under action types)
|
|
@@ -3116,17 +3199,15 @@ class sessionClass {
|
|
|
3116
3199
|
this.debuglog('getBigInningSchedule')
|
|
3117
3200
|
|
|
3118
3201
|
// temporarily disable Big Inning schedule checking until a new source URL is available
|
|
3119
|
-
this.cache.bigInningSchedule = {}
|
|
3120
|
-
return
|
|
3202
|
+
/*this.cache.bigInningSchedule = {}
|
|
3203
|
+
return*/
|
|
3121
3204
|
|
|
3122
3205
|
let currentDate = new Date()
|
|
3123
3206
|
if ( !this.cache || !this.cache.bigInningScheduleCacheExpiry || (currentDate > new Date(this.cache.bigInningScheduleCacheExpiry)) ) {
|
|
3124
3207
|
if ( !this.cache.bigInningSchedule ) this.cache.bigInningSchedule = {}
|
|
3125
3208
|
let reqObj = {
|
|
3126
|
-
|
|
3127
|
-
url: 'https://www.mlb.com/live-stream-games/help-center/subscription-access-big-inning',
|
|
3209
|
+
url: 'https://www.fubo.tv/welcome/channel/mlb-big-inning',
|
|
3128
3210
|
headers: {
|
|
3129
|
-
'authority': 'www.mlb.com',
|
|
3130
3211
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
3131
3212
|
'accept-language': 'en-US,en;q=0.9',
|
|
3132
3213
|
'cache-control': 'no-cache',
|
|
@@ -3149,89 +3230,15 @@ class sessionClass {
|
|
|
3149
3230
|
if ( response ) {
|
|
3150
3231
|
// disabled because it's very big!
|
|
3151
3232
|
//this.debuglog(response)
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
let
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
let year
|
|
3162
|
-
let month
|
|
3163
|
-
let day
|
|
3164
|
-
let this_datestring
|
|
3165
|
-
let add_date = 0
|
|
3166
|
-
let d
|
|
3167
|
-
|
|
3168
|
-
for (var j=1; j<cols.length; j++) {
|
|
3169
|
-
// split on closing bracket to get column text at resulting array index 0
|
|
3170
|
-
let col = cols[j].split('<')
|
|
3171
|
-
switch(j){
|
|
3172
|
-
// first column is date
|
|
3173
|
-
case 1:
|
|
3174
|
-
// split date into array
|
|
3175
|
-
// old date format (January 1, 1970) (disabled)
|
|
3176
|
-
/*parts = col[0].split(' ')
|
|
3177
|
-
year = parts[2]
|
|
3178
|
-
// get month index, zero-based
|
|
3179
|
-
month = new Date(Date.parse(parts[0] +" 1, 2021")).getMonth()
|
|
3180
|
-
day = parts[1].substring(0,parts[1].length-3)*/
|
|
3181
|
-
// new date format (01/01/70)
|
|
3182
|
-
parts = col[0].split('/')
|
|
3183
|
-
year = parts[2]
|
|
3184
|
-
if ( year.length == 2 ) {
|
|
3185
|
-
year = '20' + parts[2]
|
|
3186
|
-
}
|
|
3187
|
-
// get month index, zero-based
|
|
3188
|
-
month = parseInt(parts[0]) - 1
|
|
3189
|
-
day = parts[1]
|
|
3190
|
-
this_datestring = new Date(year, month, day).toISOString().substring(0,10)
|
|
3191
|
-
this.cache.bigInningSchedule[this_datestring] = {}
|
|
3192
|
-
// increment month index (not zero-based)
|
|
3193
|
-
month += 1
|
|
3194
|
-
break
|
|
3195
|
-
// remaining columns are times
|
|
3196
|
-
default:
|
|
3197
|
-
let hour
|
|
3198
|
-
let minute = '00'
|
|
3199
|
-
let ampm
|
|
3200
|
-
// if time has colon, split into array on that to get hour and minute parts
|
|
3201
|
-
if ( col[0].indexOf(':') > 0 ) {
|
|
3202
|
-
parts = col[0].split(':')
|
|
3203
|
-
hour = parseInt(parts[0])
|
|
3204
|
-
minute = parts[1].substring(0,2)
|
|
3205
|
-
} else {
|
|
3206
|
-
hour = parseInt(col[0].substring(0,col[0].length-2))
|
|
3207
|
-
}
|
|
3208
|
-
ampm = col[0].substring(col[0].length-2,col[0].length)
|
|
3209
|
-
// convert hour to 24-hour format
|
|
3210
|
-
if ( (ampm == 'PM') || ((hour == 12) && (ampm == 'AM')) ) {
|
|
3211
|
-
hour += 12
|
|
3212
|
-
}
|
|
3213
|
-
// these times are EDT so add 4 for UTC
|
|
3214
|
-
hour += 4
|
|
3215
|
-
// if hour is beyond 23, note we will have to add 1 day
|
|
3216
|
-
if ( hour > 23 ) {
|
|
3217
|
-
add_date = 1
|
|
3218
|
-
hour -= 24
|
|
3219
|
-
}
|
|
3220
|
-
|
|
3221
|
-
d = new Date(this_datestring + 'T' + hour.toString().padStart(2, '0') + ':' + minute.toString().padStart(2, '0') + ':00.000+00:00')
|
|
3222
|
-
d.setDate(d.getDate()+add_date)
|
|
3223
|
-
switch(j){
|
|
3224
|
-
// 2nd column is start time
|
|
3225
|
-
case 2:
|
|
3226
|
-
this.cache.bigInningSchedule[this_datestring].start = d
|
|
3227
|
-
break
|
|
3228
|
-
// 3rd column is end time
|
|
3229
|
-
case 3:
|
|
3230
|
-
this.cache.bigInningSchedule[this_datestring].end = d
|
|
3231
|
-
break
|
|
3232
|
-
}
|
|
3233
|
-
break
|
|
3234
|
-
}
|
|
3233
|
+
|
|
3234
|
+
let obj = JSON.parse(response.replace(/\\"/g, '"').match('(?<="channelPrograms":{"live":)(.+?(,"totalPages":1}))')[0])
|
|
3235
|
+
for (var i=0; i < obj.data.length; i++) {
|
|
3236
|
+
let est_date = new Date(obj.data[i].airings[0].start).toLocaleString("en-US", {timeZone: 'America/New_York'})
|
|
3237
|
+
let date_array = est_date.split(',')[0].split('/')
|
|
3238
|
+
let this_datestring = date_array[2] + '-' + date_array[0].padStart(2, '0') + '-' + date_array[1].padStart(2, '0')
|
|
3239
|
+
this.cache.bigInningSchedule[this_datestring] = {
|
|
3240
|
+
start: obj.data[i].airings[0].start,
|
|
3241
|
+
end: obj.data[i].airings[0].end
|
|
3235
3242
|
}
|
|
3236
3243
|
}
|
|
3237
3244
|
this.debuglog(JSON.stringify(this.cache.bigInningSchedule))
|
|
@@ -3380,6 +3387,60 @@ class sessionClass {
|
|
|
3380
3387
|
}
|
|
3381
3388
|
}
|
|
3382
3389
|
|
|
3390
|
+
// Get linear channel stream URL
|
|
3391
|
+
async getLinearStreamURL(network) {
|
|
3392
|
+
try {
|
|
3393
|
+
this.debuglog('getLinearStreamURL')
|
|
3394
|
+
|
|
3395
|
+
let reqObj = {
|
|
3396
|
+
url: GRAPHQL_URL,
|
|
3397
|
+
simple: false,
|
|
3398
|
+
headers: {
|
|
3399
|
+
'accept': 'application/json, text/plain, */*',
|
|
3400
|
+
'accept-encoding': 'gzip, deflate, br',
|
|
3401
|
+
'accept-language': 'en-US,en;q=0.5',
|
|
3402
|
+
'authorization': 'Bearer ' + await this.getLoginToken() || this.halt('missing loginToken'),
|
|
3403
|
+
'connection': 'keep-alive',
|
|
3404
|
+
'content-type': 'application/json',
|
|
3405
|
+
'x-client-name': 'WEB',
|
|
3406
|
+
'x-client-version': '7.8.1',
|
|
3407
|
+
'origin': 'https://www.mlb.com',
|
|
3408
|
+
'referer': 'https://www.mlb.com/',
|
|
3409
|
+
'user-agent': USER_AGENT
|
|
3410
|
+
},
|
|
3411
|
+
body: {
|
|
3412
|
+
'operationName': 'contentCollections',
|
|
3413
|
+
'query': 'query contentCollections(\n $categories: [ContentGroupCategory!]\n $includeRestricted: Boolean = false\n $includeSpoilers: Boolean = false\n $limit: Int = 10,\n $skip: Int = 0\n ) {\n contentCollections(\n categories: $categories\n includeRestricted: $includeRestricted\n includeSpoilers: $includeSpoilers\n limit: $limit\n skip: $skip\n ) {\n title\n category\n contents {\n assetTrackingKey\n contentDate\n contentId\n contentRestrictions\n description\n duration\n language\n mediaId\n officialDate\n title\n mediaState {\n state\n mediaType\n }\n thumbnails {\n thumbnailType\n templateUrl\n thumbnailUrl\n }\n }\n }\n }',
|
|
3414
|
+
'variables': {
|
|
3415
|
+
'categories': network,
|
|
3416
|
+
'limit': '25'
|
|
3417
|
+
}
|
|
3418
|
+
},
|
|
3419
|
+
json: true,
|
|
3420
|
+
gzip: true
|
|
3421
|
+
}
|
|
3422
|
+
var response = await this.httpPost(reqObj)
|
|
3423
|
+
if ( response ) {
|
|
3424
|
+
this.debuglog('getLinearStreamURL response : ' + JSON.stringify(response))
|
|
3425
|
+
if ( response.data && response.data.contentCollections && (response.data.contentCollections.length > 0) && response.data.contentCollections[0].contents ) {
|
|
3426
|
+
for (var i=0; i<response.data.contentCollections[0].contents.length; i++) {
|
|
3427
|
+
try {
|
|
3428
|
+
let streamInfo = await this.getStreamURL(response.data.contentCollections[0].contents[i].mediaId)
|
|
3429
|
+
if ( streamInfo.rawStreamURL ) {
|
|
3430
|
+
return streamInfo.rawStreamURL
|
|
3431
|
+
}
|
|
3432
|
+
} catch(e) {
|
|
3433
|
+
this.debuglog('getLinearStreamURL getStreamURL error : ' + e.message)
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
this.log('getLinearStreamURL stream url not found')
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
} catch(e) {
|
|
3440
|
+
this.log('getLinearStreamURL error : ' + e.message)
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
|
|
3383
3444
|
// Get Recap Rundown data
|
|
3384
3445
|
async getRecapRundownData(dateString) {
|
|
3385
3446
|
try {
|
|
@@ -3473,6 +3534,12 @@ class sessionClass {
|
|
|
3473
3534
|
playbackURL = await this.getRecapRundownURL(dateString)
|
|
3474
3535
|
} else if ( eventName.toUpperCase() == 'MLBN' ) {
|
|
3475
3536
|
playbackURL = 'https://falcon.mlbinfra.com/api/v1/linear/mlbn'
|
|
3537
|
+
} else if ( eventName.toUpperCase() == 'SNLA' ) {
|
|
3538
|
+
playbackURL = await this.getLinearStreamURL('SNLA_LIVE')
|
|
3539
|
+
return playbackURL
|
|
3540
|
+
} else if ( eventName.toUpperCase() == 'SNY' ) {
|
|
3541
|
+
playbackURL = await this.getLinearStreamURL('SNY_LIVE')
|
|
3542
|
+
return playbackURL
|
|
3476
3543
|
} else {
|
|
3477
3544
|
playbackURL = await this.getEventURL(eventName)
|
|
3478
3545
|
}
|
|
@@ -4014,7 +4081,7 @@ class sessionClass {
|
|
|
4014
4081
|
|
|
4015
4082
|
if ( !this.temp_cache.gamechanger[id].games ) this.temp_cache.gamechanger[id].games = []
|
|
4016
4083
|
this.temp_cache.gamechanger[id].games.push(best_games)
|
|
4017
|
-
let maxlength = (this.gamechanger_delay + 10) / 10
|
|
4084
|
+
let maxlength = (this.gamechanger_delay + 10 + MLB_GAMECHANGER_PADDING) / 10
|
|
4018
4085
|
while ( this.temp_cache.gamechanger[id].games.length > maxlength ) {
|
|
4019
4086
|
this.temp_cache.gamechanger[id].games.shift()
|
|
4020
4087
|
}
|