mlbserver 2025.6.12 → 2025.6.18

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 +4 -22
  2. package/package.json +1 -1
  3. package/session.js +54 -14
package/index.js CHANGED
@@ -365,10 +365,8 @@ app.get('/stream.m3u8', async function(req, res) {
365
365
  let skip_adjust = parseInt(req.query.skip_adjust) || DEFAULT_SKIP_ADJUST
366
366
 
367
367
  let skip_type = VALID_SKIP.indexOf(options.skip)
368
- // for skip other than commercial skip, look up markers
369
- if ( skip_type != 4 ) {
370
- await session.getSkipMarkers(gamePk, skip_type, options.inning_number, options.inning_half, streamURL, streamURLToken, skip_adjust)
371
- }
368
+ // look up markers
369
+ await session.getSkipMarkers(gamePk, skip_type, options.inning_number, options.inning_half, streamURL, streamURLToken, skip_adjust)
372
370
  }
373
371
  }
374
372
 
@@ -768,23 +766,7 @@ app.get('/playlist.m3u8', async function(req, res) {
768
766
  content_protect = '&content_protect=' + session.protection.content_protect
769
767
  }
770
768
 
771
- // if skipping commercials, filter the playlist to remove ad insertion domains
772
- if ( skip == 'commercials' ) {
773
- session.debuglog('filtering commercial breaks')
774
- let new_body = []
775
- let break_active = false
776
- for (var i=0; i<body.length; i++) {
777
- if ( (break_active == false) && body[i].startsWith('#EXT-OATCLS-SCTE35:') ) {
778
- break_active = true
779
- new_body.push('#EXT-X-DISCONTINUITY')
780
- } else if ( (break_active == true) && body[i].startsWith('#EXT-X-CUE-IN') ) {
781
- break_active = false
782
- } else if ( break_active == false ) {
783
- new_body.push(body[i])
784
- }
785
- }
786
- body = new_body
787
- } else if ( (gamePk) && ((inning_half != VALID_INNING_HALF[0]) || (inning_number != VALID_INNING_NUMBER[0]) || (skip != VALID_SKIP[0])) && (typeof session.temp_cache[gamePk] !== 'undefined') && (typeof session.temp_cache[gamePk].skip_markers !== 'undefined') ) {
769
+ if ( (gamePk) && ((inning_half != VALID_INNING_HALF[0]) || (inning_number != VALID_INNING_NUMBER[0]) || (skip != VALID_SKIP[0])) && (typeof session.temp_cache[gamePk] !== 'undefined') && (typeof session.temp_cache[gamePk].skip_markers !== 'undefined') ) {
788
770
  session.debuglog('pulling skip markers from temporary cache')
789
771
  skip_markers = session.temp_cache[gamePk].skip_markers
790
772
  } else {
@@ -2214,7 +2196,7 @@ app.get('/', async function(req, res) {
2214
2196
  }
2215
2197
  body += '</p>' + "\n"
2216
2198
 
2217
- body += '<p><span class="tooltip">Skip<span class="tooltiptext">For video streams only (use the video "none" option above to apply it to audio streams): you can remove all breaks, idle time, non-action pitches, or only commercial breaks from the stream (useful to make your own "condensed games").<br/><br/>NOTE: skip timings are only generated when the stream is loaded -- so for live games, it will only skip up to the time you loaded the stream. Also, commercial break skipping will ignore inning start options (it will always start from the beginning).</span></span>: '
2199
+ body += '<p><span class="tooltip">Skip<span class="tooltiptext">For video streams only (use the video "none" option above to apply it to audio streams): you can remove all breaks, idle time, non-action pitches, or only commercial breaks from the stream (useful to make your own "condensed games").<br/><br/>NOTE: skip timings are only generated when the stream is loaded -- so for live games, it will only skip up to the time you loaded the stream.</span></span>: '
2218
2200
  for (var i = 0; i < VALID_SKIP.length; i++) {
2219
2201
  body += '<button '
2220
2202
  if ( skip == VALID_SKIP[i] ) body += 'class="default" '
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlbserver",
3
- "version": "2025.06.12",
3
+ "version": "2025.06.18",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
package/session.js CHANGED
@@ -3036,10 +3036,10 @@ class sessionClass {
3036
3036
  }
3037
3037
  }
3038
3038
 
3039
- // Get broadcast start timestamp
3040
- async getBroadcastStart(streamURL, streamURLToken) {
3039
+ // Get variant playlist
3040
+ async getVariantPlaylist(streamURL, streamURLToken) {
3041
3041
  try {
3042
- this.debuglog('getBroadcastStart')
3042
+ this.debuglog('getVariantPlaylist')
3043
3043
 
3044
3044
  // MLB version
3045
3045
  let variant = '_5600K'
@@ -3059,6 +3059,19 @@ class sessionClass {
3059
3059
  }
3060
3060
  var response = await this.httpGet(reqObj, false)
3061
3061
  var body = response.replace(/^\s+|\s+$/g, '').split('\n')
3062
+
3063
+ return body
3064
+ } catch(e) {
3065
+ this.log('getVariantPlaylist error : ' + e.message)
3066
+ }
3067
+ }
3068
+
3069
+ // Get broadcast start timestamp
3070
+ async getBroadcastStart(variantPlaylist) {
3071
+ try {
3072
+ this.debuglog('getBroadcastStart')
3073
+
3074
+ var body = variantPlaylist
3062
3075
 
3063
3076
  // check if HLS
3064
3077
  if ( body[0] != '#EXTM3U' ) {
@@ -3103,7 +3116,8 @@ class sessionClass {
3103
3116
  let break_start = 0
3104
3117
 
3105
3118
  // Get the broadcast start time first -- event times will be relative to this
3106
- let broadcast_start_timestamp = await this.getBroadcastStart(streamURL, streamURLToken)
3119
+ let variantPlaylist = await this.getVariantPlaylist(streamURL, streamURLToken)
3120
+ let broadcast_start_timestamp = await this.getBroadcastStart(variantPlaylist)
3107
3121
 
3108
3122
  if ( broadcast_start_timestamp ) {
3109
3123
  this.debuglog('getSkipMarkers broadcast start detected as ' + broadcast_start_timestamp)
@@ -3145,8 +3159,8 @@ class sessionClass {
3145
3159
  // Loop through all plays
3146
3160
  for (var i=0; i < cache_data.liveData.plays.allPlays.length; i++) {
3147
3161
 
3148
- // exit loop after found inning, if not skipping any breaks
3149
- if ((skip_type == 0) && (skip_markers.length == 1)) {
3162
+ // exit loop after found inning, if not skipping any play-defined breaks
3163
+ if ( ((skip_type == 0) || (skip_type == 4)) && (skip_markers.length == 1) ) {
3150
3164
  break
3151
3165
  }
3152
3166
 
@@ -3170,8 +3184,8 @@ class sessionClass {
3170
3184
  event_end_padding = pitch_end_padding
3171
3185
  }
3172
3186
  let action_index
3173
- // skip type 0 (none, inning start) and 1 (breaks) will look at all plays with an endTime
3174
- if ((skip_type <= 1) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime) {
3187
+ // skip type 0 (none, inning start), 1 (breaks), and 4 (commercials) will look at all plays with an endTime
3188
+ if ( ((skip_type <= 1) || (skip_type == 4)) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime ) {
3175
3189
  action_index = j
3176
3190
  // skip type 2 (idle time) will look at all non-idle plays with an endTime
3177
3191
  } else if ((skip_type == 2) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime && (!cache_data.liveData.plays.allPlays[i].playEvents[j].details || !cache_data.liveData.plays.allPlays[i].playEvents[j].details.description || !IDLE_TYPES.some(v => cache_data.liveData.plays.allPlays[i].playEvents[j].details.description.includes(v)))) {
@@ -3217,8 +3231,8 @@ class sessionClass {
3217
3231
  total_skip_time += break_end - break_start
3218
3232
  previous_inning = current_inning
3219
3233
  previous_inning_half = current_inning_half
3220
- // exit loop after found inning, if not skipping breaks
3221
- if (skip_type == 0) {
3234
+ // exit loop after found inning, if not skipping play-defined breaks
3235
+ if ( (skip_type == 0) || (skip_type == 4)) {
3222
3236
  break
3223
3237
  }
3224
3238
  }
@@ -3243,6 +3257,32 @@ class sessionClass {
3243
3257
  }
3244
3258
  }
3245
3259
  }
3260
+
3261
+ // if skipping commercials, look at the variant playlist to detect insertions
3262
+ if ( skip_type == 4 ) {
3263
+ this.debuglog('detecting commercial breaks')
3264
+ let body = variantPlaylist
3265
+ let break_active = false
3266
+ let break_end = 0
3267
+ let time_counter = 0
3268
+ if ( skip_markers.length > 0 ) {
3269
+ break_end = skip_markers[skip_markers.length-1].break_end
3270
+ }
3271
+ for (var i=0; i<body.length; i++) {
3272
+ if ( body[i].startsWith('#EXTINF:') ) {
3273
+ time_counter += parseFloat(body[i].substring(8, body[i].length-1))
3274
+ }
3275
+ if ( (time_counter > break_end) && (break_active == false) && body[i].startsWith('#EXT-OATCLS-SCTE35:') ) {
3276
+ break_active = true
3277
+ break_start = time_counter
3278
+ } else if ( (break_active == true) && body[i].startsWith('#EXT-X-CUE-IN') ) {
3279
+ break_end = time_counter
3280
+ break_active = false
3281
+ skip_markers.push({'break_start': break_start, 'break_end': break_end})
3282
+ total_skip_time += break_end - break_start
3283
+ }
3284
+ }
3285
+ }
3246
3286
 
3247
3287
  this.debuglog('getSkipMarkers found ' + new Date(total_skip_time * 1000).toISOString().substr(11, 8) + ' total skip time')
3248
3288
  }
@@ -3299,13 +3339,13 @@ class sessionClass {
3299
3339
 
3300
3340
  if ( response.data ) {
3301
3341
  for (var i=0; i < response.data.length; i++) {
3302
- if ( response.data[i].airings && (response.data[i].airings.length > 0) && response.data[i].airings[0] && response.data[i].airings[0].accessRights && response.data[i].airings[0].accessRights.live ) {
3303
- let est_date = new Date(response.data[i].airings[0].accessRights.live.startTime).toLocaleString("en-US", {timeZone: 'America/New_York'})
3342
+ if ( response.data[i].airings && (response.data[i].airings.length > 0) && response.data[i].airings[0] && response.data[i].airings[0].accessRightsV2 && response.data[i].airings[0].accessRightsV2.live ) {
3343
+ let est_date = new Date(response.data[i].airings[0].accessRightsV2.live.startTime).toLocaleString("en-US", {timeZone: 'America/New_York'})
3304
3344
  let date_array = est_date.split(',')[0].split('/')
3305
3345
  let this_datestring = date_array[2] + '-' + date_array[0].padStart(2, '0') + '-' + date_array[1].padStart(2, '0')
3306
3346
  this.cache.bigInningSchedule[this_datestring] = {
3307
- start: response.data[i].airings[0].accessRights.live.startTime,
3308
- end: response.data[i].airings[0].accessRights.live.endTime
3347
+ start: response.data[i].airings[0].accessRightsV2.live.startTime,
3348
+ end: response.data[i].airings[0].accessRightsV2.live.endTime
3309
3349
  }
3310
3350
  }
3311
3351
  }