mlbserver 2025.4.1 → 2025.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.js +18 -13
  2. package/package.json +1 -1
  3. package/session.js +36 -38
package/index.js CHANGED
@@ -44,7 +44,7 @@ const VALID_SCAN_MODES = [ 'off', 'on' ]
44
44
 
45
45
  const SAMPLE_STREAM_URL = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'
46
46
 
47
- const SECONDS_PER_SEGMENT = 5
47
+ const SECONDS_PER_SEGMENT = 4
48
48
 
49
49
  // for favorites: text, then background, based on https://teamcolors.jim-nielsen.com/
50
50
  const TEAM_COLORS = { 'ATH': ['003831', 'EFB21E'], 'ATL': ['13274F', 'CE1141'], 'AZ': ['E3D4AD', 'A71930'], 'BAL': ['000000', 'DF4601'], 'BOS': ['0D2B56', 'BD3039'], 'CHC': ['CC3433', '0E3386'], 'CWS': ['000000', 'C4CED4'], 'CIN': ['FFFFFF', 'C6011F'], 'CLE': ['002B5C', 'E31937'], 'COL': ['C4CED4', '333366'], 'DET': ['0C2C56', 'FFFFFF'], 'HOU': ['002D62', 'EB6E1F'], 'KC': ['C09A5B', '004687'], 'LAA': ['FFFFFF', 'BA0021'], 'LAD': ['FFFFFF', '005A9C'], 'MIA': ['0077C8', 'FF6600'], 'MIL': ['0A2351', 'B6922E'], 'MIN': ['D31145', '002B5C'], 'NYM': ['002D72', 'FF5910'], 'NYY': ['FFFFFF', '003087'], 'OAK': ['003831', 'EFB21E'], 'PHI': ['284898', 'E81828'], 'PIT': ['000000', 'FDB827'], 'STL': ['FEDB00', 'C41E3A'], 'SD': ['FEC325', '7F411C'], 'SF': ['000000', 'FD5A1E'], 'SEA': ['C4CED4', '005C5C'], 'TB': ['092C5C', '8FBCE6'], 'TEX': ['003278', 'C0111F'], 'TOR': ['FFFFFF', '134A8E'], 'WSH': ['AB0003', '11225B'] }
@@ -863,26 +863,31 @@ app.get('/playlist.m3u8', async function(req, res) {
863
863
  })
864
864
  .join('\n')+'\n'
865
865
 
