mlbserver 2025.4.2 → 2025.4.5
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/README.md +2 -2
- package/index.js +45 -22
- package/package.json +1 -1
- package/session.js +265 -77
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ After launching the server or Docker container, you can access it at http://loca
|
|
|
43
43
|
Basic command line or Docker environment options:
|
|
44
44
|
|
|
45
45
|
```
|
|
46
|
-
--port or -p (primary port to run on; defaults to 9999 if not specified)
|
|
46
|
+
--port or -p (primary port to run on; defaults to 9999 in Docker or if not specified)
|
|
47
47
|
--debug or -d (false if not specified)
|
|
48
48
|
--version or -v (returns package version number)
|
|
49
49
|
--logout or -l (logs out and clears session)
|
|
@@ -74,7 +74,7 @@ Advanced command line or Docker environment options:
|
|
|
74
74
|
|
|
75
75
|
Supports [SWAG](https://docs.linuxserver.io/general/swag/#preset-proxy-confs) using the custom [mlbserver.subfolder.conf](https://github.com/tonywagner/mlbserver/blob/master/mlbserver.subfolder.conf) file.
|
|
76
76
|
|
|
77
|
-
For multiview, the default software encoder is limited by your CPU. You may want to experiment with different ffmpeg hardware encoders. "h264_videotoolbox" is confirmed to work on supported Macs, and "h264_v4l2m2m" is confirmed to work on a Raspberry Pi 4 (and likely other Linux systems) when ffmpeg is compiled with this patch: https://www.raspberrypi.org/forums/viewtopic.php?p=1780625#p1780625
|
|
77
|
+
For multiview, the default software video encoder is limited by your CPU. You may want to experiment with different ffmpeg hardware video encoders. "h264_videotoolbox" is confirmed to work on supported Macs, and "h264_v4l2m2m" is confirmed to work on a Raspberry Pi 4 (and likely other Linux systems) when ffmpeg is compiled with this patch: https://www.raspberrypi.org/forums/viewtopic.php?p=1780625#p1780625
|
|
78
78
|
|
|
79
79
|
More potential hardware encoders are described at https://stackoverflow.com/a/50703794
|
|
80
80
|
|
package/index.js
CHANGED
|
@@ -1564,6 +1564,7 @@ app.get('/', async function(req, res) {
|
|
|
1564
1564
|
var thislink = http_root + '/' + link
|
|
1565
1565
|
|
|
1566
1566
|
let blackouts = {}
|
|
1567
|
+
let pre_post_shows = {}
|
|
1567
1568
|
|
|
1568
1569
|
let currentDate = new Date()
|
|
1569
1570
|
|
|
@@ -1646,6 +1647,13 @@ app.get('/', async function(req, res) {
|
|
|
1646
1647
|
session.debuglog('SNY detect error : ' + e.message)
|
|
1647
1648
|
}
|
|
1648
1649
|
|
|
1650
|
+
if ( cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
|
|
1651
|
+
blackouts = await session.get_blackout_games(cache_data.dates[0].date, true)
|
|
1652
|
+
if ( gameDate >= today ) {
|
|
1653
|
+
pre_post_shows = await session.get_pre_post_shows(cache_data.dates[0].date)
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1649
1657
|
if ( (mediaType == 'MLBTV') && ((level_ids == levels['MLB']) || level_ids.startsWith(levels['MLB'] + ',')) ) {
|
|
1650
1658
|
// Recap Rundown beginning in 2023, disabled because it stopped working
|
|
1651
1659
|
/*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) ) {
|
|
@@ -1661,13 +1669,9 @@ app.get('/', async function(req, res) {
|
|
|
1661
1669
|
body += '</td></tr>' + "\n"
|
|
1662
1670
|
}*/
|
|
1663
1671
|
|
|
1664
|
-
if ( cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
|
|
1665
|
-
blackouts = await session.get_blackout_games(cache_data.dates[0].date, true)
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
1672
|
// Big Inning
|
|
1669
1673
|
var big_inning
|
|
1670
|
-
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') ) {
|
|
1674
|
+
if ( (entitlements.length > 0) && 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') ) {
|
|
1671
1675
|
// Scraped Big Inning schedule
|
|
1672
1676
|
big_inning = await session.getBigInningSchedule(gameDate)
|
|
1673
1677
|
|
|
@@ -2026,9 +2030,16 @@ app.get('/', async function(req, res) {
|
|
|
2026
2030
|
}
|
|
2027
2031
|
}
|
|
2028
2032
|
let station = broadcast.callSign
|
|
2033
|
+
|
|
2034
|
+
if ( pre_post_shows.pregame_shows && pre_post_shows.pregame_shows[broadcast.mediaId] ) {
|
|
2035
|
+
station = '/' + station
|
|
2036
|
+
}
|
|
2037
|
+
if ( pre_post_shows.postgame_shows && pre_post_shows.postgame_shows[broadcast.mediaId] ) {
|
|
2038
|
+
station += '/'
|
|
2039
|
+
}
|
|
2029
2040
|
|
|
2030
2041
|
// display blackout tooltip, if necessary
|
|
2031
|
-
if ( blackouts[gamePk] ) {
|
|
2042
|
+
if ( blackouts[gamePk] && blackouts[gamePk].blackout_feeds && blackouts[gamePk].blackout_feeds.includes(broadcast.mediaId) ) {
|
|
2032
2043
|
body += '<span class="tooltip"><span class="blackout">' + teamabbr + '</span><span class="tooltiptext">' + blackouts[gamePk].blackout_type
|
|
2033
2044
|
if ( blackouts[gamePk].blackout_type != 'Not entitled' ) {
|
|
2034
2045
|
body += ' video blackout until approx. 2.5 hours after the game'
|
|
@@ -2083,7 +2094,7 @@ app.get('/', async function(req, res) {
|
|
|
2083
2094
|
multiviewquerystring += content_protect_b
|
|
2084
2095
|
stationlink = '<a' + fav_style + ' href="' + thislink + querystring + '">' + station + '</a>'
|
|
2085
2096
|
|
|
2086
|
-
if ( blackouts[gamePk] ) {
|
|
2097
|
+
if ( blackouts[gamePk] && blackouts[gamePk].blackout_feeds && blackouts[gamePk].blackout_feeds.includes(broadcast.mediaId) ) {
|
|
2087
2098
|
body += '<span class="blackout">' + stationlink + '</span>'
|
|
2088
2099
|
} else {
|
|
2089
2100
|
body += stationlink
|
|
@@ -2124,7 +2135,7 @@ app.get('/', async function(req, res) {
|
|
|
2124
2135
|
body += '<a' + fav_style + ' href="https://www.youtube.com/watch?v=' + cache_data.dates[0].games[j].content.media.epg[k].items[x].youtube.videoId + '" target="_blank">' + station + '↗</a>'
|
|
2125
2136
|
}*/
|
|
2126
2137
|
} else {
|
|
2127
|
-
if ( blackouts[gamePk] ) {
|
|
2138
|
+
if ( blackouts[gamePk] && blackouts[gamePk].blackout_feeds && blackouts[gamePk].blackout_feeds.includes(broadcast.mediaId) ) {
|
|
2128
2139
|
body += '<s>' + station + '</s>'
|
|
2129
2140
|
} else {
|
|
2130
2141
|
body += station
|
|
@@ -2151,7 +2162,14 @@ app.get('/', async function(req, res) {
|
|
|
2151
2162
|
body += "</table>" + "\n"
|
|
2152
2163
|
|
|
2153
2164
|
if ( (Object.keys(blackouts).length > 0) ) {
|
|
2154
|
-
body += '<span class="tooltip tinytext"><span class="blackout">strikethrough</span> indicates a live blackout or non-entitled
|
|
2165
|
+
body += '<span class="tooltip tinytext"><span class="blackout">strikethrough</span> indicates a live blackout or non-entitled content<span class="tooltiptext">Tap or hover over the team abbreviation to see an estimate of when the blackout will be lifted (officially ~90 minutes, but more likely ~150 minutes or ~2.5 hours after the game ends).</span></span>' + "\n"
|
|
2166
|
+
if ( (Object.keys(pre_post_shows).length > 0) ) {
|
|
2167
|
+
body += '<br/>'
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
if ( (pre_post_shows.pregame_shows && (Object.keys(pre_post_shows.pregame_shows).length > 0)) || (pre_post_shows.postgame_shows && (Object.keys(pre_post_shows.postgame_shows).length > 0)) ) {
|
|
2172
|
+
body += '<span class="tooltip tinytext">/slashes/ indicates a live pre- and/or post-game show<span class="tooltiptext">A /slash before the station indicates a pre-game show; a slash/ after the station indicates a post-game show. Pre- and post-game shows are only available live.</span></span>' + "\n"
|
|
2155
2173
|
if ( argv.free ) {
|
|
2156
2174
|
body += '<br/>'
|
|
2157
2175
|
}
|
|
@@ -2179,7 +2197,7 @@ app.get('/', async function(req, res) {
|
|
|
2179
2197
|
}
|
|
2180
2198
|
body += '</p>' + "\n"
|
|
2181
2199
|
|
|
2182
|
-
body += '<p><span class="tooltip">Audio<span class="tooltiptext">For video streams only: you can manually specifiy which audio track to include. Some media players can accept them all and let you choose. Not all tracks are available for all games, and injected tracks
|
|
2200
|
+
body += '<p><span class="tooltip">Audio<span class="tooltiptext">For video streams only: you can manually specifiy which audio track to include. Some media players can accept them all and let you choose. Not all tracks are available for all games, and injected tracks may not work with skip options below.<br/><br/>If you select "none" for video above, picking an audio track here will make it an audio-only feed that supports the inning start and skip breaks options.</span></span>: '
|
|
2183
2201
|
for (var i = 0; i < VALID_AUDIO_TRACKS.length; i++) {
|
|
2184
2202
|
body += '<button '
|
|
2185
2203
|
if ( audio_track == VALID_AUDIO_TRACKS[i] ) body += 'class="default" '
|
|
@@ -2256,16 +2274,16 @@ app.get('/', async function(req, res) {
|
|
|
2256
2274
|
|
|
2257
2275
|
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"
|
|
2258
2276
|
|
|
2259
|
-
let include_teams = 'ath,
|
|
2260
|
-
if ( session.credentials.fav_teams.length > 0 ) {
|
|
2277
|
+
let include_teams = 'ath,atl'
|
|
2278
|
+
if ( (session.credentials.fav_teams.length > 0) && (session.credentials.fav_teams[0].length > 0) ) {
|
|
2261
2279
|
include_teams = session.credentials.fav_teams.toString()
|
|
2262
2280
|
}
|
|
2263
2281
|
body += '<p><span class="tooltip">By team<span class="tooltiptext">Including a team (MLB only, by abbreviation, in a comma-separated list if more than 1) will include all of its broadcasts, or if that team is not broadcasting the game, it will include the national broadcast or opponent\'s broadcast if available. 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 + '&includeTeams=' + include_teams + content_protect_b + '">channels.m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + content_protect_b + '">guide.xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=' + include_teams + content_protect_b + '">calendar.ics</a></p>' + "\n"
|
|
2264
2282
|
|
|
2265
2283
|
body += '<p><span class="tooltip">Include blackouts<span class="tooltiptext">An optional parameter added to the URL will include channels/games subject to blackout (although you may not be able to play those games).</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=' + include_teams + '&includeBlackouts=true' + content_protect_b + '">channels.m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&includeBlackouts=true' + content_protect_b + '">guide.xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&includeBlackouts=true' + content_protect_b + '">calendar.ics</a></p>' + "\n"
|
|
2266
2284
|
|
|
2267
|
-
let exclude_teams = 'ath,
|
|
2268
|
-
body += '<p><span class="tooltip">Exclude a team
|
|
2285
|
+
let exclude_teams = 'ath,atl'
|
|
2286
|
+
body += '<p><span class="tooltip">Exclude a team<span class="tooltiptext">Excluding a team (MLB only, by abbreviation, in a comma-separated list if more than 1) will exclude every game involving that team. Note that blackouts are already excluded without the need to specify this parameter.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&excludeTeams=' + exclude_teams + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&excludeTeams=' + exclude_teams + content_protect_b + '">xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&excludeTeams=' + exclude_teams + content_protect_b + '">ics</a></p>' + "\n"
|
|
2269
2287
|
|
|
2270
2288
|
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"
|
|
2271
2289
|
|
|
@@ -2299,7 +2317,9 @@ app.get('/', async function(req, res) {
|
|
|
2299
2317
|
|
|
2300
2318
|
body += '<p><span class="tooltip">Include by level<span class="tooltiptext">Including a level (AAA, AA, A+ encoded as A%2B, or A, in a comma-separated list if more than 1) will include all of its broadcasts, and exclude all other levels.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeLevels=a%2B,aaa' + content_protect_b + '">m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeLevels=a%2B,aaa' + content_protect_b + '">xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeLevels=a%2B,aaa' + content_protect_b + '">ics</a></p>' + "\n"
|
|
2301
2319
|
|
|
2302
|
-
body += '<p><span class="tooltip">Include teams in titles<span class="tooltiptext">An optional parameter added to the URL will include team names in the ICS/XML titles
|
|
2320
|
+
body += '<p><span class="tooltip">Include teams in titles<span class="tooltiptext">An optional parameter added to the URL will include team names in the ICS/XML titles. A value of "channels" will format the titles in the style of the <a href="https://community.getchannels.com/t/mlb-tv-for-channels/27492">legacy Channels container</a>.</span></span>: <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&includeTeamsInTitles=true' + content_protect_b + '">guide.xml</a> or <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&includeTeamsInTitles=channels' + content_protect_b + '">legacy</a>, and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&includeTeamsInTitles=true' + content_protect_b + '">calendar.ics</a></p>' + "\n"
|
|
2321
|
+
|
|
2322
|
+
body += '<p><span class="tooltip">Create Off Air events between games<span class="tooltiptext">An optional parameter added to the URL will create "Off Air" events in the XML guide, listing the time of the next game on that channel. A value of "channels" will format the events in the style of the <a href="https://community.getchannels.com/t/mlb-tv-for-channels/27492">legacy Channels container</a>.</span></span>: <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&offAir=true' + content_protect_b + '">guide.xml</a> or <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&offAir=channels' + content_protect_b + '">legacy</a></p>' + "\n"
|
|
2303
2323
|
|
|
2304
2324
|
body += '</td></tr></table><br/>' + "\n"
|
|
2305
2325
|
|
|
@@ -2319,10 +2339,7 @@ app.get('/', async function(req, res) {
|
|
|
2319
2339
|
['Team live radio', '?team=' + example_team + '&mediaType=Audio'],
|
|
2320
2340
|
['Catch-up/condensed', '?team=' + example_team + '&resolution=best&skip=pitches&date=today'],
|
|
2321
2341
|
['Condensed yesterday', '?team=' + example_team + '&resolution=best&skip=pitches&date=yesterday'],
|
|
2322
|
-
['Same but DH game 2', '?team=' + example_team + '&resolution=best&skip=pitches&date=yesterday&game=2']
|
|
2323
|
-
['Nat\'l game 1 today', '?team=NATIONAL.1&resolution=best&date=today'],
|
|
2324
|
-
['Same but incl. blackouts', '?team=NATIONAL.1&resolution=best&includeBlackouts=true'],
|
|
2325
|
-
['Nat\'l game 2 yesterday', '?team=NATIONAL.2&resolution=best&date=yesterday']
|
|
2342
|
+
['Same but DH game 2', '?team=' + example_team + '&resolution=best&skip=pitches&date=yesterday&game=2']
|
|
2326
2343
|
]
|
|
2327
2344
|
|
|
2328
2345
|
if ( argv.free ) {
|
|
@@ -2348,12 +2365,13 @@ app.get('/', async function(req, res) {
|
|
|
2348
2365
|
}
|
|
2349
2366
|
body += '</p>' + "\n"
|
|
2350
2367
|
|
|
2368
|
+
include_teams = 'ath,atl'
|
|
2351
2369
|
body += '<p><span class="tooltip">Game Changer by team examples<span class="tooltiptext">Game Changer supports specifying certain teams to include or exclude. Useful for following a group of teams.</span></span>:</p>' + "\n"
|
|
2352
2370
|
body += '<p>' + "\n"
|
|
2353
2371
|
let gamechanger_streamURL = server + '/gamechanger.m3u8?resolution=best' + content_protect_b
|
|
2354
2372
|
let gamechanger_types = ['in', 'ex']
|
|
2355
2373
|
for (var i=0; i<gamechanger_types.length; i++) {
|
|
2356
|
-
let example_streamURL = gamechanger_streamURL + '&' + gamechanger_types[i] + 'cludeTeams=
|
|
2374
|
+
let example_streamURL = gamechanger_streamURL + '&' + gamechanger_types[i] + 'cludeTeams=' + include_teams
|
|
2357
2375
|
body += '• ' + gamechanger_types[i] + 'clude: <a href="' + http_root + '/embed.html?src=' + encodeURIComponent(example_streamURL) + '&startFrom=' + VALID_START_FROM[1] + content_protect_b + '">Embed</a> | <a href="' + example_streamURL + '">Stream</a> | <a href="' + http_root + '/chromecast.html?src=' + encodeURIComponent(example_streamURL) + content_protect_b + '">Chromecast</a> | <a href="' + http_root + '/advanced.html?src=' + encodeURIComponent(example_streamURL) + content_protect_b + '">Advanced</a> | <a href="' + http_root + '/kodi.strm?src=' + encodeURIComponent(example_streamURL) + content_protect_b + '">Kodi</a><br/>' + "\n"
|
|
2358
2376
|
}
|
|
2359
2377
|
|
|
@@ -2571,7 +2589,7 @@ app.get('/channels.m3u', async function(req, res) {
|
|
|
2571
2589
|
includeOrgs = req.query.includeOrgs.toUpperCase().split(',')
|
|
2572
2590
|
}
|
|
2573
2591
|
|
|
2574
|
-
var body = await session.getTVData('channels', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, 'false', resolution, pipe, startingChannelNumber)
|
|
2592
|
+
var body = await session.getTVData('channels', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, 'false', 'false', resolution, pipe, startingChannelNumber)
|
|
2575
2593
|
|
|
2576
2594
|
res.writeHead(200, {'Content-Type': 'audio/x-mpegurl'})
|
|
2577
2595
|
res.end(body)
|
|
@@ -2671,9 +2689,14 @@ app.get('/guide.xml', async function(req, res) {
|
|
|
2671
2689
|
includeTeamsInTitles = req.query.includeTeamsInTitles
|
|
2672
2690
|
}
|
|
2673
2691
|
|
|
2692
|
+
let offAir = 'false'
|
|
2693
|
+
if ( req.query.offAir ) {
|
|
2694
|
+
offAir = req.query.offAir
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2674
2697
|
let server = (req.headers['x-forwarded-proto'] ? req.headers['x-forwarded-proto'] : 'http') + '://' + req.headers.host + http_root
|
|
2675
2698
|
|
|
2676
|
-
var body = await session.getTVData('guide', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles)
|
|
2699
|
+
var body = await session.getTVData('guide', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles, offAir)
|
|
2677
2700
|
|
|
2678
2701
|
res.end(body)
|
|
2679
2702
|
})
|
package/package.json
CHANGED
package/session.js
CHANGED
|
@@ -34,6 +34,8 @@ const AFL_ID = '119'
|
|
|
34
34
|
const LIDOM_ID = '131'
|
|
35
35
|
const WINTER_LEAGUES = [AFL_ID, LIDOM_ID]
|
|
36
36
|
|
|
37
|
+
const OFF_AIR_LOGO = 'https://lh3.googleusercontent.com/uVJBX-jpgwHsDY_o6-po2JU5-cDZuoq_CsCcqJ0-T7996z8NbOzeQCfQaAG0DB2hbkxv2VvtZ2E'
|
|
38
|
+
|
|
37
39
|
// These are the events to ignore, if we're skipping breaks
|
|
38
40
|
const BREAK_TYPES = ['Game Advisory', 'Pitching Substitution', 'Offensive Substitution', 'Defensive Sub', 'Defensive Switch', 'Runner Placed On Base']
|
|
39
41
|
// These are the events to keep, in addition to the last event of each at-bat, if we're skipping pitches
|
|
@@ -44,10 +46,10 @@ const EVENT_START_PADDING = -3
|
|
|
44
46
|
const PITCH_END_PADDING = 2
|
|
45
47
|
const ACTION_END_PADDING = 7
|
|
46
48
|
const MINIMUM_BREAK_DURATION = 5
|
|
47
|
-
// extra padding for MLB events
|
|
48
|
-
const MLB_PADDING =
|
|
49
|
-
// extra Game Changer padding for MLB
|
|
50
|
-
const MLB_GAMECHANGER_PADDING =
|
|
49
|
+
// hardcode extra padding for MLB events
|
|
50
|
+
const MLB_PADDING = 2
|
|
51
|
+
// hardcode extra Game Changer padding for MLB, in 10-second increments as needed
|
|
52
|
+
const MLB_GAMECHANGER_PADDING = 0
|
|
51
53
|
|
|
52
54
|
const LI_TABLE = {
|
|
53
55
|
1: {
|
|
@@ -2158,7 +2160,7 @@ class sessionClass {
|
|
|
2158
2160
|
}
|
|
2159
2161
|
|
|
2160
2162
|
// get TV data (channels or guide)
|
|
2161
|
-
async getTVData(dataType, mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles='false', resolution='best', pipe='false', startingChannelNumber=1) {
|
|
2163
|
+
async getTVData(dataType, mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles='false', offAir='false', resolution='best', pipe='false', startingChannelNumber=1) {
|
|
2162
2164
|
try {
|
|
2163
2165
|
this.debuglog('getTVData for ' + dataType)
|
|
2164
2166
|
|
|
@@ -2247,6 +2249,8 @@ class sessionClass {
|
|
|
2247
2249
|
|
|
2248
2250
|
let blackouts = {}
|
|
2249
2251
|
if ( includeBlackouts == 'false' ) blackouts = await this.get_blackout_games()
|
|
2252
|
+
|
|
2253
|
+
let pre_post_shows = await this.get_pre_post_shows()
|
|
2250
2254
|
|
|
2251
2255
|
for (var i = 0; i < cache_data.dates.length; i++) {
|
|
2252
2256
|
this.debuglog('getTVData processing date ' + cache_data.dates[i].date)
|
|
@@ -2301,29 +2305,35 @@ class sessionClass {
|
|
|
2301
2305
|
stream += '&resolution=' + resolution
|
|
2302
2306
|
if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
|
|
2303
2307
|
if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
|
|
2304
|
-
channels[channelid]
|
|
2308
|
+
if ( !channels[channelid] ) {
|
|
2309
|
+
channels[channelid] = await this.create_channel_object(channelid, logo, stream, mediaType)
|
|
2310
|
+
}
|
|
2305
2311
|
|
|
2306
2312
|
let title = 'Minor League Baseball'
|
|
2307
2313
|
if ( WINTER_LEAGUES.includes(league_id.toString()) ) {
|
|
2308
2314
|
title = cache_data.dates[i].games[j].teams['home'].team.league.name
|
|
2309
2315
|
}
|
|
2310
2316
|
|
|
2311
|
-
let away_team = cache_data.dates[i].games[j].teams['away'].team.
|
|
2312
|
-
let home_team = cache_data.dates[i].games[j].teams['home'].team.
|
|
2317
|
+
let away_team = cache_data.dates[i].games[j].teams['away'].team.shortName
|
|
2318
|
+
let home_team = cache_data.dates[i].games[j].teams['home'].team.shortName
|
|
2313
2319
|
let subtitle = away_team + ' at ' + home_team
|
|
2314
|
-
|
|
2315
|
-
if (includeTeamsInTitles
|
|
2316
|
-
if (
|
|
2317
|
-
title =
|
|
2318
|
-
} else if ( league_id == LIDOM_ID ) {
|
|
2319
|
-
title = 'LIDOM'
|
|
2320
|
+
|
|
2321
|
+
if ( includeTeamsInTitles != 'false' ) {
|
|
2322
|
+
if ( includeTeamsInTitles == 'channels' ) {
|
|
2323
|
+
title = this.channelsFormattedTitle(subtitle, cache_data.dates[i].games[j].gameDate)
|
|
2320
2324
|
} else {
|
|
2321
|
-
|
|
2325
|
+
if ( league_id == AFL_ID ) {
|
|
2326
|
+
title = 'AFL'
|
|
2327
|
+
} else if ( league_id == LIDOM_ID ) {
|
|
2328
|
+
title = 'LIDOM'
|
|
2329
|
+
} else {
|
|
2330
|
+
title = 'MiLB'
|
|
2331
|
+
}
|
|
2332
|
+
title += ': ' + subtitle
|
|
2322
2333
|
}
|
|
2323
|
-
title += ': ' + subtitle
|
|
2324
2334
|
}
|
|
2325
2335
|
|
|
2326
|
-
let description = cache_data.dates[i].games[j].teams['home'].team.league.name + '. '
|
|
2336
|
+
let description = cache_data.dates[i].games[j].teams['home'].team.sport.name + ' ' + cache_data.dates[i].games[j].teams['home'].team.league.name + '. '
|
|
2327
2337
|
if ( cache_data.dates[i].games[j].seriesDescription != 'Regular Season' ) {
|
|
2328
2338
|
description += cache_data.dates[i].games[j].seriesDescription + '. '
|
|
2329
2339
|
}
|
|
@@ -2334,6 +2344,9 @@ class sessionClass {
|
|
|
2334
2344
|
if ( scheduledInnings != '9' ) {
|
|
2335
2345
|
description += scheduledInnings + '-inning game. '
|
|
2336
2346
|
}
|
|
2347
|
+
if ( cache_data.dates[i].games[j].teams['away'].team.parentOrgName && cache_data.dates[i].games[j].teams['home'].team.parentOrgName ) {
|
|
2348
|
+
description += cache_data.dates[i].games[j].teams['away'].team.name + ' (' + this.getParent(cache_data.dates[i].games[j].teams['away'].team.parentOrgName) + ') at ' + cache_data.dates[i].games[j].teams['home'].team.name + ' (' + this.getParent(cache_data.dates[i].games[j].teams['home'].team.parentOrgName) + '). '
|
|
2349
|
+
}
|
|
2337
2350
|
if ( (cache_data.dates[i].games[j].teams['away'].probablePitcher && cache_data.dates[i].games[j].teams['away'].probablePitcher.fullName) || (cache_data.dates[i].games[j].teams['home'].probablePitcher && cache_data.dates[i].games[j].teams['home'].probablePitcher.fullName) ) {
|
|
2338
2351
|
if ( cache_data.dates[i].games[j].teams['away'].probablePitcher && cache_data.dates[i].games[j].teams['away'].probablePitcher.fullName ) {
|
|
2339
2352
|
description += cache_data.dates[i].games[j].teams['away'].probablePitcher.fullName
|
|
@@ -2380,21 +2393,22 @@ class sessionClass {
|
|
|
2380
2393
|
let location = server + '/embed.html?team=' + encodeURIComponent(team) + '&mediaType=' + streamMediaType
|
|
2381
2394
|
if ( this.protection.content_protect ) location += '&content_protect=' + this.protection.content_protect
|
|
2382
2395
|
calendar += await this.generate_ics_event(prefix, calendar_start, calendar_stop, subtitle, description, location)
|
|
2396
|
+
|
|
2397
|
+
// Off Air if necessary
|
|
2398
|
+
let off_air_event = await this.generate_off_air_event(offAir, channelid, cache_data.dates[i].date, channels[channelid].stop, cache_data.dates[i].games[j].gameDate, cache_data.dates[i].games[j].teams['away'].team.shortName + ' at ' + cache_data.dates[i].games[j].teams['home'].team.shortName)
|
|
2399
|
+
if ( off_air_event ) {
|
|
2400
|
+
programs += off_air_event
|
|
2401
|
+
channels[channelid].stop = stop
|
|
2402
|
+
}
|
|
2383
2403
|
|
|
2384
2404
|
// MILB guide XML
|
|
2385
|
-
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertDateToAirDate(gameDate), subtitle, team_id, cache_data.dates[i].games[j].gamePk, away_team, home_team)
|
|
2405
|
+
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertDateToAirDate(new Date(cache_data.dates[i].games[j].gameDate)), subtitle, team_id, cache_data.dates[i].games[j].gamePk, away_team, home_team)
|
|
2386
2406
|
|
|
2387
2407
|
//break
|
|
2388
2408
|
//}
|
|
2389
2409
|
}
|
|
2390
2410
|
} else {
|
|
2391
2411
|
// Begin MLB games
|
|
2392
|
-
// check blackout status, if necessary
|
|
2393
|
-
let gamePk = cache_data.dates[i].games[j].gamePk.toString()
|
|
2394
|
-
if ( (mediaType == 'MLBTV') && (includeBlackouts == 'false') && blackouts[gamePk] ) {
|
|
2395
|
-
continue
|
|
2396
|
-
}
|
|
2397
|
-
|
|
2398
2412
|
if ( cache_data.dates[i].games[j].broadcasts ) {
|
|
2399
2413
|
// initial loop will count number of broadcasts
|
|
2400
2414
|
let broadcast_count = await this.count_broadcasts(cache_data.dates[i].games[j].broadcasts, mediaType, language)
|
|
@@ -2404,10 +2418,14 @@ class sessionClass {
|
|
|
2404
2418
|
let mediaTitle = 'Audio'
|
|
2405
2419
|
if ( broadcast.type == 'TV' ) {
|
|
2406
2420
|
mediaTitle = 'MLBTV'
|
|
2407
|
-
} else if ( broadcast.language == 'es' ) {
|
|
2408
|
-
mediaTitle = 'Spanish'
|
|
2409
2421
|
}
|
|
2410
2422
|
if ( mediaType == mediaTitle ) {
|
|
2423
|
+
|
|
2424
|
+
// check blackout or non-entitlement status, if necessary
|
|
2425
|
+
let gamePk = cache_data.dates[i].games[j].gamePk.toString()
|
|
2426
|
+
if ( (includeBlackouts == 'false') && blackouts[gamePk] && blackouts[gamePk].blackout_feeds && blackouts[gamePk].blackout_feeds.includes(broadcast.mediaId) ) {
|
|
2427
|
+
continue
|
|
2428
|
+
}
|
|
2411
2429
|
|
|
2412
2430
|
if ( (broadcast.type == 'TV') || ((mediaType == 'Audio') && (broadcast.language == language)) ) {
|
|
2413
2431
|
let teamType = broadcast.homeAway
|
|
@@ -2486,13 +2504,17 @@ class sessionClass {
|
|
|
2486
2504
|
//logo += '/image.svg?teamId=MLB'
|
|
2487
2505
|
//if ( this.protection.content_protect ) logo += '&content_protect=' + this.protection.content_protect
|
|
2488
2506
|
logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA'
|
|
2489
|
-
nationalChannels[channelid]
|
|
2507
|
+
if ( !nationalChannels[channelid] ) {
|
|
2508
|
+
nationalChannels[channelid] = await this.create_channel_object(channelid, logo, stream, channelMediaType)
|
|
2509
|
+
}
|
|
2490
2510
|
} else {
|
|
2491
2511
|
seriesId = cache_data.dates[i].games[j].teams[teamType].team.id
|
|
2492
2512
|
//logo += '/image.svg?teamId=' + cache_data.dates[i].games[j].teams[teamType].team.id
|
|
2493
2513
|
//if ( this.protection.content_protect ) logo += '&content_protect=' + this.protection.content_protect
|
|
2494
2514
|
logo = 'https://www.mlbstatic.com/team-logos/share/' + cache_data.dates[i].games[j].teams[teamType].team.id + '.jpg'
|
|
2495
|
-
channels[channelid]
|
|
2515
|
+
if ( !channels[channelid] ) {
|
|
2516
|
+
channels[channelid] = await this.create_channel_object(channelid, logo, stream, channelMediaType)
|
|
2517
|
+
}
|
|
2496
2518
|
}
|
|
2497
2519
|
|
|
2498
2520
|
let title = 'MLB Baseball'
|
|
@@ -2501,15 +2523,19 @@ class sessionClass {
|
|
|
2501
2523
|
let home_team = cache_data.dates[i].games[j].teams['home'].team.teamName
|
|
2502
2524
|
let subtitle = away_team + ' at ' + home_team
|
|
2503
2525
|
|
|
2504
|
-
if (includeTeamsInTitles
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2526
|
+
if (includeTeamsInTitles != 'false') {
|
|
2527
|
+
if ( includeTeamsInTitles == 'channels' ) {
|
|
2528
|
+
title = this.channelsFormattedTitle(subtitle, cache_data.dates[i].games[j].gameDate)
|
|
2529
|
+
} else {
|
|
2530
|
+
title = 'MLB: ' + subtitle + ' (' + station
|
|
2531
|
+
if ( language == 'es' ) {
|
|
2532
|
+
title += ' Spanish'
|
|
2533
|
+
}
|
|
2534
|
+
if ( mediaType == 'Audio' ) {
|
|
2535
|
+
title += ' Radio'
|
|
2536
|
+
}
|
|
2537
|
+
title += ')'
|
|
2511
2538
|
}
|
|
2512
|
-
title += ')'
|
|
2513
2539
|
}
|
|
2514
2540
|
|
|
2515
2541
|
let description = station
|
|
@@ -2585,7 +2611,42 @@ class sessionClass {
|
|
|
2585
2611
|
calendar += await this.generate_ics_event(prefix, calendar_start, calendar_stop, subtitle, description, location)
|
|
2586
2612
|
|
|
2587
2613
|
// MLB guide XML
|
|
2588
|
-
programs += await this.generate_xml_program(channelid, start, stop, title, description, icon, this.convertDateToAirDate(gameDate), subtitle, seriesId, cache_data.dates[i].games[j].gamePk, away_team, home_team)
|
|
2614
|
+
programs += await this.generate_xml_program(channelid, start, stop, title, description, icon, this.convertDateToAirDate(new Date(cache_data.dates[i].games[j].gameDate)), subtitle, seriesId, cache_data.dates[i].games[j].gamePk, away_team, home_team)
|
|
2615
|
+
|
|
2616
|
+
// pre- and post-game shows
|
|
2617
|
+
if ( pre_post_shows.pregame_shows[broadcast.mediaId] || pre_post_shows.postgame_shows[broadcast.mediaId] ) {
|
|
2618
|
+
if ( (pre_post_shows.pregame_shows[broadcast.mediaId] && (pre_post_shows.pregame_shows[broadcast.mediaId].team == 'home')) || (pre_post_shows.postgame_shows[broadcast.mediaId] && (pre_post_shows.postgame_shows[broadcast.mediaId].team == 'home')) ) {
|
|
2619
|
+
away_team = false
|
|
2620
|
+
} else {
|
|
2621
|
+
home_team = false
|
|
2622
|
+
}
|
|
2623
|
+
// pre-game
|
|
2624
|
+
if ( pre_post_shows.pregame_shows[broadcast.mediaId] ) {
|
|
2625
|
+
let pre_start = this.convertDateToXMLTV(new Date(pre_post_shows.pregame_shows[broadcast.mediaId].start))
|
|
2626
|
+
title = cache_data.dates[i].games[j].teams[pre_post_shows.pregame_shows[broadcast.mediaId].team].team.teamName + ' Pregame'
|
|
2627
|
+
let preSeriesId = seriesId + '1'
|
|
2628
|
+
programs += await this.generate_xml_program(channelid, pre_start, start, title, '', icon, this.convertDateToAirDate(new Date(pre_post_shows.pregame_shows[broadcast.mediaId].start)), '', preSeriesId, cache_data.dates[i].games[j].gamePk, away_team, home_team)
|
|
2629
|
+
start = pre_start
|
|
2630
|
+
}
|
|
2631
|
+
// post-game
|
|
2632
|
+
if ( pre_post_shows.postgame_shows[broadcast.mediaId] ) {
|
|
2633
|
+
let postgameMinutes = 30
|
|
2634
|
+
let startDate = stopDate
|
|
2635
|
+
stopDate.setMinutes(stopDate.getMinutes()+postgameMinutes)
|
|
2636
|
+
let post_stop = this.convertDateToXMLTV(stopDate)
|
|
2637
|
+
title = cache_data.dates[i].games[j].teams[pre_post_shows.postgame_shows[broadcast.mediaId].team].team.teamName + ' Postgame'
|
|
2638
|
+
let postSeriesId = seriesId + '2'
|
|
2639
|
+
programs += await this.generate_xml_program(channelid, stop, post_stop, title, '', icon, this.convertDateToAirDate(startDate), '', postSeriesId, cache_data.dates[i].games[j].gamePk, away_team, home_team)
|
|
2640
|
+
stop = post_stop
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
// Off Air if necessary
|
|
2645
|
+
let off_air_event = await this.generate_off_air_event(offAir, channelid, cache_data.dates[i].date, channels[channelid].stop, cache_data.dates[i].games[j].gameDate, subtitle)
|
|
2646
|
+
if ( off_air_event ) {
|
|
2647
|
+
programs += off_air_event
|
|
2648
|
+
channels[channelid].stop = stop
|
|
2649
|
+
}
|
|
2589
2650
|
}
|
|
2590
2651
|
}
|
|
2591
2652
|
}
|
|
@@ -2599,7 +2660,6 @@ class sessionClass {
|
|
|
2599
2660
|
}
|
|
2600
2661
|
channels = this.sortObj(channels)
|
|
2601
2662
|
channels = Object.assign(channels, nationalChannels)
|
|
2602
|
-
|
|
2603
2663
|
|
|
2604
2664
|
let entitlements = await this.getEntitlements()
|
|
2605
2665
|
// MLB Network live stream for eligible USA subscribers
|
|
@@ -2699,7 +2759,7 @@ class sessionClass {
|
|
|
2699
2759
|
}
|
|
2700
2760
|
|
|
2701
2761
|
// Big Inning
|
|
2702
|
-
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2762
|
+
if ( (entitlements.length > 0) && (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2703
2763
|
if ( (excludeTeams.length > 0) && excludeTeams.includes('BIGINNING') ) {
|
|
2704
2764
|
// do nothing
|
|
2705
2765
|
} else if ( (includeTeams.length == 0) || includeTeams.includes('BIGINNING') ) {
|
|
@@ -2733,6 +2793,13 @@ class sessionClass {
|
|
|
2733
2793
|
let location = server + '/embed.html?event=biginning&mediaType=Video&resolution=' + resolution
|
|
2734
2794
|
if ( this.protection.content_protect ) location += '&content_protect=' + this.protection.content_protect
|
|
2735
2795
|
calendar += await this.generate_ics_event(prefix, new Date(this.cache.bigInningSchedule[gameDate].start), new Date(this.cache.bigInningSchedule[gameDate].end), title, description, location)
|
|
2796
|
+
|
|
2797
|
+
// Off Air if necessary
|
|
2798
|
+
let off_air_event = await this.generate_off_air_event(offAir, channelid, gameDate, channels[channelid].stop, this.cache.bigInningSchedule[gameDate].start, title)
|
|
2799
|
+
if ( off_air_event ) {
|
|
2800
|
+
programs += off_air_event
|
|
2801
|
+
channels[channelid].stop = stop
|
|
2802
|
+
}
|
|
2736
2803
|
|
|
2737
2804
|
// Big Inning guide XML
|
|
2738
2805
|
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertDateToAirDate(new Date(this.cache.bigInningSchedule[gameDate].start)))
|
|
@@ -2750,7 +2817,7 @@ class sessionClass {
|
|
|
2750
2817
|
}
|
|
2751
2818
|
|
|
2752
2819
|
// Game Changer
|
|
2753
|
-
if ( (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2820
|
+
if ( (entitlements.length > 0) && (mediaType == 'MLBTV') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2754
2821
|
if ( (excludeTeams.length > 0) && excludeTeams.includes('GAMECHANGER') ) {
|
|
2755
2822
|
// do nothing
|
|
2756
2823
|
} else if ( (includeTeams.length == 0) || includeTeams.includes('GAMECHANGER') ) {
|
|
@@ -2785,6 +2852,13 @@ class sessionClass {
|
|
|
2785
2852
|
let location = server + '/embed.html?src=' + encodeURIComponent(stream)
|
|
2786
2853
|
if ( this.protection.content_protect ) location += '&content_protect=' + this.protection.content_protect
|
|
2787
2854
|
calendar += await this.generate_ics_event(prefix, new Date(cache_data.dates[i].games[gameIndexes.firstGameIndex].gameDate), gameDate, title, description, location)
|
|
2855
|
+
|
|
2856
|
+
// Off Air if necessary
|
|
2857
|
+
let off_air_event = await this.generate_off_air_event(offAir, channelid, cache_data.dates[i].date, channels[channelid].stop, cache_data.dates[i].games[gameIndexes.firstGameIndex].gameDate, title)
|
|
2858
|
+
if ( off_air_event ) {
|
|
2859
|
+
programs += off_air_event
|
|
2860
|
+
channels[channelid].stop = stop
|
|
2861
|
+
}
|
|
2788
2862
|
|
|
2789
2863
|
// Game Changer guide XML
|
|
2790
2864
|
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertDateToAirDate(gameDate))
|
|
@@ -2797,7 +2871,7 @@ class sessionClass {
|
|
|
2797
2871
|
}
|
|
2798
2872
|
|
|
2799
2873
|
// Multiview
|
|
2800
|
-
if ( (mediaType == 'MLBTV') && (typeof this.data.multiviewStreamURLPath !== 'undefined') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2874
|
+
if ( (entitlements.length > 0) && (mediaType == 'MLBTV') && (typeof this.data.multiviewStreamURLPath !== 'undefined') && ((includeLevels.length == 0) || includeLevels.includes('MLB') || includeLevels.includes('ALL')) ) {
|
|
2801
2875
|
if ( (excludeTeams.length > 0) && excludeTeams.includes('MULTIVIEW') ) {
|
|
2802
2876
|
// do nothing
|
|
2803
2877
|
} else if ( (includeTeams.length == 0) || includeTeams.includes('MULTIVIEW') ) {
|
|
@@ -2831,6 +2905,13 @@ class sessionClass {
|
|
|
2831
2905
|
let prefix = 'Watch'
|
|
2832
2906
|
let location = stream.replace('/stream.m3u8?src=', '/embed.html?msrc=')
|
|
2833
2907
|
calendar += await this.generate_ics_event(prefix, new Date(cache_data.dates[i].games[gameIndexes.firstGameIndex].gameDate), gameDate, title, description, location)
|
|
2908
|
+
|
|
2909
|
+
// Off Air if necessary
|
|
2910
|
+
let off_air_event = await this.generate_off_air_event(offAir, channelid, cache_data.dates[i].date, channels[channelid].stop, cache_data.dates[i].games[gameIndexes.firstGameIndex].gameDate, title)
|
|
2911
|
+
if ( off_air_event ) {
|
|
2912
|
+
programs += off_air_event
|
|
2913
|
+
channels[channelid].stop = stop
|
|
2914
|
+
}
|
|
2834
2915
|
|
|
2835
2916
|
// Multview guide XML
|
|
2836
2917
|
programs += await this.generate_xml_program(channelid, start, stop, title, description, logo, this.convertDateToAirDate(gameDate))
|
|
@@ -2841,7 +2922,7 @@ class sessionClass {
|
|
|
2841
2922
|
this.debuglog('getTVData completed Multiview')
|
|
2842
2923
|
}
|
|
2843
2924
|
}
|
|
2844
|
-
|
|
2925
|
+
}
|
|
2845
2926
|
} catch(e) {
|
|
2846
2927
|
this.log('getTVData processing error : ' + e.message)
|
|
2847
2928
|
}
|
|
@@ -3659,40 +3740,57 @@ class sessionClass {
|
|
|
3659
3740
|
|
|
3660
3741
|
let cache_data
|
|
3661
3742
|
cache_data = await this.getBlackoutsData(gameDate)
|
|
3743
|
+
|
|
3744
|
+
let feedTypes = ['videoFeeds', 'audioFeeds']
|
|
3662
3745
|
|
|
3663
3746
|
if ( cache_data && cache_data.results && (cache_data.results.length > 0) ) {
|
|
3664
|
-
for (var
|
|
3665
|
-
let game = cache_data.results[
|
|
3747
|
+
for (var i = 0; i < cache_data.results.length; i++) {
|
|
3748
|
+
let game = cache_data.results[i]
|
|
3666
3749
|
let game_pk = game.gamePk
|
|
3667
3750
|
this.debuglog('get_blackout_games checking game ' + game_pk)
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
this.debuglog('get_blackout_games found national blackout')
|
|
3673
|
-
blackout_type = 'National/International'
|
|
3674
|
-
} else if ( game.videoStatusCodes.includes(1) ) {
|
|
3675
|
-
this.debuglog('get_blackout_games found local blackout')
|
|
3676
|
-
blackout_type = 'Local'
|
|
3677
|
-
} else {
|
|
3678
|
-
this.debuglog('get_blackout_games found non-entitled video')
|
|
3751
|
+
let blackout_type = ''
|
|
3752
|
+
if ( game.blackedOutVideo || !game.entitledVideo || !game.entitledAudio ) {
|
|
3753
|
+
if ( !game.entitledVideo || !game.entitledAudio ) {
|
|
3754
|
+
this.debuglog('get_blackout_games found non-entitled game ' + game_pk)
|
|
3679
3755
|
blackout_type = 'Not entitled'
|
|
3756
|
+
} else {
|
|
3757
|
+
this.debuglog('get_blackout_games found blackout game ' + game_pk)
|
|
3680
3758
|
}
|
|
3681
|
-
blackouts[game_pk] = { blackout_type: blackout_type }
|
|
3682
|
-
}
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3759
|
+
blackouts[game_pk] = { blackout_type: blackout_type }
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3762
|
+
let blackout_feeds = []
|
|
3763
|
+
for (var j = 0; j < feedTypes.length; j++) {
|
|
3764
|
+
let feedType = feedTypes[j]
|
|
3765
|
+
for (var k = 0; k < game[feedType].length; k++) {
|
|
3766
|
+
let feed = game[feedType][k]
|
|
3767
|
+
if ( !feed.entitled || ((j == 0) && feed.blackedOut) ) {
|
|
3768
|
+
blackout_feeds.push(feed['mediaId'])
|
|
3769
|
+
if ( !feed['entitled'] ) {
|
|
3770
|
+
this.debuglog('get_blackout_games found non-entitled feed ' + feed.callLetters)
|
|
3771
|
+
blackout_type = 'Not entitled'
|
|
3772
|
+
} else {
|
|
3773
|
+
this.debuglog('get_blackout_games found blackout feed ' + feed.callLetters)
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
if ( blackout_feeds.length > 0 ) {
|
|
3779
|
+
if ( !blackouts[game_pk] ) {
|
|
3780
|
+
blackouts[game_pk] = { blackout_type: blackout_type }
|
|
3781
|
+
}
|
|
3782
|
+
blackouts[game_pk].blackout_feeds = blackout_feeds
|
|
3783
|
+
}
|
|
3784
|
+
|
|
3687
3785
|
// add blackout expiry, if requested
|
|
3688
3786
|
if ( blackouts[game_pk] && (blackouts[game_pk].blackout_type != 'Not entitled') && calculate_expiries && await this.check_game_time(game.gameData) ) {
|
|
3689
3787
|
this.debuglog('get_blackout_games calculating blackout expiry')
|
|
3690
3788
|
let date_cache_data = await this.getDayData(gameDate)
|
|
3691
3789
|
if ( date_cache_data.dates && date_cache_data.dates[0] && date_cache_data.dates[0].games && (date_cache_data.dates[0].games.length > 0) ) {
|
|
3692
|
-
for (var
|
|
3693
|
-
if ( game_pk == date_cache_data.dates[0].games[
|
|
3790
|
+
for (var j = 0; j < date_cache_data.dates[0].games.length; j++) {
|
|
3791
|
+
if ( game_pk == date_cache_data.dates[0].games[j].gamePk ) {
|
|
3694
3792
|
this.debuglog('get_blackout_games found matching game')
|
|
3695
|
-
let blackoutExpiry = await this.get_blackout_expiry(date_cache_data.dates[0].games[
|
|
3793
|
+
let blackoutExpiry = await this.get_blackout_expiry(date_cache_data.dates[0].games[j])
|
|
3696
3794
|
this.debuglog('get_blackout_games calculated blackout expiry as ' + blackoutExpiry)
|
|
3697
3795
|
blackouts[game_pk].blackoutExpiry = blackoutExpiry
|
|
3698
3796
|
break
|
|
@@ -3706,6 +3804,45 @@ class sessionClass {
|
|
|
3706
3804
|
return blackouts
|
|
3707
3805
|
}
|
|
3708
3806
|
|
|
3807
|
+
// get all pre- and post-game for a date
|
|
3808
|
+
async get_pre_post_shows(gameDate='guide') {
|
|
3809
|
+
this.debuglog('get_pre_post_shows')
|
|
3810
|
+
let pregame_shows = {}
|
|
3811
|
+
let postgame_shows = {}
|
|
3812
|
+
|
|
3813
|
+
let cache_data
|
|
3814
|
+
cache_data = await this.getBlackoutsData(gameDate)
|
|
3815
|
+
|
|
3816
|
+
let teamTypes = ['home', 'away']
|
|
3817
|
+
let showTypes = ['preGame', 'postGame']
|
|
3818
|
+
|
|
3819
|
+
if ( cache_data && cache_data.results && (cache_data.results.length > 0) ) {
|
|
3820
|
+
for (var i = 0; i < cache_data.results.length; i++) {
|
|
3821
|
+
let game = cache_data.results[i]
|
|
3822
|
+
if ( game.prePostShows ) {
|
|
3823
|
+
for (var j = 0; j < teamTypes.length; j++) {
|
|
3824
|
+
let teamType = teamTypes[j]
|
|
3825
|
+
if ( game.prePostShows[teamType] ) {
|
|
3826
|
+
for (var k = 0; k < showTypes.length; k++) {
|
|
3827
|
+
let showType = showTypes[k]
|
|
3828
|
+
if ( game.prePostShows[teamType][showType] && game.prePostShows[teamType][showType].hasShow ) {
|
|
3829
|
+
this.debuglog('get_pre_post_shows found ' + teamType + ' ' + showType + ' ' + game.prePostShows[teamType].contentId)
|
|
3830
|
+
if ( game.prePostShows[teamType][showType].startTime ) {
|
|
3831
|
+
pregame_shows[game.prePostShows[teamType].contentId] = { team: teamType, start: game.prePostShows[teamType][showType].startTime }
|
|
3832
|
+
} else {
|
|
3833
|
+
postgame_shows[game.prePostShows[teamType].contentId] = { team: teamType }
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
return { pregame_shows, postgame_shows }
|
|
3844
|
+
}
|
|
3845
|
+
|
|
3709
3846
|
async resetGameChanger(id, includeTeams, excludeTeams) {
|
|
3710
3847
|
let today = this.liveDate()
|
|
3711
3848
|
if ( !this.temp_cache.gamechanger || !this.temp_cache.gamechanger.date || (this.temp_cache.gamechanger.date != today) ) {
|
|
@@ -3835,7 +3972,12 @@ class sessionClass {
|
|
|
3835
3972
|
}
|
|
3836
3973
|
|
|
3837
3974
|
// Game is not broadcast
|
|
3838
|
-
if ( !cache_data.dates[0].games[i].broadcasts || (cache_data.dates[0].games[i].broadcasts.length == 0)
|
|
3975
|
+
if ( !cache_data.dates[0].games[i].broadcasts || (cache_data.dates[0].games[i].broadcasts.length == 0) ) {
|
|
3976
|
+
omitted_games.no_broadcast.push(teams)
|
|
3977
|
+
continue
|
|
3978
|
+
}
|
|
3979
|
+
let broadcast_count = await this.count_broadcasts(cache_data.dates[0].games[i].broadcasts, 'MLBTV')
|
|
3980
|
+
if ( broadcast_count == 0 ) {
|
|
3839
3981
|
omitted_games.no_broadcast.push(teams)
|
|
3840
3982
|
continue
|
|
3841
3983
|
}
|
|
@@ -3852,8 +3994,8 @@ class sessionClass {
|
|
|
3852
3994
|
continue
|
|
3853
3995
|
}
|
|
3854
3996
|
|
|
3855
|
-
//
|
|
3856
|
-
if ( this.temp_cache.gamechanger.blackouts[game_pk] ) {
|
|
3997
|
+
// All feeds are blacked out or not entitled
|
|
3998
|
+
if ( this.temp_cache.gamechanger.blackouts[game_pk] && this.temp_cache.gamechanger.blackouts[game_pk].blackout_feeds && (this.temp_cache.gamechanger.blackouts[game_pk].blackout_feeds.length == broadcast_count) ) {
|
|
3857
3999
|
omitted_games.blackout.push(teams)
|
|
3858
4000
|
continue
|
|
3859
4001
|
}
|
|
@@ -4150,6 +4292,10 @@ class sessionClass {
|
|
|
4150
4292
|
for (var y = 0; y < broadcasts.length; y++) {
|
|
4151
4293
|
let broadcast = broadcasts[y]
|
|
4152
4294
|
if ( (broadcast.availableForStreaming == true) && (broadcast.type == 'TV') && broadcast.mediaState && broadcast.mediaState.mediaStateCode && (broadcast.mediaState.mediaStateCode == 'MEDIA_ON') ) {
|
|
4295
|
+
// skip blackout feeds
|
|
4296
|
+
if ( this.temp_cache.gamechanger.blackouts[curr_game.game_pk] && this.temp_cache.gamechanger.blackouts[curr_game.game_pk].blackout_feeds && this.temp_cache.gamechanger.blackouts[curr_game.game_pk].blackout_feeds.includes(broadcast.mediaId) ) {
|
|
4297
|
+
continue
|
|
4298
|
+
}
|
|
4153
4299
|
// prefer fav team broadcasts
|
|
4154
4300
|
if ( this.credentials.fav_teams.length > 0 ) {
|
|
4155
4301
|
for (var z = 0; z < this.credentials.fav_teams.length; z++) {
|
|
@@ -4351,21 +4497,23 @@ class sessionClass {
|
|
|
4351
4497
|
if ( subtitle ) {
|
|
4352
4498
|
xml_output += ' <sub-title lang="en">' + subtitle + '</sub-title>' + "\n"
|
|
4353
4499
|
}
|
|
4354
|
-
xml_output += ' <
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4500
|
+
xml_output += ' <icon src="' + icon + '"></icon>' + "\n"
|
|
4501
|
+
if ( icon != OFF_AIR_LOGO ) {
|
|
4502
|
+
xml_output += ' <desc lang="en">' + description.trim() + '</desc>' + "\n" +
|
|
4503
|
+
' <category lang="en">Sports</category>' + "\n" +
|
|
4504
|
+
' <category lang="en">Baseball</category>' + "\n" +
|
|
4505
|
+
' <category lang="en">Sports event</category>' + "\n" +
|
|
4506
|
+
' <episode-num system="original-air-date">' + date + '</episode-num>' + "\n" +
|
|
4507
|
+
' <new/>' + "\n" +
|
|
4508
|
+
' <live/>' + "\n" +
|
|
4509
|
+
' <sport>Baseball</sport>' + "\n"
|
|
4510
|
+
}
|
|
4359
4511
|
if ( teamId ) {
|
|
4360
4512
|
xml_output += ' <series-id system="team-id">' + teamId + '</series-id>' + "\n"
|
|
4361
4513
|
}
|
|
4362
|
-
xml_output += ' <episode-num system="original-air-date">' + date + '</episode-num>' + "\n"
|
|
4363
4514
|
if ( gamePk ) {
|
|
4364
4515
|
xml_output += ' <episode-num system="game-id">' + gamePk + '</episode-num>' + "\n"
|
|
4365
4516
|
}
|
|
4366
|
-
xml_output += ' <new/>' + "\n" +
|
|
4367
|
-
' <live/>' + "\n" +
|
|
4368
|
-
' <sport>Baseball</sport>' + "\n"
|
|
4369
4517
|
if ( away_team ) {
|
|
4370
4518
|
xml_output += ' <team lang="en">' + away_team + '</team>' + "\n"
|
|
4371
4519
|
}
|
|
@@ -4388,7 +4536,47 @@ class sessionClass {
|
|
|
4388
4536
|
channel_object.mediatype = channelMediaType
|
|
4389
4537
|
return channel_object
|
|
4390
4538
|
}
|
|
4391
|
-
|
|
4539
|
+
|
|
4540
|
+
async generate_off_air_event(offAir, channelid, gameDate, start, stop, title) {
|
|
4541
|
+
try {
|
|
4542
|
+
if ( offAir != 'false' ) {
|
|
4543
|
+
let today = this.liveDate()
|
|
4544
|
+
let nextWeek = new Date(today)
|
|
4545
|
+
nextWeek.setDate(nextWeek.getDate()+6)
|
|
4546
|
+
nextWeek = nextWeek.toISOString().substring(0,10)
|
|
4547
|
+
if ( !start ) {
|
|
4548
|
+
start = this.convertDateToXMLTV(new Date(today + ' 00:00:00'))
|
|
4549
|
+
}
|
|
4550
|
+
let offAirTitle = 'Off Air'
|
|
4551
|
+
let offAirSubtitle = ''
|
|
4552
|
+
let day = new Date(gameDate + ' 00:00:00').toLocaleString('en-US', { weekday: 'long' })
|
|
4553
|
+
if ( gameDate == today ) {
|
|
4554
|
+
day = 'Today'
|
|
4555
|
+
}
|
|
4556
|
+
if ( gameDate > nextWeek ) {
|
|
4557
|
+
day += ' ' + this.channelsFormattedDate(stop)
|
|
4558
|
+
}
|
|
4559
|
+
let time = new Date(stop).toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })
|
|
4560
|
+
if ( offAir == 'channels' ) {
|
|
4561
|
+
offAirTitle = 'Upcoming: ' + time + ' ' + day + ', ' + title
|
|
4562
|
+
offAirSubtitle = ''
|
|
4563
|
+
} else {
|
|
4564
|
+
offAirSubtitle = 'next ' + day + ' ' + time
|
|
4565
|
+
}
|
|
4566
|
+
return await this.generate_xml_program(channelid, start, this.convertDateToXMLTV(new Date(stop)), offAirTitle, '', OFF_AIR_LOGO, '', offAirSubtitle)
|
|
4567
|
+
}
|
|
4568
|
+
} catch(e) {
|
|
4569
|
+
this.log('generate_off_air_event error : ' + e.message)
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
|
|
4573
|
+
channelsFormattedTitle(subtitle, date) {
|
|
4574
|
+
return subtitle + ' *Live* ' + this.channelsFormattedDate(date)
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4577
|
+
channelsFormattedDate(date) {
|
|
4578
|
+
return new Date(date).toLocaleString('en-us', { month: 'short', day: 'numeric' })
|
|
4579
|
+
}
|
|
4392
4580
|
}
|
|
4393
4581
|
|
|
4394
4582
|
module.exports = sessionClass
|