mlbserver 2024.8.2 → 2024.10.1

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 (3) hide show
  1. package/index.js +26 -9
  2. package/package.json +1 -1
  3. package/session.js +131 -66
package/index.js CHANGED
@@ -37,6 +37,7 @@ const VALID_AUDIO_TRACKS = [ 'all', 'English', 'English Radio', 'Radio Española
37
37
  const DISPLAY_AUDIO_TRACKS = [ 'all', 'TV', 'Radio', 'Spanish', 'Alt.', 'Alt. Spanish', 'none' ]
38
38
  const DEFAULT_MULTIVIEW_AUDIO_TRACK = 'English'
39
39
  const VALID_SKIP = [ 'off', 'breaks', 'idle time', 'pitches', 'commercials' ]
40
+ const DEFAULT_SKIP_ADJUST = 0
40
41
  const VALID_PAD = [ 'off', 'on' ]
41
42
  const VALID_FORCE_VOD = [ 'off', 'on' ]
42
43
  const VALID_SCAN_MODES = [ 'off', 'on' ]
@@ -221,6 +222,8 @@ app.get('/clearcache', async function(req, res) {
221
222
 
222
223
  session.log('Clearing cache...')
223
224
  session.clear_cache()
225
+ session.log('Clearing session...')
226
+ session.clear_session_data()
224
227
  session = new sessionClass(argv)
225
228
 
226
229
  let server = 'http://' + req.headers.host
@@ -338,10 +341,12 @@ app.get('/stream.m3u8', async function(req, res) {
338
341
  if ( gamePk ) {
339
342
  options.gamePk = gamePk
340
343
 
344
+ let skip_adjust = parseInt(req.query.skip_adjust) || DEFAULT_SKIP_ADJUST
345
+
341
346
  let skip_type = VALID_SKIP.indexOf(options.skip)
342
347
  // for skip other than commercial skip, look up markers
343
348
  if ( skip_type != 4 ) {
344
- await session.getSkipMarkers(gamePk, skip_type, options.inning_number, options.inning_half, streamURL, streamURLToken)
349
+ await session.getSkipMarkers(gamePk, skip_type, options.inning_number, options.inning_half, streamURL, streamURLToken, skip_adjust)
345
350
  }
346
351
  }
347
352
  }
@@ -455,6 +460,7 @@ function getMasterPlaylist(streamURL, req, res, options = {}) {
455
460
  let inning_half = options.inning_half || VALID_INNING_HALF[0]
456
461
  let inning_number = options.inning_number || VALID_INNING_NUMBER[0]
457
462
  let skip = options.skip || VALID_SKIP[0]
463
+ let skip_adjust = options.skip_adjust || DEFAULT_SKIP_ADJUST
458
464
  let pad = options.pad || VALID_PAD[0]
459
465
  let gamePk = options.gamePk || false
460
466
 
@@ -559,6 +565,7 @@ function getMasterPlaylist(streamURL, req, res, options = {}) {
559
565
  if ( inning_half != VALID_INNING_HALF[0] ) newurl += '&inning_half=' + inning_half
560
566
  if ( inning_number != VALID_INNING_NUMBER[0] ) newurl += '&inning_number=' + inning_number
561
567
  if ( skip != VALID_SKIP[0] ) newurl += '&skip=' + skip
568
+ if ( skip_adjust != DEFAULT_SKIP_ADJUST ) newurl += '&skip_adjust=' + skip_adjust
562
569
  if ( pad != VALID_PAD[0] ) newurl += '&pad=' + pad
563
570
  if ( gamePk ) newurl += '&gamePk=' + gamePk
564
571
  newurl += content_protect + referer_parameter + token_parameter
@@ -626,6 +633,7 @@ function getMasterPlaylist(streamURL, req, res, options = {}) {
626
633
  if ( inning_half != VALID_INNING_HALF[0] ) newurl += '&inning_half=' + inning_half
627
634
  if ( inning_number != VALID_INNING_NUMBER[0] ) newurl += '&inning_number=' + inning_number
628
635
  if ( skip != VALID_SKIP[0] ) newurl += '&skip=' + skip
636
+ if ( skip_adjust != DEFAULT_SKIP_ADJUST ) newurl += '&skip_adjust=' + skip_adjust
629
637
  if ( pad != VALID_PAD[0] ) newurl += '&pad=' + pad
630
638
  if ( gamePk ) newurl += '&gamePk=' + gamePk
631
639
  newurl += content_protect + referer_parameter + token_parameter
@@ -681,6 +689,7 @@ app.get('/playlist', async function(req, res) {
681
689
  var inning_half = req.query.inning_half || VALID_INNING_HALF[0]
682
690
  var inning_number = req.query.inning_number || VALID_INNING_NUMBER[0]
683
691
  var skip = req.query.skip || VALID_SKIP[0]
692
+ var skip_adjust = req.query.skip_adjust || DEFAULT_SKIP_ADJUST
684
693
  var pad = req.query.pad || VALID_PAD[0]
685
694
  var gamePk = req.query.gamePk || false
686
695
 
@@ -1045,10 +1054,10 @@ app.get('/gamechangerplaylist', async function(req, res) {
1045
1054
  }
1046
1055
  session.temp_cache.gamechanger[id].lastAccess = gamechangerAccess
1047
1056
 
1048
- if ( !session.temp_cache.gamechanger.start || (gamechangerAccess < session.temp_cache.gamechanger.start) || !session.temp_cache.gamechanger.end || (gamechangerAccess > session.temp_cache.gamechanger.end) ) {
1057
+ /*if ( !session.temp_cache.gamechanger.start || (gamechangerAccess < session.temp_cache.gamechanger.start) || !session.temp_cache.gamechanger.end || (gamechangerAccess > session.temp_cache.gamechanger.end) ) {
1049
1058
  session.log(game_changer_title + 'outside of games starting/ending, skipping')
1050
1059
  respond(GAMECHANGER_RESPONSE_HEADERS, res, Buffer.from(''))
1051
- } else {
1060
+ } else {*/
1052
1061
  let streamURL
1053
1062
  let streamURLToken
1054
1063
  let discontinuity = false
@@ -1164,7 +1173,7 @@ app.get('/gamechangerplaylist', async function(req, res) {
1164
1173
  respond(GAMECHANGER_RESPONSE_HEADERS, res, Buffer.from(session.temp_cache.gamechanger[id].playlist[resolution]))
1165
1174
  }
1166
1175
  }
1167
- }
1176
+ //}
1168
1177
  }
1169
1178
 
1170
1179
  return req()
@@ -1329,6 +1338,10 @@ app.get('/', async function(req, res) {
1329
1338
  if ( req.query.skip ) {
1330
1339
  skip = req.query.skip
1331
1340
  }
1341
+ var skip_adjust = DEFAULT_SKIP_ADJUST
1342
+ if ( req.query.skip_adjust ) {
1343
+ skip_adjust = req.query.skip_adjust
1344
+ }
1332
1345
  var pad = VALID_PAD[0]
1333
1346
  if ( req.query.pad ) {
1334
1347
  pad = req.query.pad
@@ -1361,10 +1374,10 @@ app.get('/', async function(req, res) {
1361
1374
  body += '</style><script type="text/javascript">' + "\n";
1362
1375
 
1363
1376
  // Define option variables in page
1364
- body += 'var date="' + gameDate + '";var level="' + level + '";var org="' + org + '";var mediaType="' + mediaType + '";var resolution="' + resolution + '";var audio_track="' + audio_track + '";var force_vod="' + force_vod + '";var inning_half="' + inning_half + '";var inning_number="' + inning_number + '";var skip="' + skip + '";var pad="' + pad + '";var linkType="' + linkType + '";var startFrom="' + startFrom + '";var scores="' + scores + '";var controls="' + controls + '";var scan_mode="' + scan_mode + '";var content_protect="' + content_protect + '";' + "\n"
1377
+ body += 'var date="' + gameDate + '";var level="' + level + '";var org="' + org + '";var mediaType="' + mediaType + '";var resolution="' + resolution + '";var audio_track="' + audio_track + '";var force_vod="' + force_vod + '";var inning_half="' + inning_half + '";var inning_number="' + inning_number + '";var skip="' + skip + '";var skip_adjust="' + skip_adjust + '";var pad="' + pad + '";var linkType="' + linkType + '";var startFrom="' + startFrom + '";var scores="' + scores + '";var controls="' + controls + '";var scan_mode="' + scan_mode + '";var content_protect="' + content_protect + '";' + "\n"
1365
1378
 
1366
1379
  // Reload function, called after options change
1367
- body += 'var defaultDate="' + today + '";var curDate=new Date();var utcHours=curDate.getUTCHours();if ((utcHours >= ' + todayUTCHours + ') && (utcHours < ' + YESTERDAY_UTC_HOURS + ')){defaultDate="' + yesterday + '"}function reload(){var newurl="/?";if (date != defaultDate){var urldate=date;if (date == "' + today + '"){urldate="today"}else if (date == "' + yesterday + '"){urldate="yesterday"}newurl+="date="+urldate+"&"}if (level != "' + default_level + '"){newurl+="level="+encodeURIComponent(level)+"&"}if (org != "All"){newurl+="org="+encodeURIComponent(org)+"&"}if (mediaType != "' + VALID_MEDIA_TYPES[0] + '"){newurl+="mediaType="+mediaType+"&"}if (mediaType=="Video"){if (resolution != "' + VALID_RESOLUTIONS[0] + '"){newurl+="resolution="+resolution+"&"}if (audio_track != "' + VALID_AUDIO_TRACKS[0] + '"){newurl+="audio_track="+encodeURIComponent(audio_track)+"&"}else if (resolution == "none"){newurl+="audio_track="+encodeURIComponent("' + VALID_AUDIO_TRACKS[2] + '")+"&"}if (inning_half != "' + VALID_INNING_HALF[0] + '"){newurl+="inning_half="+inning_half+"&"}if (inning_number != "' + VALID_INNING_NUMBER[0] + '"){newurl+="inning_number="+inning_number+"&"}if (skip != "' + VALID_SKIP[0] + '"){newurl+="skip="+skip+"&";}}if (pad != "' + VALID_PAD[0] + '"){newurl+="pad="+pad+"&";}if (linkType != "' + VALID_LINK_TYPES[0] + '"){newurl+="linkType="+linkType+"&"}if (linkType=="' + VALID_LINK_TYPES[0] + '"){if (startFrom != "' + VALID_START_FROM[0] + '"){newurl+="startFrom="+startFrom+"&"}if (controls != "' + VALID_CONTROLS[0] + '"){newurl+="controls="+controls+"&"}}if (linkType=="Stream"){if (force_vod != "' + VALID_FORCE_VOD[0] + '"){newurl+="force_vod="+force_vod+"&"}}if (scores != "' + VALID_SCORES[0] + '"){newurl+="scores="+scores+"&"}if (scan_mode != "' + session.data.scan_mode + '"){newurl+="scan_mode="+scan_mode+"&"}if (content_protect != ""){newurl+="content_protect="+content_protect+"&"}window.location=newurl.substring(0,newurl.length-1)}' + "\n"
1380
+ body += 'var defaultDate="' + today + '";var curDate=new Date();var utcHours=curDate.getUTCHours();if ((utcHours >= ' + todayUTCHours + ') && (utcHours < ' + YESTERDAY_UTC_HOURS + ')){defaultDate="' + yesterday + '"}function reload(){var newurl="/?";if (date != defaultDate){var urldate=date;if (date == "' + today + '"){urldate="today"}else if (date == "' + yesterday + '"){urldate="yesterday"}newurl+="date="+urldate+"&"}if (level != "' + default_level + '"){newurl+="level="+encodeURIComponent(level)+"&"}if (org != "All"){newurl+="org="+encodeURIComponent(org)+"&"}if (mediaType != "' + VALID_MEDIA_TYPES[0] + '"){newurl+="mediaType="+mediaType+"&"}if (mediaType=="Video"){if (resolution != "' + VALID_RESOLUTIONS[0] + '"){newurl+="resolution="+resolution+"&"}if (audio_track != "' + VALID_AUDIO_TRACKS[0] + '"){newurl+="audio_track="+encodeURIComponent(audio_track)+"&"}else if (resolution == "none"){newurl+="audio_track="+encodeURIComponent("' + VALID_AUDIO_TRACKS[2] + '")+"&"}if (inning_half != "' + VALID_INNING_HALF[0] + '"){newurl+="inning_half="+inning_half+"&"}if (inning_number != "' + VALID_INNING_NUMBER[0] + '"){newurl+="inning_number="+inning_number+"&"}if (skip != "' + VALID_SKIP[0] + '"){newurl+="skip="+skip+"&";if (skip_adjust != "' + DEFAULT_SKIP_ADJUST + '"){newurl+="skip_adjust="+skip_adjust+"&"}}}if (pad != "' + VALID_PAD[0] + '"){newurl+="pad="+pad+"&";}if (linkType != "' + VALID_LINK_TYPES[0] + '"){newurl+="linkType="+linkType+"&"}if (linkType=="' + VALID_LINK_TYPES[0] + '"){if (startFrom != "' + VALID_START_FROM[0] + '"){newurl+="startFrom="+startFrom+"&"}if (controls != "' + VALID_CONTROLS[0] + '"){newurl+="controls="+controls+"&"}}if (linkType=="Stream"){if (force_vod != "' + VALID_FORCE_VOD[0] + '"){newurl+="force_vod="+force_vod+"&"}}if (scores != "' + VALID_SCORES[0] + '"){newurl+="scores="+scores+"&"}if (scan_mode != "' + session.data.scan_mode + '"){newurl+="scan_mode="+scan_mode+"&"}if (content_protect != ""){newurl+="content_protect="+content_protect+"&"}window.location=newurl.substring(0,newurl.length-1)}' + "\n"
1368
1381
 
1369
1382
  // Ajax function for multiview and highlights
1370
1383
  body += 'function makeGETRequest(url, callback){var request=new XMLHttpRequest();request.onreadystatechange=function(){if (request.readyState==4 && request.status==200){callback(request.responseText)}};request.open("GET", url);request.send();}' + "\n"
@@ -1546,7 +1559,7 @@ app.get('/', async function(req, res) {
1546
1559
  }*/
1547
1560
 
1548
1561
  if ( (gameDate >= today) && cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
1549
- blackouts = await session.get_blackout_games(cache_data.dates[0].games, true)
1562
+ blackouts = await session.get_blackout_games(cache_data.dates[0].date, true)
1550
1563
  }
1551
1564
 
1552
1565
  // Big Inning
@@ -1835,7 +1848,7 @@ app.get('/', async function(req, res) {
1835
1848
  if ( inning_half != VALID_INNING_HALF[0] ) querystring += '&inning_half=' + inning_half
1836
1849
  if ( inning_number != VALID_INNING_NUMBER[0] ) querystring += '&inning_number=' + relative_inning
1837
1850
  if ( skip != VALID_SKIP[0] ) querystring += '&skip=' + skip
1838
- //if ( skip_adjust != DEFAULT_SKIP_ADJUST ) querystring += '&skip_adjust=' + skip_adjust
1851
+ if ( skip_adjust != DEFAULT_SKIP_ADJUST ) querystring += '&skip_adjust=' + skip_adjust
1839
1852
  }
1840
1853
  if ( pad != VALID_PAD[0] ) querystring += '&pad=' + pad
1841
1854
  if ( linkType == VALID_LINK_TYPES[1] ) {
@@ -1927,6 +1940,7 @@ app.get('/', async function(req, res) {
1927
1940
  if ( inning_half != VALID_INNING_HALF[0] ) querystring += '&inning_half=' + inning_half
1928
1941
  if ( inning_number != VALID_INNING_NUMBER[0] ) querystring += '&inning_number=' + relative_inning
1929
1942
  if ( skip != VALID_SKIP[0] ) querystring += '&skip=' + skip
1943
+ if ( skip_adjust != DEFAULT_SKIP_ADJUST ) querystring += '&skip_adjust=' + skip_adjust
1930
1944
  if ( (inning_half != VALID_INNING_HALF[0]) || (inning_number != VALID_INNING_NUMBER[0]) || (skip != VALID_SKIP[0]) ) {
1931
1945
  querystring += '&gamePk=' + cache_data.dates[0].games[j].gamePk
1932
1946
  }
@@ -2053,6 +2067,9 @@ app.get('/', async function(req, res) {
2053
2067
  if ( skip == VALID_SKIP[i] ) body += 'class="default" '
2054
2068
  body += 'onclick="skip=\'' + VALID_SKIP[i] + '\';reload()">' + VALID_SKIP[i] + '</button> '
2055
2069
  }
2070
+ if ( skip != VALID_SKIP[0] ) {
2071
+ body += '<br><span class="tooltip">Skip Adjust<span class="tooltiptext">Seconds to adjust the skip time video segments, if necessary. Try a negative number if the plays are ending before the video segments begin; use a positive number if the video segments are ending before the play happens.</span></span>: <input type="number" id="skip_adjust" value="' + skip_adjust + '" step="1" onchange="setTimeout(function(){skip_adjust=document.getElementById(\'skip_adjust\').value;reload()},750)" onblur="skip_adjust=this.value;reload()" style="vertical-align:top;font-size:.8em;width:3em"/>'
2072
+ }
2056
2073
  body += '</p>' + "\n"
2057
2074
  }
2058
2075
 
@@ -2215,7 +2232,7 @@ app.get('/', async function(req, res) {
2215
2232
  body += '<p><span class="tooltip">Bookmarklets for MLB.com<span class="tooltiptext">If you watch at MLB.com, drag these bookmarklets to your bookmarks toolbar and use them to hide parts of the interface.</span></span>: <a href="javascript:(function(){let x=document.querySelector(\'#mlbtv-stats-panel\');if(x.style.display==\'none\'){x.style.display=\'initial\';}else{x.style.display=\'none\';}})();">Boxscore</a> | <a href="javascript:(function(){let x=document.querySelector(\'.mlbtv-header-container\');if(x.style.display==\'none\'){let y=document.querySelector(\'.mlbtv-players-container\');y.style.display=\'none\';x.style.display=\'initial\';setTimeout(function(){y.style.display=\'initial\';},15);}else{x.style.display=\'none\';}})();">Scoreboard</a> | <a href="javascript:(function(){let x=document.querySelector(\'.mlbtv-container--footer\');if(x.style.display==\'none\'){let y=document.querySelector(\'.mlbtv-players-container\');y.style.display=\'none\';x.style.display=\'initial\';setTimeout(function(){y.style.display=\'initial\';},15);}else{x.style.display=\'none\';}})();">Linescore</a> | <a href="javascript:(function(){let x=document.querySelector(\'#mlbtv-stats-panel\');if(x.style.display==\'none\'){x.style.display=\'initial\';}else{x.style.display=\'none\';}x=document.querySelector(\'.mlbtv-header-container\');if(x.style.display==\'none\'){x.style.display=\'initial\';}else{x.style.display=\'none\';}x=document.querySelector(\'.mlbtv-container--footer\');if(x.style.display==\'none\'){let y=document.querySelector(\'.mlbtv-players-container\');y.style.display=\'none\';x.style.display=\'initial\';setTimeout(function(){y.style.display=\'initial\';},15);}else{x.style.display=\'none\';}})();">All</a></p>' + "\n"
2216
2233
 
2217
2234
  // Print version
2218
- body += '<p class="tinytext">Version ' + version + ' (<a href="/clearcache">clear cache</a>)</p>' + "\n"
2235
+ body += '<p class="tinytext">Version ' + version + ' (<a href="/clearcache">clear session and cache</a>)</p>' + "\n"
2219
2236
 
2220
2237
  // Datepicker functions
2221
2238
  body += '<script>var datePicker=document.getElementById("gameDate");function changeDate(e){date=datePicker.value;reload()}function removeDate(e){datePicker.removeEventListener("change",changeDate,false);datePicker.addEventListener("blur",changeDate,false);if(e.keyCode===13){date=datePicker.value;reload()}}datePicker.addEventListener("change",changeDate,false);datePicker.addEventListener("keypress",removeDate,false)</script>' + "\n"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlbserver",
3
- "version": "2024.08.02",
3
+ "version": "2024.10.01",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
package/session.js CHANGED
@@ -1201,6 +1201,17 @@ class sessionClass {
1201
1201
  this.save_cache_data()
1202
1202
  }
1203
1203
 
1204
+ setBlackoutsCacheExpiry(cache_name, expiryDate) {
1205
+ if ( !this.cache.blackouts ) {
1206
+ this.cache.blackouts={}
1207
+ }
1208
+ if ( !this.cache.blackouts[cache_name] ) {
1209
+ this.cache.blackouts[cache_name] = {}
1210
+ }
1211
+ this.cache.blackouts[cache_name].blackoutsCacheExpiry = expiryDate
1212
+ this.save_cache_data()
1213
+ }
1214
+
1204
1215
  setDateCacheExpiry(cache_name, expiryDate) {
1205
1216
  if ( !this.cache.dates ) {
1206
1217
  this.cache.dates={}
@@ -1663,6 +1674,7 @@ class sessionClass {
1663
1674
  this.data.loginToken = obj.access_token
1664
1675
  this.data.loginTokenExpiry = new Date(new Date().getTime() + obj.expires_in * 1000)
1665
1676
  this.save_session_data()
1677
+ await this.getSession()
1666
1678
  return this.data.loginToken
1667
1679
  } else {
1668
1680
  this.log('getLoginToken response failure')
@@ -1714,7 +1726,7 @@ class sessionClass {
1714
1726
  let nationalCount = 0
1715
1727
  let freeCount = 0
1716
1728
  let blackouts = {}
1717
- if ( includeBlackouts == 'false' ) blackouts = await this.get_blackout_games(cache_data.dates[0].games, true)
1729
+ if ( includeBlackouts == 'false' ) blackouts = await this.get_blackout_games(cache_data.dates[0].date, true)
1718
1730
 
1719
1731
  for (var j = 0; j < cache_data.dates[0].games.length; j++) {
1720
1732
  if ( mediaInfo.mediaId || mediaInfo.gamePk ) break
@@ -2181,13 +2193,14 @@ class sessionClass {
2181
2193
 
2182
2194
  let gameIndexes_obj = {}
2183
2195
 
2196
+ let blackouts = {}
2197
+ if ( includeBlackouts == 'false' ) blackouts = await this.get_blackout_games()
2198
+
2184
2199
  for (var i = 0; i < cache_data.dates.length; i++) {
2185
2200
  this.debuglog('getTVData processing date ' + cache_data.dates[i].date)
2186
2201
  let dateIndex = {MLBTV:i,Free:i,Audio:i}
2187
2202
  let gameCounter = {MLBTV:0,Free:0,Audio:0}
2188
2203
 
2189
- let blackouts = {}
2190
- if ( includeBlackouts == 'false' ) blackouts = await this.get_blackout_games(cache_data.dates[i].games)
2191
2204
  let gameIndexes = await this.get_first_and_last_games(cache_data.dates[i].games, blackouts)
2192
2205
  // store gameIndexes for gamechanger/multiview reference later
2193
2206
  gameIndexes_obj[cache_data.dates[i].date] = gameIndexes
@@ -2829,6 +2842,9 @@ class sessionClass {
2829
2842
  if ( streamURLToken ) {
2830
2843
  variant_url += '&streamURLToken=' + encodeURIComponent(streamURLToken)
2831
2844
  }
2845
+ if ( this.protection.content_protect ) {
2846
+ variant_url += '&content_protect=' + this.protection.content_protect
2847
+ }
2832
2848
  let reqObj = {
2833
2849
  url: variant_url
2834
2850
  }
@@ -2853,10 +2869,12 @@ class sessionClass {
2853
2869
  }
2854
2870
 
2855
2871
  // Get skip markers into temporary cache
2856
- async getSkipMarkers(gamePk, skip_type, start_inning, start_inning_half, streamURL, streamURLToken) {
2872
+ async getSkipMarkers(gamePk, skip_type, start_inning, start_inning_half, streamURL, streamURLToken, skip_adjust) {
2857
2873
  try {
2858
2874
  this.debuglog('getSkipMarkers')
2859
2875
 
2876
+ if ( skip_adjust != 0 ) this.log('manual adjustment of ' + skip_adjust + ' seconds being applied')
2877
+
2860
2878
  if ( !this.temp_cache[gamePk] ) {
2861
2879
  this.temp_cache[gamePk] = {}
2862
2880
  }
@@ -2972,6 +2990,8 @@ class sessionClass {
2972
2990
  // then we'll add the skip marker
2973
2991
  // otherwise we'll ignore it and move on to the next one
2974
2992
  if ( ((break_end - break_start) >= MINIMUM_BREAK_DURATION) && ((skip_type != 1) || (current_inning != previous_inning) || (current_inning_half != previous_inning_half)) ) {
2993
+ if ( break_start > 0 ) break_start += skip_adjust
2994
+ break_end += skip_adjust
2975
2995
  skip_markers.push({'break_start': break_start, 'break_end': break_end})
2976
2996
  total_skip_time += break_end - break_start
2977
2997
  previous_inning = current_inning
@@ -3486,71 +3506,111 @@ class sessionClass {
3486
3506
  return regional_fox_games_exist
3487
3507
  }
3488
3508
 
3509
+ // get blackouts data for a day
3510
+ async getBlackoutsData(dateString, endDate) {
3511
+ try {
3512
+ let cache_data
3513
+ let cache_name = 'b' + dateString
3514
+ let data_url = 'https://mastapi.mobile.mlbinfra.com/api/epg/v3/search?exp=MLB&date=' + dateString
3515
+ let utcHours = 10
3516
+ if ( dateString == 'guide' ) {
3517
+ cache_name = 'bweek'
3518
+ this.debuglog('getBlackoutsData for week')
3519
+ let startDate = this.liveDate(utcHours)
3520
+ let endDate = new Date(startDate)
3521
+ endDate.setDate(endDate.getDate()+20)
3522
+ endDate = endDate.toISOString().substring(0,10)
3523
+ data_url = 'https://mastapi.mobile.mlbinfra.com/api/epg/v3/search?exp=MLB&startDate=' + startDate + '&endDate=' + endDate
3524
+ } else {
3525
+ this.debuglog('getBlackoutsData for ' + dateString)
3526
+ }
3527
+ let cache_file = path.join(this.CACHE_DIRECTORY, cache_name+'.json')
3528
+ let currentDate = new Date()
3529
+ if ( !fs.existsSync(cache_file) || !this.cache || !this.cache.blackouts || !this.cache.blackouts[cache_name] || !this.cache.blackouts[cache_name].blackoutsCacheExpiry || (currentDate > new Date(this.cache.blackouts[cache_name].blackoutsCacheExpiry)) ) {
3530
+ let reqObj = {
3531
+ url: data_url,
3532
+ headers: {
3533
+ 'Accept': '*/*',
3534
+ 'Accept-Language': 'en-US,en;q=0.9',
3535
+ 'Content-Type': 'application/json',
3536
+ 'Origin': 'https://www.mlb.com',
3537
+ 'Referer': 'https://www.mlb.com/',
3538
+ 'User-Agent': USER_AGENT
3539
+ }
3540
+ }
3541
+ var response = await this.httpGet(reqObj, false)
3542
+ if ( response && this.isValidJson(response) ) {
3543
+ //this.debuglog(response)
3544
+ cache_data = JSON.parse(response)
3545
+ this.save_json_cache_file(cache_name, cache_data)
3546
+
3547
+ // Default cache period is 1 day from now
3548
+ let today = this.liveDate()
3549
+ let tomorrowDate = new Date(today)
3550
+ tomorrowDate.setDate(tomorrowDate.getDate()+1)
3551
+ tomorrowDate.setHours(tomorrowDate.getHours()+utcHours)
3552
+ let cacheExpiry = tomorrowDate
3553
+
3554
+ // finally save the setting
3555
+ this.setBlackoutsCacheExpiry(cache_name, cacheExpiry)
3556
+ } else {
3557
+ this.log('error : invalid json from url ' + reqObj.url)
3558
+ }
3559
+ } else {
3560
+ this.debuglog('using cached date data')
3561
+ cache_data = this.readFileToJson(cache_file)
3562
+ }
3563
+ if (cache_data) {
3564
+ return cache_data
3565
+ }
3566
+ } catch(e) {
3567
+ this.log('getBlackoutsData error : ' + e.message)
3568
+ }
3569
+ }
3570
+
3489
3571
  // get all blackout games for a date
3490
- async get_blackout_games(games, calculate_expiries=false) {
3572
+ async get_blackout_games(gameDate='guide', calculate_expiries=false) {
3491
3573
  this.debuglog('get_blackout_games')
3492
3574
  let blackouts = {}
3493
3575
 
3494
- let usa_blackout = /(^\d{5}$)/.test(this.credentials.zip_code) && (this.credentials.country == 'USA')
3576
+ let cache_data
3577
+ cache_data = await this.getBlackoutsData(gameDate)
3578
+
3579
+ if ( cache_data && cache_data.results && (cache_data.results.length > 0) ) {
3580
+ for (var j = 0; j < cache_data.results.length; j++) {
3581
+ let game = cache_data.results[j]
3582
+ let game_pk = game.gamePk
3583
+ this.debuglog('get_blackout_games checking game ' + game_pk)
3584
+ if ( game.blackedOutVideo ) {
3585
+ this.debuglog('get_blackout_games found blackout')
3586
+ let blackout_type = ''
3587
+ // local/national blackout label disabled, as all were returning local
3588
+ /*if ( game.videoStatusCodes.includes('2') ) {
3589
+ this.debuglog('get_blackout_games found national blackout')
3590
+ blackout_type = 'National/International'
3591
+ } else {
3592
+ this.debuglog('get_blackout_games found local blackout')
3593
+ blackout_type = 'Local'
3594
+ }*/
3595
+ blackouts[game_pk] = { blackout_type: blackout_type }
3596
+ }
3495
3597
 
3496
- let regional_fox_games_exist
3497
- for (var j = 0; j < games.length; j++) {
3498
- let game_pk = games[j].gamePk.toString()
3499
- this.debuglog('get_blackout_games checking game ' + game_pk)
3500
- if ( games[j].broadcasts ) {
3501
- for (var k = 0; k < games[j].broadcasts.length; k++) {
3502
- let broadcast = games[j].broadcasts[k]
3503
- if ( broadcast.type == 'TV' ) {
3504
- this.debuglog('get_blackout_games checking feed ' + broadcast.callSign)
3505
- if ( (broadcast.isNational == true) || (await this.check_pay_tv(broadcast)) || broadcast.callSign.endsWith('-INT') ) {
3506
- this.debuglog('get_blackout_games checking national game')
3507
- // International blackouts according to https://www.mlb.com/live-stream-games/help-center/blackouts-available-games
3508
- if ( usa_blackout && (broadcast.callSign == 'FOX') ) {
3509
- if ( !regional_fox_games_exist && (games[j].seriesDescription == 'Regular Season') ) {
3510
- regional_fox_games_exist = await this.check_regional_fox_games(games)
3511
- }
3512
- if ( !regional_fox_games_exist || (regional_fox_games_exist == 'false') ) {
3513
- this.debuglog('get_blackout_games found non-regional FOX game')
3514
- blackouts[game_pk] = { blackout_type:'National' }
3515
- break
3516
- }
3517
- // Apple TV+ games are blacked out everywhere
3518
- } else if ( broadcast.callSign == 'Apple TV+' ) {
3519
- this.debuglog('get_blackout_games found Apple TV+ blackout')
3520
- blackouts[game_pk] = { blackout_type:'Full International' }
3521
- // ESPN Sunday Night games are blacked out in a list of countries
3522
- } else if ( (broadcast.callSign == 'ESPN') && (new Date(games[j].gameDate).getDay() == 0) && ESPN_SUNDAY_NIGHT_BLACKOUT_COUNTRIES.includes(this.credentials.country) ) {
3523
- this.debuglog('get_blackout_games found ESPN blackout')
3524
- blackouts[game_pk] = { blackout_type:'Partial International' }
3525
- // games with an "-INT" variant are postseason games, blacked out in USA and Canada
3526
- } else if ( broadcast.callSign.endsWith('-INT') && (usa_blackout || (this.credentials.country == 'Canada')) ) {
3527
- this.debuglog('get_blackout_games found national blackout')
3528
- blackouts[game_pk] = { blackout_type:'National' }
3529
- } else if ( usa_blackout ) {
3530
- this.debuglog('get_blackout_games found USA blackout')
3531
- blackouts[game_pk] = { blackout_type:'National' }
3532
- }
3533
- break
3534
- // check local blackouts
3535
- } else {
3536
- this.debuglog('get_blackout_games checking local game')
3537
- let awayteam = games[j].teams['away'].team.abbreviation
3538
- let hometeam = games[j].teams['home'].team.abbreviation
3539
- if ( (games[j].seriesDescription != 'Spring Training') && (this.credentials.blackout_teams.includes(hometeam) || this.credentials.blackout_teams.includes(awayteam)) ) {
3540
- this.debuglog('get_blackout_games found local blackout')
3541
- blackouts[game_pk] = { blackout_type:'Local' }
3598
+ // add blackout expiry, if requested
3599
+ if ( blackouts[game_pk] && calculate_expiries && await this.check_game_time(game.gameData) ) {
3600
+ this.debuglog('get_blackout_games calculating blackout expiry')
3601
+ let date_cache_data = await this.getDayData(gameDate)
3602
+ if ( date_cache_data.dates && date_cache_data.dates[0] && date_cache_data.dates[0].games && (date_cache_data.dates[0].games.length > 0) ) {
3603
+ for (var k = 0; k < date_cache_data.dates[0].games.length; k++) {
3604
+ if ( game_pk == date_cache_data.dates[0].games[k].gamePk ) {
3605
+ this.debuglog('get_blackout_games found matching game')
3606
+ let blackoutExpiry = await this.get_blackout_expiry(date_cache_data.dates[0].games[k])
3607
+ this.debuglog('get_blackout_games calculated blackout expiry as ' + blackoutExpiry)
3608
+ blackouts[game_pk].blackoutExpiry = blackoutExpiry
3542
3609
  break
3543
3610
  }
3544
3611
  }
3545
- break
3546
3612
  }
3547
3613
  }
3548
-
3549
- // add blackout expiry, if requested
3550
- if ( blackouts[game_pk] && calculate_expiries && await this.check_game_time(games[j]) ) {
3551
- let blackoutExpiry = await this.get_blackout_expiry(games[j])
3552
- blackouts[game_pk].blackoutExpiry = blackoutExpiry
3553
- }
3554
3614
  }
3555
3615
  }
3556
3616
 
@@ -3566,7 +3626,7 @@ class sessionClass {
3566
3626
  let start
3567
3627
  let end
3568
3628
  if ( cache_data.dates && cache_data.dates[0] && cache_data.dates[0].games && (cache_data.dates[0].games.length > 0) ) {
3569
- blackouts = await this.get_blackout_games(cache_data.dates[0].games)
3629
+ blackouts = await this.get_blackout_games(today)
3570
3630
  this.debuglog('Game changer blackouts ' + JSON.stringify(blackouts))
3571
3631
 
3572
3632
  let gameIndexes = await this.get_first_and_last_games(cache_data.dates[0].games, blackouts)
@@ -4066,7 +4126,7 @@ class sessionClass {
4066
4126
  let firstGameIndex
4067
4127
  for (var j = 0; j < games.length; j++) {
4068
4128
  let gamePk = games[j].gamePk.toString()
4069
- if ( games[j].gameDate && !blackouts[gamePk] && !games[j].rescheduleDate && !games[j].status.startTimeTBD && games[j].broadcasts && (await this.count_broadcasts(games[j].broadcasts, 'MLBTV') > 0) ) {
4129
+ if ( games[j].gameDate && (games[j].teams.home.team.sport.id == 1) && (games[j].teams.away.team.sport.id == 1) && !blackouts[gamePk] && !games[j].rescheduleDate && !games[j].status.startTimeTBD && games[j].broadcasts && (await this.count_broadcasts(games[j].broadcasts, 'MLBTV') > 0) ) {
4070
4130
  this.debuglog('get_first_and_last_games first : ' + j + ' ' + gamePk + ' at ' + games[j].gameDate)
4071
4131
  firstGameIndex = j
4072
4132
  break
@@ -4075,7 +4135,7 @@ class sessionClass {
4075
4135
  let lastGameIndex
4076
4136
  for (var j = (games.length-1); j >= 0; j--) {
4077
4137
  let gamePk = games[j].gamePk.toString()
4078
- if ( games[j].gameDate && !blackouts[gamePk] && !games[j].rescheduleDate && games[j].broadcasts && (await this.count_broadcasts(games[j].broadcasts, 'MLBTV') > 0) ) {
4138
+ if ( games[j].gameDate && (games[j].teams.home.team.sport.id == 1) && (games[j].teams.away.team.sport.id == 1) && !blackouts[gamePk] && !games[j].rescheduleDate && games[j].broadcasts && (await this.count_broadcasts(games[j].broadcasts, 'MLBTV') > 0) ) {
4079
4139
  this.debuglog('get_first_and_last_games last : ' + j + ' ' + gamePk + ' at ' + games[j].gameDate)
4080
4140
  lastGameIndex = j
4081
4141
  break
@@ -4134,8 +4194,8 @@ class sessionClass {
4134
4194
  return scheduledInnings
4135
4195
  }
4136
4196
 
4137
- async check_game_time(game) {
4138
- if ( !game.resumeGameDate && !game.resumedFromDate && (game.status.startTimeTBD == false) ) {
4197
+ async check_game_time(gameData) {
4198
+ if ( !gameData.resumeGameDate && !gameData.resumedFromDate && (gameData.startTimeTBD == false) ) {
4139
4199
  return true
4140
4200
  } else {
4141
4201
  return false
@@ -4144,20 +4204,25 @@ class sessionClass {
4144
4204
 
4145
4205
  async get_blackout_expiry(game) {
4146
4206
  let scheduledInnings = await this.get_scheduled_innings(game)
4147
- // avg 9 inning game was 3:11 in 2021, or 21.22 minutes per inning
4148
- let gameDurationMinutes = 21.22 * scheduledInnings
4207
+ this.debuglog('get_blackout_expiry scheduledInnings ' + scheduledInnings)
4208
+ // avg 9 inning game was 2:39 in 2023, or 17.66 minutes per inning
4209
+ let gameDurationMinutes = 17.66 * scheduledInnings
4149
4210
  // default to assuming the scheduled game time is the first pitch time
4150
4211
  let firstPitch = new Date(game.gameDate)
4212
+ this.debuglog('get_blackout_expiry gameDate ' + firstPitch)
4151
4213
  if ( game.gameInfo ) {
4152
4214
  // check if firstPitch has been updated with a valid time (later than the scheduled game time)
4153
4215
  if ( game.gameInfo.firstPitch && (game.gameInfo.firstPitch >= game.gameDate) ) {
4154
4216
  firstPitch = new Date(game.gameInfo.firstPitch)
4217
+ this.debuglog('get_blackout_expiry firstPitch ' + firstPitch)
4155
4218
  // for completed games, get the duration too
4156
4219
  if ( game.gameInfo.gameDurationMinutes ) {
4157
4220
  gameDurationMinutes = game.gameInfo.gameDurationMinutes
4221
+ this.debuglog('get_blackout_expiry gameDurationMinutes ' + gameDurationMinutes)
4158
4222
  // add any delays
4159
4223
  if ( game.gameInfo.delayDurationMinutes ) {
4160
4224
  gameDurationMinutes += game.gameInfo.delayDurationMinutes
4225
+ this.debuglog('get_blackout_expiry delayDurationMinutes ' + game.gameInfo.delayDurationMinutes)
4161
4226
  }
4162
4227
  }
4163
4228
  }