866
+ let end_tag = '#EXT-X-ENDLIST'
866
867
  if ( pad != VALID_PAD[0] ) {
867
868
  let body_array = body.trim().split('\n')
868
- let last_segment_index = body_array.length-1
869
- if ( body_array[last_segment_index] == '#EXT-X-ENDLIST' ) {
869
+ let segment_index = body_array.length-1
870
+ if ( body_array[segment_index] == end_tag ) {
870
871
  session.debuglog('padding archive stream with extra segments')
871
- last_segment_index--
872
- while ( !body_array[last_segment_index].startsWith('#EXTINF:') ) {
873
- last_segment_index--
872
+ while ( body_array[segment_index].startsWith('#') ) {
873
+ segment_index--
874
874
  }
875
- last_segment_inf = body_array[last_segment_index]
876
- last_segment = body_array[last_segment_index+1]
877
- let pad_lines = '#EXT-X-DISCONTINUITY' + '\n' + '#EXTINF:' + SECONDS_PER_SEGMENT + '\n' + last_segment + '\n'
878
- session.debuglog(pad_lines)
875
+ let last_segment = body_array[segment_index]
876
+ body_array.pop()
879
877
  for (i=0; i<pad; i++) {
880
- body += pad_lines
878
+ body_array.push('#EXT-X-DISCONTINUITY')
879
+ body_array.push('#EXTINF:' + SECONDS_PER_SEGMENT)
880
+ body_array.push(last_segment)
881
881
  }
882
- body += '#EXT-X-ENDLIST' + '\n'
882
+ body_array.push(end_tag)
883
+ body = body_array.join('\n')
884
+ }
885
+ } else if ( force_vod != VALID_FORCE_VOD[0] ) {
886
+ let body_array = body.trim().split('\n')
887
+ if ( body_array[body_array.length-1] != end_tag ) {
888
+ body += end_tag + '\n'
883
889
  }
884
890
  }
885
- if ( force_vod != VALID_FORCE_VOD[0] ) body += '#EXT-X-ENDLIST' + '\n'
886
891
  session.debuglog(body)
887
892
  respond(response, res, Buffer.from(body))
888
893
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlbserver",
3
- "version": "2025.04.01",
3
+ "version": "2025.04.02",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
package/session.js CHANGED
@@ -1311,7 +1311,11 @@ class sessionClass {
1311
1311
  requestlog(type, req, debug=false) {
1312
1312
  if ( req.url ) {
1313
1313
  let msg = type + ' request : ' + req.url
1314
- if ( req.connection && req.connection.remoteAddress ) msg += ' from: ' + req.connection.remoteAddress
1314
+ if ( req.headers && req.headers['x-forwarded-for'] ) {
1315
+ msg += ' from: ' + req.headers['x-forwarded-for']
1316
+ } else if ( req.connection && req.connection.remoteAddress ) {
1317
+ msg += ' from: ' + req.connection.remoteAddress
1318
+ }
1315
1319
  if ( req.headers && req.headers['user-agent'] ) msg += ' using: ' + req.headers['user-agent']
1316
1320
  if (!debug || this.debug) this.log(msg)
1317
1321
  }
@@ -2711,7 +2715,6 @@ class sessionClass {
2711
2715
  let title = 'MLB Big Inning'
2712
2716
  let description = 'Live look-ins and big moments from around the league'
2713
2717
 
2714
- // disabled Big Inning schedule scraping March 2025
2715
2718
  for (var i = 0; i < cache_data.dates.length; i++) {
2716
2719
  // Scraped Big Inning schedule
2717
2720
  if ( (cache_data.dates[i].date >= today) && cache_data.dates[i].games && (cache_data.dates[i].games.length > 1) && cache_data.dates[i].games[0] && (cache_data.dates[i].games[0].seriesDescription == 'Regular Season') ) {
@@ -2719,20 +2722,12 @@ class sessionClass {
2719
2722
  }
2720
2723
  this.debuglog('getTVData processing Big Inning for date ' + cache_data.dates[i].date)
2721
2724
  let gameDate = cache_data.dates[i].date
2722
- // Disabled Big Inning specific schedule scraping
2723
- //if ( this.cache.bigInningSchedule && this.cache.bigInningSchedule[gameDate] && this.cache.bigInningSchedule[gameDate].start ) {
2724
- //if ( (gameDate >= today) && cache_data.dates[i].games && (cache_data.dates[i].games.length > 1) && cache_data.dates[i].games[0] && (cache_data.dates[i].games[0].seriesDescription == 'Regular Season') ) {
2725
2725
  if ( (gameDate >= today) && cache_data.dates[i].games && (cache_data.dates[i].games.length > 1) && cache_data.dates[i].games[0] && (cache_data.dates[i].games[0].seriesDescription == 'Regular Season') && this.cache.bigInningSchedule[gameDate] ) {
2726
2726
  this.debuglog('getTVData Big Inning active for date ' + cache_data.dates[i].date)
2727
2727
  // Scraped Big Inning schedule
2728
2728
  let start = this.convertDateToXMLTV(new Date(this.cache.bigInningSchedule[gameDate].start))
2729
2729
  let stop = this.convertDateToXMLTV(new Date(this.cache.bigInningSchedule[gameDate].end))
2730
2730
 
2731
- // Generated Big Inning schedule (disabled)
2732
- //let big_inning = await this.generateBigInningSchedule(gameDate)
2733
- //let start = this.convertDateToXMLTV(new Date(big_inning.start))
2734
- //let stop = this.convertDateToXMLTV(new Date(big_inning.end))
2735
-
2736
2731
  // Big Inning calendar ICS
2737
2732
  let prefix = 'Watch'
2738
2733
  let location = server + '/embed.html?event=biginning&mediaType=Video&resolution=' + resolution
@@ -3054,6 +3049,21 @@ class sessionClass {
3054
3049
  // make sure we have play data
3055
3050
  if (cache_data && cache_data.liveData && cache_data.liveData.plays && cache_data.liveData.plays.allPlays) {
3056
3051
 
3052
+ // make sure start inning is valid
3053
+ if (start_inning > 0) {
3054
+ let last_play_index = cache_data.liveData.plays.allPlays.length - 1
3055
+ let final_inning = cache_data.liveData.plays.allPlays[last_play_index].about.inning
3056
+ if (start_inning >= final_inning) {
3057
+ if (start_inning > final_inning) {
3058
+ start_inning = final_inning
3059
+ let final_inning_half = json_source['liveData']['plays']['allPlays'][last_play_index]['about']['halfInning']
3060
+ if ((start_inning_half == 'bottom') && (final_inning_half == 'top')) {
3061
+ start_inning_half = final_inning_half
3062
+ }
3063
+ }
3064
+ }
3065
+ }
3066
+
3057
3067
  // keep track of inning, if skipping inning breaks only
3058
3068
  let previous_inning = 0
3059
3069
  let previous_inning_half = ''
@@ -3064,21 +3074,6 @@ class sessionClass {
3064
3074
  // Loop through all plays
3065
3075
  for (var i=0; i < cache_data.liveData.plays.allPlays.length; i++) {
3066
3076
 
3067
- // make sure start inning is valid
3068
- if (start_inning > 0) {
3069
- let last_play_index = cache_data.liveData.plays.allPlays.length - 1
3070
- let final_inning = cache_data.liveData.plays.allPlays[last_play_index].about.inning
3071
- if (start_inning >= final_inning) {
3072
- if (start_inning > final_inning) {
3073
- start_inning = final_inning
3074
- let final_inning_half = json_source['liveData']['plays']['allPlays'][last_play_index]['about']['halfInning']
3075
- if ((start_inning_half == 'bottom') && (final_inning_half == 'top')) {
3076
- start_inning_half = final_inning_half
3077
- }
3078
- }
3079
- }
3080
- }
3081
-
3082
3077
  // exit loop after found inning, if not skipping any breaks
3083
3078
  if ((skip_type == 0) && (skip_markers.length == 1)) {
3084
3079
  break
@@ -3104,8 +3099,8 @@ class sessionClass {
3104
3099
  event_end_padding = pitch_end_padding
3105
3100
  }
3106
3101
  let action_index
3107
- // skip type 1 (breaks) will look at all plays with an endTime
3108
- if ((skip_type == 1) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime) {
3102
+ // skip type 0 (none, inning start) and 1 (breaks) will look at all plays with an endTime
3103
+ if ((skip_type <= 1) && cache_data.liveData.plays.allPlays[i].playEvents[j].endTime) {
3109
3104
  action_index = j
3110
3105
  // skip type 2 (idle time) will look at all non-idle plays with an endTime
3111
3106
  } 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)))) {
@@ -3206,7 +3201,7 @@ class sessionClass {
3206
3201
  if ( !this.cache || !this.cache.bigInningScheduleCacheExpiry || (currentDate > new Date(this.cache.bigInningScheduleCacheExpiry)) ) {
3207
3202
  if ( !this.cache.bigInningSchedule ) this.cache.bigInningSchedule = {}
3208
3203
  let reqObj = {
3209
- url: 'https://www.fubo.tv/welcome/channel/mlb-big-inning',
3204
+ url: 'https://api.fubo.tv/gg/series/123881219/live-programs?limit=14&languages=en&countrySlugs=USA',
3210
3205
  headers: {
3211
3206
  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
3212
3207
  'accept-language': 'en-US,en;q=0.9',
@@ -3224,21 +3219,24 @@ class sessionClass {
3224
3219
  'upgrade-insecure-requests': '1',
3225
3220
  'user-agent': USER_AGENT
3226
3221
  },
3222
+ json: true,
3227
3223
  gzip: true
3228
3224
  }
3229
3225
  var response = await this.httpGet(reqObj, false)
3230
3226
  if ( response ) {
3231
- // disabled because it's very big!
3232
- //this.debuglog(response)
3227
+ this.debuglog(JSON.stringify(response))
3233
3228
 
3234
- let obj = JSON.parse(response.replace(/\\"/g, '"').match('(?<="channelPrograms":{"live":)(.+?(,"totalPages":1}))')[0])
3235
- for (var i=0; i < obj.data.length; i++) {
3236
- let est_date = new Date(obj.data[i].airings[0].start).toLocaleString("en-US", {timeZone: 'America/New_York'})
3237
- let date_array = est_date.split(',')[0].split('/')
3238
- let this_datestring = date_array[2] + '-' + date_array[0].padStart(2, '0') + '-' + date_array[1].padStart(2, '0')
3239
- this.cache.bigInningSchedule[this_datestring] = {
3240
- start: obj.data[i].airings[0].start,
3241
- end: obj.data[i].airings[0].end
3229
+ if ( response.data ) {
3230
+ for (var i=0; i < response.data.length; i++) {
3231
+ 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 ) {
3232
+ let est_date = new Date(response.data[i].airings[0].accessRights.live.startTime).toLocaleString("en-US", {timeZone: 'America/New_York'})
3233
+ let date_array = est_date.split(',')[0].split('/')
3234
+ let this_datestring = date_array[2] + '-' + date_array[0].padStart(2, '0') + '-' + date_array[1].padStart(2, '0')
3235
+ this.cache.bigInningSchedule[this_datestring] = {
3236
+ start: response.data[i].airings[0].accessRights.live.startTime,
3237
+ end: response.data[i].airings[0].accessRights.live.endTime
3238
+ }
3239
+ }
3242
3240
  }
3243
3241
  }
3244
3242
  this.debuglog(JSON.stringify(this.cache.bigInningSchedule))