mlbserver 2023.7.10 → 2023.10.27

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.
Files changed (4) hide show
  1. package/README.md +1 -1
  2. package/index.js +18 -14
  3. package/package.json +2 -2
  4. package/session.js +41 -16
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # mlbserver
2
2
 
3
- Current version 2023.07.10
3
+ Current version 2023.10.27
4
4
 
5
5
  Credit to https://github.com/tonycpsu/streamglob and https://github.com/mafintosh/hls-decryptor
6
6
 
package/index.js CHANGED
@@ -313,7 +313,8 @@ app.get('/stream.m3u8', async function(req, res) {
313
313
  }
314
314
  } else if ( req.query.team ) {
315
315
  let mediaType = req.query.mediaType || VALID_MEDIA_TYPES[0]
316
- let mediaInfo = await session.getMediaId(decodeURIComponent(req.query.team), mediaType, req.query.date, req.query.game, includeBlackouts)
316
+ let level = req.query.level || 'MLB'
317
+ let mediaInfo = await session.getMediaId(decodeURIComponent(req.query.team), decodeURIComponent(level), mediaType, req.query.date, req.query.game, includeBlackouts)
317
318
  if ( mediaInfo ) {
318
319
 
319
320
  if ( mediaInfo.gamePk ) {
@@ -1285,7 +1286,7 @@ app.get('/', async function(req, res) {
1285
1286
  }
1286
1287
  }
1287
1288
  let cache_name = gameDate
1288
- if ( level_ids != '1' ) {
1289
+ if ( level_ids != levels['MLB'] ) {
1289
1290
  cache_name += '.' + level_ids
1290
1291
  }
1291
1292
  if ( team_ids != '' ) {
@@ -1511,9 +1512,11 @@ app.get('/', async function(req, res) {
1511
1512
 
1512
1513
  let blackouts = {}
1513
1514
 
1514
- if ( (mediaType == 'MLBTV') && ((level_ids == '1') || level_ids.startsWith('1,')) ) {
1515
- // Recap Rundown beginning in 2023
1516
- 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) ) {
1515
+ let currentDate = new Date()
1516
+
1517
+ if ( (mediaType == 'MLBTV') && ((level_ids == levels['MLB']) || level_ids.startsWith(levels['MLB'] + ',')) ) {
1518
+ // Recap Rundown beginning in 2023, disabled because it stopped working
1519
+ /*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) ) {
1517
1520
  body += '<tr><td><span class="tooltip">VOD<span class="tooltiptext">Recap Rundown plays all of a day\'s recaps in order.</span></span></td><td>'
1518
1521
  let dateArray = gameDate.split('-')
1519
1522
  let querystring = '?event=recaprundown' + parseInt(dateArray[1]).toString() + '-' + parseInt(dateArray[2]).toString() + '-' + dateArray[0].substring(2,4)
@@ -1524,14 +1527,12 @@ app.get('/', async function(req, res) {
1524
1527
  querystring += content_protect_b
1525
1528
  body += '<a href="' + thislink + querystring + '">Recap Rundown</a>'
1526
1529
  body += '</td></tr>' + "\n"
1527
- }
1530
+ }*/
1528
1531
 
1529
1532
  if ( (gameDate >= today) && cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
1530
1533
  blackouts = await session.get_blackout_games(cache_data.dates[0].games, true)
1531
1534
  }
1532
1535
 
1533
- let currentDate = new Date()
1534
-
1535
1536
  // Big Inning
1536
1537
  var big_inning
1537
1538
  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') ) {
@@ -1600,6 +1601,8 @@ app.get('/', async function(req, res) {
1600
1601
 
1601
1602
  if ( cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games ) {
1602
1603
  for (var j = 0; j < cache_data.dates[0].games.length; j++) {
1604
+ let gamePk = cache_data.dates[0].games[j].gamePk.toString()
1605
+
1603
1606
  let game_started = false
1604
1607
 
1605
1608
  let awayteam = cache_data.dates[0].games[j].teams['away'].team.abbreviation
@@ -1607,23 +1610,25 @@ app.get('/', async function(req, res) {
1607
1610
  if ( cache_data.dates[0].games[j].teams['away'].team.sport.name != 'Major League Baseball' ) {
1608
1611
  awayteam = cache_data.dates[0].games[j].teams['away'].team.shortName + ' (' + session.getParent(cache_data.dates[0].games[j].teams['away'].team.parentOrgName) + ')'
1609
1612
  awayteam_abbr = cache_data.dates[0].games[j].teams['away'].team.abbreviation
1613
+ awayteam_level = session.getLevelNameFromSportId(cache_data.dates[0].games[j].teams['away'].team.sport.id)
1610
1614
  }
1611
1615
  let hometeam = cache_data.dates[0].games[j].teams['home'].team.abbreviation
1612
1616
  let hometeam_abbr
1613
1617
  if ( cache_data.dates[0].games[j].teams['home'].team.sport.name != 'Major League Baseball' ) {
1614
1618
  hometeam = cache_data.dates[0].games[j].teams['home'].team.shortName + ' (' + session.getParent(cache_data.dates[0].games[j].teams['home'].team.parentOrgName) + ')'
1615
1619
  hometeam_abbr = cache_data.dates[0].games[j].teams['home'].team.abbreviation
1620
+ hometeam_level = session.getLevelNameFromSportId(cache_data.dates[0].games[j].teams['home'].team.sport.id)
1616
1621
  }
1617
1622
 
1618
1623
  let teams = ""
1619
1624
  if ( awayteam_abbr ) {
1620
- teams += '<span class="tooltip">' + awayteam + '<span class="tooltiptext">Team Abbreviation: ' + awayteam_abbr + '</span></span>'
1625
+ teams += '<span class="tooltip">' + awayteam + '<span class="tooltiptext">Team Abbreviation: ' + awayteam_abbr + ', level ' + awayteam_level + '</span></span>'
1621
1626
  } else {
1622
1627
  teams += awayteam
1623
1628
  }
1624
1629
  teams += " @ "
1625
1630
  if ( hometeam_abbr ) {
1626
- teams += '<span class="tooltip">' + hometeam + '<span class="tooltiptext">Team Abbreviation: ' + hometeam_abbr+ '</span></span>'
1631
+ teams += '<span class="tooltip">' + hometeam + '<span class="tooltiptext">Team Abbreviation: ' + hometeam_abbr + ', level ' + hometeam_level + '</span></span>'
1627
1632
  } else {
1628
1633
  teams += hometeam
1629
1634
  }
@@ -1787,7 +1792,7 @@ app.get('/', async function(req, res) {
1787
1792
  body += '><td>' + description + teams + pitchers + state + '</td>'
1788
1793
 
1789
1794
  // Check if Winter League / MiLB game first
1790
- if ( (cache_data.dates[0].games[j].teams['home'].team.sport.id != '1') && (mediaType == 'MLBTV') ) {
1795
+ if ( (cache_data.dates[0].games[j].teams['home'].team.sport.id != levels['MLB']) && (mediaType == 'MLBTV') ) {
1791
1796
  body += "<td>"
1792
1797
  if ( cache_data.dates[0].games[j].broadcasts ) {
1793
1798
  let broadcastName = 'N/A'
@@ -1807,7 +1812,6 @@ app.get('/', async function(req, res) {
1807
1812
  let startTime = new Date(cache_data.dates[0].games[j].gameDate)
1808
1813
  startTime.setMinutes(startTime.getMinutes()-30)
1809
1814
  if ( (currentTime >= startTime) ) {
1810
- let gamePk = cache_data.dates[0].games[j].gamePk
1811
1815
  let querystring
1812
1816
  querystring = '?gamePk=' + gamePk
1813
1817
  let multiviewquerystring = querystring + '&resolution=' + DEFAULT_MULTIVIEW_RESOLUTION
@@ -1875,7 +1879,6 @@ app.get('/', async function(req, res) {
1875
1879
  let station = cache_data.dates[0].games[j].content.media.epg[k].items[x].callLetters
1876
1880
 
1877
1881
  // display blackout tooltip, if necessary
1878
- let gamePk = cache_data.dates[0].games[j].gamePk.toString()
1879
1882
  if ( blackouts[gamePk] ) {
1880
1883
  body += '<span class="tooltip"><span class="blackout">' + teamabbr + '</span><span class="tooltiptext">' + blackouts[gamePk].blackout_type + ' video blackout until approx. 2.5 hours after the game'
1881
1884
  if ( blackouts[gamePk].blackoutExpiry ) {
@@ -2158,6 +2161,7 @@ app.get('/', async function(req, res) {
2158
2161
 
2159
2162
  let examples = [
2160
2163
  ['Team live video', '?team=' + example_team + '&resolution=best'],
2164
+ ['MiLB team live video', '?team=COL&level=AAA&resolution=best'],
2161
2165
  ['Team live radio', '?team=' + example_team + '&mediaType=Audio'],
2162
2166
  ['Catch-up/condensed', '?team=' + example_team + '&resolution=best&skip=pitches&date=today'],
2163
2167
  ['Condensed yesterday', '?team=' + example_team + '&resolution=best&skip=pitches&date=yesterday'],
@@ -2350,7 +2354,7 @@ app.get('/embed.html', async function(req, res) {
2350
2354
 
2351
2355
  body += '<button onclick="changeTime(video.duration-10)">Latest</button> '
2352
2356
 
2353
- body += '<button id="airplay">AirPlay</button></p><p>Playback rate: <input type="number" value=1.0 min=0.1 max=16.0 step=0.1 id="playback_rate" size="8" style="width: 4em" onchange="video.defaultPlaybackRate=video.playbackRate=this.value"></p><p>Audio: <button onclick="video.muted=!video.muted">Toggle Mute</button> <span id="audioSpan"></span></p><p>Controls: <button onclick="video.controls=!video.controls">Toggle Controls</button></p><p><button onclick="goBack()">Back</button></p><script>var airPlay=document.getElementById("airplay");if(window.WebKitPlaybackTargetAvailabilityEvent){video.addEventListener("webkitplaybacktargetavailabilitychanged",function(event){switch(event.availability){case "available":airPlay.style.display="inline";break;default:airPlay.style.display="none"}airPlay.addEventListener("click",function(){video.webkitShowPlaybackTargetPicker()})})}else{airPlay.style.display="none"}</script></body></html>'
2357
+ body += '<button id="airplay">AirPlay</button></p><p>Playback rate: <input type="number" value=1.0 min=0.1 max=16.0 step=0.1 id="playback_rate" size="8" style="width: 4em" onchange="video.defaultPlaybackRate=video.playbackRate=this.value"></p><p>Audio: <button onclick="video.muted=!video.muted">Toggle Mute</button> <span id="audioSpan"></span></p><p>Controls: <button onclick="video.controls=!video.controls">Toggle Controls</button></p><p><button id="pauseButton">Pause</button></p><script>document.addEventListener("DOMContentLoaded", function() {var pauseButton = document.getElementById("pauseButton"); pauseButton.addEventListener("click", function() {if (video.paused) {video.play();} else {video.pause();}}); });</script><p><button onclick="goBack()">Back</button></p><script>var airPlay=document.getElementById("airplay");if(window.WebKitPlaybackTargetAvailabilityEvent){video.addEventListener("webkitplaybacktargetavailabilitychanged",function(event){switch(event.availability){case "available":airPlay.style.display="inline";break;default:airPlay.style.display="none"}airPlay.addEventListener("click",function(){video.webkitShowPlaybackTargetPicker()})})}else{airPlay.style.display="none"}</script></body></html>'
2354
2358
  res.end(body)
2355
2359
  })
2356
2360
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlbserver",
3
- "version": "2023.07.10",
3
+ "version": "2023.10.27",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "hls-server": "^1.5.0",
13
13
  "http": "0.0.1-security",
14
14
  "http-attach": "^1.0.0",
15
- "minimist": "^1.2.5",
15
+ "minimist": "^1.2.8",
16
16
  "readline-sync": "^1.4.10",
17
17
  "request": "^2.88.2",
18
18
  "request-promise": "^4.2.6",
package/session.js CHANGED
@@ -31,7 +31,7 @@ const AFFILIATE_TEAM_IDS = { 'ARI': '419,516,2310,5368', 'ATL': '430,432,478,431
31
31
  const ESPN_SUNDAY_NIGHT_BLACKOUT_COUNTRIES = ["Angola", "Anguilla", "Antigua and Barbuda", "Argentina", "Aruba", "Australia", "Bahamas", "Barbados", "Belize", "Belize", "Benin", "Bermuda", "Bolivia", "Bonaire", "Botswana", "Brazil", "British Virgin Islands", "Burkina Faso", "Burundi", "Cameroon", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "Colombia", "Comoros", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Curacao", "Democratic Republic of the Congo", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "El Salvador", "England", "Equatorial Guinea", "Eritrea", "Eswatini", "Ethiopia", "Falkland Islands", "Falkland Islands", "Fiji", "French Guiana", "French Guiana", "French Polynesia", "Gabon", "Ghana", "Grenada", "Guadeloupe", "Guatemala", "Guinea", "Guinea Bissau", "Guyana", "Guyana", "Haiti", "Honduras", "Ireland", "Jamaica", "Kenya", "Kiribati", "Lesotho", "Liberia", "Madagascar", "Malawi", "Mali", "Marshall Islands", "Martinique", "Mayotte", "Mexico", "Micronesia", "Montserrat", "Mozambique", "Namibia", "Netherlands", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Northern Ireland", "Palau Islands", "Panama", "Paraguay", "Peru", "Republic of Ireland", "Reunion", "Rwanda", "Saba", "Saint Maarten", "Samoa", "Sao Tome & Principe", "Scotland", "Senegal", "Seychelles", "Sierra Leone", "Solomon Islands", "Somalia", "South Africa", "St. Barthelemy", "St. Eustatius", "St. Kitts and Nevis", "St. Lucia", "St. Martin", "St. Vincent and the Grenadines", "Sudan", "Surinam", "Suriname", "Tahiti", "Tanzania & Zanzibar", "The Gambia", "The Republic of Congo", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Uruguay", "Venezuela", "Wales", "Zambia", "Zimbabwe"]
32
32
 
33
33
  // First is default level, last should be All (also used as default org)
34
- const LEVELS = { 'MLB': '1,51', 'AAA': '11', 'AA': '12', 'A+': '13', 'A': '14', 'All': '1,11,12,13,14,51' }
34
+ const LEVELS = { 'MLB': '1', 'AAA': '11', 'AA': '12', 'A+': '13', 'A': '14', 'All': '1,11,12,13,14' }
35
35
 
36
36
  // These are the events to ignore, if we're skipping breaks
37
37
  const BREAK_TYPES = ['Game Advisory', 'Pitching Substitution', 'Offensive Substitution', 'Defensive Sub', 'Defensive Switch', 'Runner Placed On Base']
@@ -1108,6 +1108,16 @@ class sessionClass {
1108
1108
  return LEVELS
1109
1109
  }
1110
1110
 
1111
+ getLevelNameFromSportId(sportId) {
1112
+ let sportIds = Object.values(LEVELS)
1113
+ for (var i=0; i<sportIds.length; i++) {
1114
+ if ( sportId == sportIds[i] ) {
1115
+ let levelNames = Object.keys(LEVELS)
1116
+ return levelNames[i]
1117
+ }
1118
+ }
1119
+ }
1120
+
1111
1121
  getTeamIds(team_abbr = false) {
1112
1122
  if ( team_abbr ) {
1113
1123
  return TEAM_IDS[team_abbr]
@@ -1800,7 +1810,7 @@ class sessionClass {
1800
1810
  }
1801
1811
 
1802
1812
  // get mediaId for a live channel request
1803
- async getMediaId(team, mediaType, mediaDate, gameNumber, includeBlackouts) {
1813
+ async getMediaId(team, level, mediaType, mediaDate, gameNumber, includeBlackouts) {
1804
1814
  try {
1805
1815
  this.debuglog('getMediaId')
1806
1816
 
@@ -1852,14 +1862,16 @@ class sessionClass {
1852
1862
  if ( typeof cache_data.dates[0].games[j] !== 'undefined' ) {
1853
1863
  let home_team = cache_data.dates[0].games[j].teams['home'].team.abbreviation
1854
1864
  let away_team = cache_data.dates[0].games[j].teams['away'].team.abbreviation
1865
+ let home_level = cache_data.dates[0].games[j].teams['home'].team.sport.id
1866
+ let away_level = cache_data.dates[0].games[j].teams['away'].team.sport.id
1855
1867
  this.debuglog('checking game ' + cache_data.dates[0].games[j].teams['home'].team.abbreviation + '@' + cache_data.dates[0].games[j].teams['away'].team.abbreviation)
1856
1868
 
1857
- // check that that game involves the requested team, or if it's a national or free game and we've requested that
1858
- if ( (team.toUpperCase() == home_team) || (team.toUpperCase() == away_team) || ((team.toUpperCase().indexOf('NATIONAL.') == 0) && ((cache_data.dates[0].games[j].content.media.epg[k].items[x][mediaFeedType] == 'NATIONAL') || ((mediaType == 'MLBTV') && (cache_data.dates[0].games[j].seriesDescription != 'Regular Season') && (cache_data.dates[0].games[j].seriesDescription != 'Spring Training')))) || (team.toUpperCase().startsWith('FREE.') && cache_data.dates[0].games[j].content.media.freeGame) ) {
1859
- this.debuglog('matched team for ' + cache_data.dates[0].games[j].teams['home'].team.abbreviation + '@' + cache_data.dates[0].games[j].teams['away'].team.abbreviation)
1869
+ // check that that game involves the requested team, or if we've requested a national or free game
1870
+ if ( ((team.toUpperCase() == home_team) && (LEVELS[level.toUpperCase()] == home_level)) || ((team.toUpperCase() == away_team) && (LEVELS[level.toUpperCase()] == away_level)) || (team.toUpperCase().indexOf('NATIONAL.') == 0) || ((team.toUpperCase().startsWith('FREE.') && cache_data.dates[0].games[j].content && cache_data.dates[0].games[j].content.media && cache_data.dates[0].games[j].content.media.freeGame)) ) {
1860
1871
 
1861
1872
  // Check if Winter League / MiLB game first
1862
- if ( (cache_data.dates[0].games[j].teams['home'].team.sport.id != '1') && (mediaType == 'MLBTV') ) {
1873
+ if ( (cache_data.dates[0].games[j].teams['home'].team.sport.id != LEVELS['MLB']) && (mediaType == 'MLBTV') ) {
1874
+ this.debuglog('matched non-MLB team for ' + cache_data.dates[0].games[j].teams['home'].team.abbreviation + '@' + cache_data.dates[0].games[j].teams['away'].team.abbreviation)
1863
1875
  if ( cache_data.dates[0].games[j].broadcasts ) {
1864
1876
  let broadcastName = 'N/A'
1865
1877
  for (var k = 0; k < cache_data.dates[0].games[j].broadcasts.length; k++) {
@@ -1886,7 +1898,6 @@ class sessionClass {
1886
1898
 
1887
1899
  // MLB games
1888
1900
  if ( cache_data.dates[0].games[j].content && cache_data.dates[0].games[j].content.media && cache_data.dates[0].games[j].content.media.epg ) {
1889
-
1890
1901
  // check blackout status, if necessary
1891
1902
  if ( (mediaType == 'MLBTV') && (includeBlackouts == 'false') && blackouts[gamePk] ) {
1892
1903
  if ( !blackouts[gamePk].blackoutExpiry || (currentDate < blackouts[gamePk].blackoutExpiry) ) {
@@ -2075,7 +2086,7 @@ class sessionClass {
2075
2086
  try {
2076
2087
  let cache_data
2077
2088
  let cache_name = dateString
2078
- if ( level_ids != '1' ) {
2089
+ if ( level_ids != LEVELS['MLB'] ) {
2079
2090
  cache_name += '.' + level_ids
2080
2091
  }
2081
2092
  if ( team_ids != '' ) {
@@ -2314,7 +2325,8 @@ class sessionClass {
2314
2325
  let dateIndex = {MLBTV:i,Free:i,Audio:i}
2315
2326
  let gameCounter = {MLBTV:0,Free:0,Audio:0}
2316
2327
 
2317
- let blackouts = await this.get_blackout_games(cache_data.dates[i].games)
2328
+ let blackouts = {}
2329
+ if ( includeBlackouts == 'false' ) blackouts = await this.get_blackout_games(cache_data.dates[i].games)
2318
2330
  let gameIndexes = await this.get_first_and_last_games(cache_data.dates[i].games, blackouts)
2319
2331
  // store gameIndexes for gamechanger/multiview reference later
2320
2332
  gameIndexes_obj[cache_data.dates[i].date] = gameIndexes
@@ -2322,7 +2334,7 @@ class sessionClass {
2322
2334
  for (var j = 0; j < cache_data.dates[i].games.length; j++) {
2323
2335
  this.debuglog('getTVData processing game ' + j + ' for date ' + cache_data.dates[i].date)
2324
2336
  // Check if Winter League / MiLB game first
2325
- if ( (cache_data.dates[i].games[j].teams['home'].team.sport.id != '1') && (mediaType == 'MLBTV') ) {
2337
+ if ( (cache_data.dates[i].games[j].teams['home'].team.sport.id != LEVELS['MLB']) && (mediaType == 'MLBTV') ) {
2326
2338
  if ( cache_data.dates[i].games[j].broadcasts ) {
2327
2339
  let broadcastName = 'N/A'
2328
2340
  for (var k = 0; k < cache_data.dates[i].games[j].broadcasts.length; k++) {
@@ -2346,6 +2358,8 @@ class sessionClass {
2346
2358
  let logo = server + '/image.svg?teamId=' + team_id
2347
2359
  let streamMediaType = 'Video'
2348
2360
  let stream = server + '/stream.m3u8?team=' + encodeURIComponent(team) + '&mediaType=' + streamMediaType
2361
+ let sportId = cache_data.dates[i].games[j].teams['home'].team.sport.id
2362
+ stream += '&level=' + this.getLevelNameFromSportId(sportId)
2349
2363
  stream += '&resolution=' + resolution
2350
2364
  if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
2351
2365
  if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
@@ -3544,13 +3558,16 @@ class sessionClass {
3544
3558
  for (var k = 0; k < games[j].content.media.epg.length; k++) {
3545
3559
  if ( games[j].content.media.epg[k].title == 'MLBTV' ) {
3546
3560
  for (var x = 0; x < games[j].content.media.epg[k].items.length; x++) {
3561
+ this.debuglog('check_regional_fox_games checking ' + games[j].content.media.epg[k].items[x].callLetters)
3547
3562
  if ( games[j].content.media.epg[k].items[x].callLetters == 'FOX' ) {
3563
+ this.debuglog('check_regional_fox_games found FOX game')
3548
3564
  if ( fox_start_time && (games[j].gameDate == fox_start_time) ) {
3549
- this.debuglog('check_regional_fox_games found')
3565
+ this.debuglog('check_regional_fox_games determined regional game')
3550
3566
  regional_fox_games_exist = 'true'
3551
3567
  break
3552
3568
  } else {
3553
3569
  fox_start_time = games[j].gameDate
3570
+ break
3554
3571
  }
3555
3572
  }
3556
3573
  }
@@ -3564,6 +3581,7 @@ class sessionClass {
3564
3581
 
3565
3582
  // get all blackout games for a date
3566
3583
  async get_blackout_games(games, calculate_expiries=false) {
3584
+ this.debuglog('get_blackout_games')
3567
3585
  let blackouts = {}
3568
3586
 
3569
3587
  let usa_blackout = /(^\d{5}$)/.test(this.credentials.zip_code) && (this.credentials.country == 'USA')
@@ -3574,14 +3592,18 @@ class sessionClass {
3574
3592
  if ( games[j].content && games[j].content.media && games[j].content.media.epg ) {
3575
3593
  for (var k = 0; k < games[j].content.media.epg.length; k++) {
3576
3594
  if ( games[j].content.media.epg[k].title == 'MLBTV' ) {
3595
+ this.debuglog('get_blackout_games checking ' + game_pk)
3577
3596
  for (var x = 0; x < games[j].content.media.epg[k].items.length; x++) {
3578
- if (games[j].content.media.epg[k].items[x].mediaFeedType == 'NATIONAL') {
3597
+ this.debuglog('get_blackout_games checking feed ' + games[j].content.media.epg[k].items[x].mediaFeedType + ' ' + games[j].content.media.epg[k].items[x].callLetters)
3598
+ if ( (games[j].content.media.epg[k].items[x].mediaFeedType == 'NATIONAL') || (await this.check_pay_tv(games[j].content.media.epg[k].items[x])) || games[j].content.media.epg[k].items[x].callLetters.endsWith('-INT') ) {
3599
+ this.debuglog('get_blackout_games checking national game')
3579
3600
  // International blackouts according to https://www.mlb.com/live-stream-games/help-center/blackouts-available-games
3580
- if ( usa_blackout && (games[j].content.media.epg[k].items[x].callLetters == 'FOX') && (games[j].seriesDescription == 'Regular Season') ) {
3581
- if ( !regional_fox_games_exist ) {
3601
+ if ( usa_blackout && (games[j].content.media.epg[k].items[x].callLetters == 'FOX') ) {
3602
+ if ( !regional_fox_games_exist && (games[j].seriesDescription == 'Regular Season') ) {
3582
3603
  regional_fox_games_exist = await this.check_regional_fox_games(games)
3583
3604
  }
3584
- if ( regional_fox_games_exist == 'false' ) {
3605
+ if ( !regional_fox_games_exist || (regional_fox_games_exist == 'false') ) {
3606
+ this.debuglog('get_blackout_games found non-regional FOX game')
3585
3607
  blackouts[game_pk] = { blackout_type:'National' }
3586
3608
  break
3587
3609
  }
@@ -3591,6 +3613,9 @@ class sessionClass {
3591
3613
  // ESPN Sunday Night games are blacked out in a list of countries
3592
3614
  } else if ( (games[j].content.media.epg[k].items[x].callLetters == 'ESPN') && (new Date(games[j].gameDate).getDay() == 0) && ESPN_SUNDAY_NIGHT_BLACKOUT_COUNTRIES.includes(this.credentials.country) ) {
3593
3615
  blackouts[game_pk] = { blackout_type:'Partial International' }
3616
+ // games with an "-INT" variant are postseason games, blacked out in USA and Canada
3617
+ } else if ( games[j].content.media.epg[k].items[x].callLetters.endsWith('-INT') && (usa_blackout || (this.credentials.country == 'Canada')) ) {
3618
+ blackouts[game_pk] = { blackout_type:'National' }
3594
3619
  } else if ( usa_blackout ) {
3595
3620
  blackouts[game_pk] = { blackout_type:'National' }
3596
3621
  }
@@ -4163,7 +4188,7 @@ class sessionClass {
4163
4188
 
4164
4189
  async check_pay_tv(item) {
4165
4190
  try {
4166
- if ( item.foxAuthRequired || item.tbsAuthRequired || item.espnAuthRequired || item.fs1AuthRequired || item.mlbnAuthRequired ) {
4191
+ if ( item.foxAuthRequired || item.tbsAuthRequired || item.espnAuthRequired || item.espn2AuthRequired || item.fs1AuthRequired || item.mlbnAuthRequired || item.abcAuthRequired ) {
4167
4192
  return true
4168
4193
  }
4169
4194
  } catch (e) {