mlbserver 2025.3.2-9.2 → 2025.3.3-0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +84 -19
- package/package.json +1 -1
- package/session.js +155 -19
package/index.js
CHANGED
|
@@ -1041,7 +1041,7 @@ app.get('/gamechanger.m3u8', async function(req, res) {
|
|
|
1041
1041
|
|
|
1042
1042
|
for ( gamechanger_resolution in GAMECHANGER_RESOLUTIONS ) {
|
|
1043
1043
|
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'
|
|
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.m3u8?id=' + id + '&resolution=' + gamechanger_resolution + includeTeams + excludeTeams + content_protect + '\n'
|
|
1045
1045
|
break
|
|
1046
1046
|
}
|
|
1047
1047
|
}
|
|
@@ -1055,10 +1055,10 @@ app.get('/gamechanger.m3u8', async function(req, res) {
|
|
|
1055
1055
|
|
|
1056
1056
|
|
|
1057
1057
|
// Listen for gamechanger playlist requests
|
|
1058
|
-
app.get('/gamechangerplaylist', async function(req, res) {
|
|
1058
|
+
app.get('/gamechangerplaylist.m3u8', async function(req, res) {
|
|
1059
1059
|
if ( ! (await protect(req, res)) ) return
|
|
1060
1060
|
|
|
1061
|
-
session.requestlog('gamechangerplaylist', req, true)
|
|
1061
|
+
session.requestlog('gamechangerplaylist.m3u8', req, true)
|
|
1062
1062
|
|
|
1063
1063
|
let gamechangerAccess = new Date()
|
|
1064
1064
|
|
|
@@ -1562,11 +1562,11 @@ app.get('/', async function(req, res) {
|
|
|
1562
1562
|
|
|
1563
1563
|
let currentDate = new Date()
|
|
1564
1564
|
|
|
1565
|
+
let entitlements = await session.getEntitlements()
|
|
1565
1566
|
// MLB Network live stream for eligible USA subscribers
|
|
1566
1567
|
try {
|
|
1567
|
-
let entitlements = await session.getEntitlements()
|
|
1568
1568
|
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://
|
|
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://support.mlb.com/s/article/MLB-Network-Streaming-FAQ">See here for more information</a>.</span></span></td><td>'
|
|
1570
1570
|
let querystring = '?event=MLBN'
|
|
1571
1571
|
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1572
1572
|
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
@@ -1589,6 +1589,58 @@ app.get('/', async function(req, res) {
|
|
|
1589
1589
|
session.debuglog('MLB Network detect error : ' + e.message)
|
|
1590
1590
|
}
|
|
1591
1591
|
|
|
1592
|
+
// SNLA live stream for entitled subscribers
|
|
1593
|
+
try {
|
|
1594
|
+
if ( entitlements.includes('SNLA_119') ) {
|
|
1595
|
+
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>'
|
|
1596
|
+
let querystring = '?event=SNLA'
|
|
1597
|
+
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1598
|
+
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
1599
|
+
if ( startFrom != VALID_START_FROM[0] ) querystring += '&startFrom=' + startFrom
|
|
1600
|
+
if ( controls != VALID_CONTROLS[0] ) querystring += '&controls=' + controls
|
|
1601
|
+
}
|
|
1602
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) querystring += '&resolution=' + resolution
|
|
1603
|
+
if ( linkType == VALID_LINK_TYPES[1] ) {
|
|
1604
|
+
if ( force_vod != VALID_FORCE_VOD[0] ) querystring += '&force_vod=' + force_vod
|
|
1605
|
+
} else if ( linkType == VALID_LINK_TYPES[4] ) {
|
|
1606
|
+
querystring += '&filename=' + gameDate + ' SNLA'
|
|
1607
|
+
}
|
|
1608
|
+
querystring += content_protect_b
|
|
1609
|
+
multiviewquerystring += content_protect_b
|
|
1610
|
+
body += '<a href="' + thislink + querystring + '">SNLA</a>'
|
|
1611
|
+
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1612
|
+
body += '</td></tr>' + "\n"
|
|
1613
|
+
} // end entitlements check
|
|
1614
|
+
} catch (e) {
|
|
1615
|
+
session.debuglog('SNLA detect error : ' + e.message)
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// SNY live stream for entitled subscribers
|
|
1619
|
+
try {
|
|
1620
|
+
if ( entitlements.includes('SNY_121') ) {
|
|
1621
|
+
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>'
|
|
1622
|
+
let querystring = '?event=SNY'
|
|
1623
|
+
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1624
|
+
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
1625
|
+
if ( startFrom != VALID_START_FROM[0] ) querystring += '&startFrom=' + startFrom
|
|
1626
|
+
if ( controls != VALID_CONTROLS[0] ) querystring += '&controls=' + controls
|
|
1627
|
+
}
|
|
1628
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) querystring += '&resolution=' + resolution
|
|
1629
|
+
if ( linkType == VALID_LINK_TYPES[1] ) {
|
|
1630
|
+
if ( force_vod != VALID_FORCE_VOD[0] ) querystring += '&force_vod=' + force_vod
|
|
1631
|
+
} else if ( linkType == VALID_LINK_TYPES[4] ) {
|
|
1632
|
+
querystring += '&filename=' + gameDate + ' SNY'
|
|
1633
|
+
}
|
|
1634
|
+
querystring += content_protect_b
|
|
1635
|
+
multiviewquerystring += content_protect_b
|
|
1636
|
+
body += '<a href="' + thislink + querystring + '">SNY</a>'
|
|
1637
|
+
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1638
|
+
body += '</td></tr>' + "\n"
|
|
1639
|
+
} // end entitlements check
|
|
1640
|
+
} catch (e) {
|
|
1641
|
+
session.debuglog('SNY detect error : ' + e.message)
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1592
1644
|
if ( (mediaType == 'MLBTV') && ((level_ids == levels['MLB']) || level_ids.startsWith(levels['MLB'] + ',')) ) {
|
|
1593
1645
|
// Recap Rundown beginning in 2023, disabled because it stopped working
|
|
1594
1646
|
/*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) ) {
|
|
@@ -1609,7 +1661,8 @@ app.get('/', async function(req, res) {
|
|
|
1609
1661
|
}
|
|
1610
1662
|
|
|
1611
1663
|
// Big Inning
|
|
1612
|
-
|
|
1664
|
+
// disabled Big Inning schedule scraping (March 2025)
|
|
1665
|
+
/*var big_inning
|
|
1613
1666
|
if ( cache_data.dates && cache_data.dates[0] && (cache_data.dates[0].date >= today) && cache_data.dates[0].games && (cache_data.dates[0].games.length > 1) && cache_data.dates[0].games[0] && (cache_data.dates[0].games[0].seriesDescription == 'Regular Season') ) {
|
|
1614
1667
|
// Scraped Big Inning schedule
|
|
1615
1668
|
big_inning = await session.getBigInningSchedule(gameDate)
|
|
@@ -1618,12 +1671,13 @@ app.get('/', async function(req, res) {
|
|
|
1618
1671
|
//big_inning = await session.generateBigInningSchedule(gameDate)
|
|
1619
1672
|
}
|
|
1620
1673
|
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://
|
|
1674
|
+
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
1675
|
let compareStart = new Date(big_inning.start)
|
|
1623
1676
|
compareStart.setMinutes(compareStart.getMinutes()-10)
|
|
1624
1677
|
let compareEnd = new Date(big_inning.end)
|
|
1625
1678
|
compareEnd.setHours(compareEnd.getHours()+1)
|
|
1626
|
-
if ( (currentDate >= compareStart) && (currentDate < compareEnd) ) {
|
|
1679
|
+
if ( (currentDate >= compareStart) && (currentDate < compareEnd) ) {*/
|
|
1680
|
+
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
1681
|
let querystring = '?event=biginning'
|
|
1628
1682
|
let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
|
|
1629
1683
|
if ( linkType == VALID_LINK_TYPES[0] ) {
|
|
@@ -1640,11 +1694,11 @@ app.get('/', async function(req, res) {
|
|
|
1640
1694
|
multiviewquerystring += content_protect_b
|
|
1641
1695
|
body += '<a href="' + thislink + querystring + '">Big Inning</a>'
|
|
1642
1696
|
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + '/stream.m3u8' + multiviewquerystring + '" onclick="addmultiview(this)">'
|
|
1643
|
-
} else {
|
|
1697
|
+
/*} else {
|
|
1644
1698
|
body += 'Big Inning'
|
|
1645
|
-
}
|
|
1699
|
+
}*/
|
|
1646
1700
|
body += '</td></tr>' + "\n"
|
|
1647
|
-
}
|
|
1701
|
+
//}
|
|
1648
1702
|
|
|
1649
1703
|
// Game Changer
|
|
1650
1704
|
if ( (gameDate >= today) && cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 1) ) {
|
|
@@ -1659,15 +1713,15 @@ app.get('/', async function(req, res) {
|
|
|
1659
1713
|
compareEnd.setHours(compareEnd.getHours()+4)
|
|
1660
1714
|
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
1715
|
if ( (currentDate >= compareStart) && (currentDate < compareEnd) ) {
|
|
1662
|
-
let streamURL = server + '/gamechanger.m3u8'
|
|
1663
|
-
let multiviewquerystring = streamURL + '
|
|
1716
|
+
let streamURL = server + '/gamechanger.m3u8?'
|
|
1717
|
+
let multiviewquerystring = streamURL + 'resolution=' + DEFAULT_MULTIVIEW_RESOLUTION + content_protect_b
|
|
1664
1718
|
streamURL += content_protect_a
|
|
1665
|
-
if ( resolution != VALID_RESOLUTIONS[0] ) streamURL += '
|
|
1719
|
+
if ( resolution != VALID_RESOLUTIONS[0] ) streamURL += 'resolution=' + resolution + '&'
|
|
1666
1720
|
if ( linkType != VALID_LINK_TYPES[1] ) {
|
|
1667
|
-
streamURL = thislink + '?src=' + encodeURIComponent(streamURL) + '
|
|
1721
|
+
streamURL = thislink + '?src=' + encodeURIComponent(streamURL) + 'startFrom=' + VALID_START_FROM[1] + content_protect_b + '&'
|
|
1668
1722
|
}
|
|
1669
1723
|
if ( linkType == VALID_LINK_TYPES[4] ) {
|
|
1670
|
-
streamURL += '
|
|
1724
|
+
streamURL += 'filename=' + gameDate + ' Game Changer' + '&'
|
|
1671
1725
|
}
|
|
1672
1726
|
body += '<a href="' + streamURL + '">Game Changer</a>'
|
|
1673
1727
|
body += '<input type="checkbox" value="http://127.0.0.1:' + session.data.port + multiviewquerystring + '" onclick="addmultiview(this, [], excludeTeams)">'
|
|
@@ -2196,7 +2250,7 @@ app.get('/', async function(req, res) {
|
|
|
2196
2250
|
resolution = 'best'
|
|
2197
2251
|
}
|
|
2198
2252
|
|
|
2199
|
-
body += '<p><span class="tooltip">All<span class="tooltiptext">Will include all live MLB broadcasts (
|
|
2253
|
+
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
2254
|
|
|
2201
2255
|
let include_teams = 'ath,national'
|
|
2202
2256
|
if ( session.credentials.fav_teams.length > 0 ) {
|
|
@@ -2211,9 +2265,20 @@ app.get('/', async function(req, res) {
|
|
|
2211
2265
|
|
|
2212
2266
|
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
2267
|
|
|
2214
|
-
|
|
2268
|
+
if ( entitlements.includes('MLBN') || entitlements.includes('EXECMLB') || entitlements.includes('MLBTVMLBNADOBEPASS') ) {
|
|
2269
|
+
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"
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
if ( entitlements.includes('SNLA_119') ) {
|
|
2273
|
+
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"
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
if ( entitlements.includes('SNY_121') ) {
|
|
2277
|
+
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"
|
|
2278
|
+
}
|
|
2215
2279
|
|
|
2216
|
-
|
|
2280
|
+
// disabled Big Inning schedule scraping (March 2025)
|
|
2281
|
+
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
2282
|
|
|
2218
2283
|
let gamechanger_resolution = resolution
|
|
2219
2284
|
if ( gamechanger_resolution == VALID_RESOLUTIONS[0] ) {
|
package/package.json
CHANGED
package/session.js
CHANGED
|
@@ -39,13 +39,15 @@ const BREAK_TYPES = ['Game Advisory', 'Pitching Substitution', 'Offensive Substi
|
|
|
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
41
|
// These are some idle events to skip
|
|
42
|
-
const IDLE_TYPES = ['Mound Visit', 'Batter Timeout', 'Pitcher Step Off']
|
|
42
|
+
const IDLE_TYPES = ['Mound Visit', 'Batter Timeout', 'Pitcher Step Off', 'challenge']
|
|
43
43
|
const EVENT_START_PADDING = -3
|
|
44
44
|
const PITCH_END_PADDING = 2
|
|
45
45
|
const ACTION_END_PADDING = 7
|
|
46
46
|
const MINIMUM_BREAK_DURATION = 5
|
|
47
47
|
// extra padding for MLB events (2025)
|
|
48
48
|
const MLB_PADDING = 39
|
|
49
|
+
// extra Game Changer padding for MLB (2025)
|
|
50
|
+
const MLB_GAMECHANGER_PADDING = 20
|
|
49
51
|
|
|
50
52
|
const LI_TABLE = {
|
|
51
53
|
1: {
|
|
@@ -1613,18 +1615,22 @@ class sessionClass {
|
|
|
1613
1615
|
var response = await this.httpPost(reqObj)
|
|
1614
1616
|
if ( response ) {
|
|
1615
1617
|
this.debuglog('getStreamURL response : ' + JSON.stringify(response))
|
|
1616
|
-
if ( response.data && response.data.initPlaybackSession && response.data.initPlaybackSession.playback && response.data.initPlaybackSession.playback.url
|
|
1618
|
+
if ( response.data && response.data.initPlaybackSession && response.data.initPlaybackSession.playback && response.data.initPlaybackSession.playback.url ) {
|
|
1617
1619
|
let rawStreamURL = response.data.initPlaybackSession.playback.url
|
|
1618
1620
|
this.debuglog('getStreamURL rawStreamURL : ' + rawStreamURL)
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1621
|
+
if ( response.data.initPlaybackSession.playback.token == null ) {
|
|
1622
|
+
return rawStreamURL
|
|
1623
|
+
} else if ( response.data.initPlaybackSession.playback.token && response.data.initPlaybackSession.playback.expiration ) {
|
|
1624
|
+
let streamURL = rawStreamURL.replace(/[\/]([A-Za-z0-9_]+)[\/]/, '/')
|
|
1625
|
+
this.debuglog('getStreamURL streamURL : ' + streamURL)
|
|
1626
|
+
let streamURLToken = response.data.initPlaybackSession.playback.token
|
|
1627
|
+
this.debuglog('getStreamURL token : ' + streamURLToken)
|
|
1628
|
+
let streamURLExpiration = response.data.initPlaybackSession.playback.expiration
|
|
1629
|
+
this.debuglog('getStreamURL expiration : ' + streamURLExpiration)
|
|
1630
|
+
this.cacheStreamURL(mediaId, streamURL, streamURLToken, streamURLExpiration)
|
|
1631
|
+
let streamInfo = {streamURL: streamURL, streamURLToken: streamURLToken}
|
|
1632
|
+
return streamInfo
|
|
1633
|
+
}
|
|
1628
1634
|
} else {
|
|
1629
1635
|
this.log('getStreamURL streamURL not found')
|
|
1630
1636
|
return false
|
|
@@ -2590,9 +2596,10 @@ class sessionClass {
|
|
|
2590
2596
|
channels = this.sortObj(channels)
|
|
2591
2597
|
channels = Object.assign(channels, nationalChannels)
|
|
2592
2598
|
|
|
2599
|
+
|
|
2600
|
+
let entitlements = await this.getEntitlements()
|
|
2593
2601
|
// MLB Network live stream for eligible USA subscribers
|
|
2594
2602
|
try {
|
|
2595
|
-
let entitlements = await this.getEntitlements()
|
|
2596
2603
|
if ( (entitlements.includes('MLBN') || entitlements.includes('EXECMLB') || entitlements.includes('MLBTVMLBNADOBEPASS')) ) {
|
|
2597
2604
|
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2598
2605
|
if ( (excludeTeams.length > 0) && excludeTeams.includes('MLBN') ) {
|
|
@@ -2622,6 +2629,70 @@ class sessionClass {
|
|
|
2622
2629
|
} catch (e) {
|
|
2623
2630
|
this.debuglog('getTVData MLB Network detect error : ' + e.message)
|
|
2624
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
|
+
}
|
|
2625
2696
|
|
|
2626
2697
|
// Big Inning
|
|
2627
2698
|
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
@@ -2640,7 +2711,8 @@ class sessionClass {
|
|
|
2640
2711
|
let title = 'MLB Big Inning'
|
|
2641
2712
|
let description = 'Live look-ins and big moments from around the league'
|
|
2642
2713
|
|
|
2643
|
-
|
|
2714
|
+
// disabled Big Inning schedule scraping March 2025
|
|
2715
|
+
/*for (var i = 0; i < cache_data.dates.length; i++) {
|
|
2644
2716
|
// Scraped Big Inning schedule
|
|
2645
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') ) {
|
|
2646
2718
|
await this.getBigInningSchedule()
|
|
@@ -2657,9 +2729,9 @@ class sessionClass {
|
|
|
2657
2729
|
let stop = this.convertDateToXMLTV(new Date(this.cache.bigInningSchedule[gameDate].end))
|
|
2658
2730
|
|
|
2659
2731
|
// Generated Big Inning schedule (disabled)
|
|
2660
|
-
|
|
2661
|
-
let start = this.convertDateToXMLTV(new Date(big_inning.start))
|
|
2662
|
-
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))
|
|
2663
2735
|
|
|
2664
2736
|
// Big Inning calendar ICS
|
|
2665
2737
|
let prefix = 'Watch'
|
|
@@ -2671,7 +2743,13 @@ class sessionClass {
|
|
|
2671
2743
|
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertDateToAirDate(new Date(this.cache.bigInningSchedule[gameDate].start)))
|
|
2672
2744
|
}
|
|
2673
2745
|
this.debuglog('getTVData completed Big Inning for date ' + cache_data.dates[i].date)
|
|
2674
|
-
}
|
|
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
|
+
|
|
2675
2753
|
this.debuglog('getTVData completed Big Inning')
|
|
2676
2754
|
}
|
|
2677
2755
|
}
|
|
@@ -3030,7 +3108,7 @@ class sessionClass {
|
|
|
3030
3108
|
if ((skip_type == 1) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime) {
|
|
3031
3109
|
action_index = j
|
|
3032
3110
|
// skip type 2 (idle time) will look at all non-idle plays with an endTime
|
|
3033
|
-
} else if ((skip_type == 2) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime && !IDLE_TYPES.some(v => cache_data.liveData.plays.allPlays[i].playEvents[j].details.description.includes(v))) {
|
|
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)))) {
|
|
3034
3112
|
action_index = j
|
|
3035
3113
|
} else if (skip_type == 3) {
|
|
3036
3114
|
// skip type 3 excludes non-action pitches (events that aren't last in the at-bat and don't fall under action types)
|
|
@@ -3385,6 +3463,60 @@ class sessionClass {
|
|
|
3385
3463
|
}
|
|
3386
3464
|
}
|
|
3387
3465
|
|
|
3466
|
+
// Get linear channel stream URL
|
|
3467
|
+
async getLinearStreamURL(network) {
|
|
3468
|
+
try {
|
|
3469
|
+
this.debuglog('getLinearStreamURL')
|
|
3470
|
+
|
|
3471
|
+
let reqObj = {
|
|
3472
|
+
url: GRAPHQL_URL,
|
|
3473
|
+
simple: false,
|
|
3474
|
+
headers: {
|
|
3475
|
+
'accept': 'application/json, text/plain, */*',
|
|
3476
|
+
'accept-encoding': 'gzip, deflate, br',
|
|
3477
|
+
'accept-language': 'en-US,en;q=0.5',
|
|
3478
|
+
'authorization': 'Bearer ' + await this.getLoginToken() || this.halt('missing loginToken'),
|
|
3479
|
+
'connection': 'keep-alive',
|
|
3480
|
+
'content-type': 'application/json',
|
|
3481
|
+
'x-client-name': 'WEB',
|
|
3482
|
+
'x-client-version': '7.8.1',
|
|
3483
|
+
'origin': 'https://www.mlb.com',
|
|
3484
|
+
'referer': 'https://www.mlb.com/',
|
|
3485
|
+
'user-agent': USER_AGENT
|
|
3486
|
+
},
|
|
3487
|
+
body: {
|
|
3488
|
+
'operationName': 'contentCollections',
|
|
3489
|
+
'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 }',
|
|
3490
|
+
'variables': {
|
|
3491
|
+
'categories': network,
|
|
3492
|
+
'limit': '25'
|
|
3493
|
+
}
|
|
3494
|
+
},
|
|
3495
|
+
json: true,
|
|
3496
|
+
gzip: true
|
|
3497
|
+
}
|
|
3498
|
+
var response = await this.httpPost(reqObj)
|
|
3499
|
+
if ( response ) {
|
|
3500
|
+
this.debuglog('getLinearStreamURL response : ' + JSON.stringify(response))
|
|
3501
|
+
if ( response.data && response.data.contentCollections && (response.data.contentCollections.length > 0) && response.data.contentCollections[0].contents ) {
|
|
3502
|
+
for (var i=0; i<response.data.contentCollections[0].contents.length; i++) {
|
|
3503
|
+
try {
|
|
3504
|
+
let streamURL = this.getStreamURL(response.data.contentCollections[0].contents[i].mediaId)
|
|
3505
|
+
if ( streamURL ) {
|
|
3506
|
+
return streamURL
|
|
3507
|
+
}
|
|
3508
|
+
} catch(e) {
|
|
3509
|
+
this.debuglog('getLinearStreamURL getStreamURL error : ' + e.message)
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
this.log('getLinearStreamURL stream url not found')
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
} catch(e) {
|
|
3516
|
+
this.log('getLinearStreamURL error : ' + e.message)
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3388
3520
|
// Get Recap Rundown data
|
|
3389
3521
|
async getRecapRundownData(dateString) {
|
|
3390
3522
|
try {
|
|
@@ -3478,6 +3610,10 @@ class sessionClass {
|
|
|
3478
3610
|
playbackURL = await this.getRecapRundownURL(dateString)
|
|
3479
3611
|
} else if ( eventName.toUpperCase() == 'MLBN' ) {
|
|
3480
3612
|
playbackURL = 'https://falcon.mlbinfra.com/api/v1/linear/mlbn'
|
|
3613
|
+
} else if ( eventName.toUpperCase() == 'SNLA' ) {
|
|
3614
|
+
playbackURL = await this.getLinearStreamURL('SNLA_LIVE')
|
|
3615
|
+
} else if ( eventName.toUpperCase() == 'SNY' ) {
|
|
3616
|
+
playbackURL = await this.getLinearStreamURL('SNY_LIVE')
|
|
3481
3617
|
} else {
|
|
3482
3618
|
playbackURL = await this.getEventURL(eventName)
|
|
3483
3619
|
}
|
|
@@ -4019,7 +4155,7 @@ class sessionClass {
|
|
|
4019
4155
|
|
|
4020
4156
|
if ( !this.temp_cache.gamechanger[id].games ) this.temp_cache.gamechanger[id].games = []
|
|
4021
4157
|
this.temp_cache.gamechanger[id].games.push(best_games)
|
|
4022
|
-
let maxlength = (this.gamechanger_delay + 10) / 10
|
|
4158
|
+
let maxlength = (this.gamechanger_delay + 10 + MLB_GAMECHANGER_PADDING) / 10
|
|
4023
4159
|
while ( this.temp_cache.gamechanger[id].games.length > maxlength ) {
|
|
4024
4160
|
this.temp_cache.gamechanger[id].games.shift()
|
|
4025
4161
|
}
|