mlbserver 2025.8.16 → 2025.8.17
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/index.js +62 -4
- package/package.json +1 -1
- package/session.js +29 -1
package/index.js
CHANGED
|
@@ -295,7 +295,7 @@ app.get('/stream.m3u8', async function(req, res) {
|
|
|
295
295
|
options.resolution = req.query.resolution
|
|
296
296
|
options.audio_track = VALID_AUDIO_TRACKS[0]
|
|
297
297
|
if ( req.query.audio_track ) {
|
|
298
|
-
options.audio_track =
|
|
298
|
+
options.audio_track = req.query.audio_track.split(' ')[0]
|
|
299
299
|
}
|
|
300
300
|
options.captions = req.query.captions || VALID_CAPTIONS[0]
|
|
301
301
|
options.force_vod = req.query.force_vod || VALID_FORCE_VOD[0]
|
|
@@ -339,6 +339,17 @@ app.get('/stream.m3u8', async function(req, res) {
|
|
|
339
339
|
} else {
|
|
340
340
|
mediaId = mediaInfo.mediaId
|
|
341
341
|
gamePk = mediaInfo.gamePk
|
|
342
|
+
if ( mediaInfo.teamType ) {
|
|
343
|
+
if ( options.audio_track.toLowerCase() == 'radio' ) {
|
|
344
|
+
options.audio_track = mediaInfo.teamType
|
|
345
|
+
} else if ( options.audio_track.toLowerCase() == 'spanish' ) {
|
|
346
|
+
if ( mediaInfo.teamType == 'Away' ) {
|
|
347
|
+
options.audio_track = VALID_AUDIO_TRACKS[5]
|
|
348
|
+
} else {
|
|
349
|
+
options.audio_track = VALID_AUDIO_TRACKS[3]
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
342
353
|
}
|
|
343
354
|
} else {
|
|
344
355
|
session.log('no matching game found ' + req.url)
|
|
@@ -520,6 +531,34 @@ function getMasterPlaylist(streamURL, req, res, options = {}) {
|
|
|
520
531
|
|
|
521
532
|
let resolution = options.resolution || VALID_RESOLUTIONS[0]
|
|
522
533
|
let audio_track = options.audio_track || VALID_AUDIO_TRACKS[0]
|
|
534
|
+
// if specific audio track is requested, check if master playlist contains it
|
|
535
|
+
if ( audio_track != VALID_AUDIO_TRACKS[0] ) {
|
|
536
|
+
if ( !response.body.includes(',NAME="' + audio_track) ) {
|
|
537
|
+
session.debuglog('requested ' + audio_track + ' audio track not available')
|
|
538
|
+
// fallback check other team's radio feed
|
|
539
|
+
if ( VALID_AUDIO_TRACKS.slice(2, 6).includes(audio_track) ) {
|
|
540
|
+
if ( audio_track == VALID_AUDIO_TRACKS[5] ) {
|
|
541
|
+
audio_track = VALID_AUDIO_TRACKS[3]
|
|
542
|
+
} else if ( audio_track == VALID_AUDIO_TRACKS[3] ) {
|
|
543
|
+
audio_track = VALID_AUDIO_TRACKS[5]
|
|
544
|
+
} else if ( audio_track == VALID_AUDIO_TRACKS[4] ) {
|
|
545
|
+
audio_track = VALID_AUDIO_TRACKS[2]
|
|
546
|
+
} else if ( audio_track == VALID_AUDIO_TRACKS[2] ) {
|
|
547
|
+
audio_track = VALID_AUDIO_TRACKS[4]
|
|
548
|
+
}
|
|
549
|
+
if ( !response.body.includes(',NAME="' + audio_track) ) {
|
|
550
|
+
// if fallback feed is also not available, fall back to default
|
|
551
|
+
session.debuglog('fallback ' + audio_track + ' audio track also not available')
|
|
552
|
+
audio_track = VALID_AUDIO_TRACKS[0]
|
|
553
|
+
} else {
|
|
554
|
+
session.debuglog('falling back to ' + audio_track + ' audio track')
|
|
555
|
+
}
|
|
556
|
+
} else {
|
|
557
|
+
// fall back to default
|
|
558
|
+
audio_track = VALID_AUDIO_TRACKS[0]
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
523
562
|
let captions = options.captions || VALID_CAPTIONS[0]
|
|
524
563
|
let force_vod = options.force_vod || VALID_FORCE_VOD[0]
|
|
525
564
|
|
|
@@ -2388,6 +2427,10 @@ app.get('/', async function(req, res) {
|
|
|
2388
2427
|
include_teams = session.credentials.fav_teams.toString()
|
|
2389
2428
|
}
|
|
2390
2429
|
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"
|
|
2430
|
+
|
|
2431
|
+
body += '<p><span class="tooltip">By team w/ radio<span class="tooltiptext">Same as above, but defaults to that team\'s radio track, if available.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=' + include_teams + '&audio_track=radio' + content_protect_b + '">channels.m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&audio_track=radio' + content_protect_b + '">guide.xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&audio_track=radio' + content_protect_b + '">calendar.ics</a></p>' + "\n"
|
|
2432
|
+
|
|
2433
|
+
body += '<p><span class="tooltip">By team w/ Spanish<span class="tooltiptext">Same as above, but defaults to that team\'s Spanish radio track, if available.</span></span>: <a href="' + http_root + '/channels.m3u?mediaType=' + mediaType + '&resolution=' + resolution + '&includeTeams=' + include_teams + '&audio_track=spanish' + content_protect_b + '">channels.m3u</a> and <a href="' + http_root + '/guide.xml?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&audio_track=spanish' + content_protect_b + '">guide.xml</a> and <a href="' + http_root + '/calendar.ics?mediaType=' + mediaType + '&includeTeams=' + include_teams + '&audio_track=spanish' + content_protect_b + '">calendar.ics</a></p>' + "\n"
|
|
2391
2434
|
|
|
2392
2435
|
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"
|
|
2393
2436
|
|
|
@@ -2820,6 +2863,11 @@ app.get('/channels.m3u', async function(req, res) {
|
|
|
2820
2863
|
startingChannelNumber = req.query.startingChannelNumber
|
|
2821
2864
|
}
|
|
2822
2865
|
|
|
2866
|
+
let audio_track = false
|
|
2867
|
+
if ( req.query.audio_track ) {
|
|
2868
|
+
audio_track = req.query.audio_track
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2823
2871
|
let includeBlackouts = 'false'
|
|
2824
2872
|
if ( req.query.includeBlackouts ) {
|
|
2825
2873
|
includeBlackouts = req.query.includeBlackouts
|
|
@@ -2835,7 +2883,7 @@ app.get('/channels.m3u', async function(req, res) {
|
|
|
2835
2883
|
includeOrgs = req.query.includeOrgs.toUpperCase().split(',')
|
|
2836
2884
|
}
|
|
2837
2885
|
|
|
2838
|
-
var body = await session.getTVData('channels', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, 'false', 'false', resolution, pipe, startingChannelNumber)
|
|
2886
|
+
var body = await session.getTVData('channels', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, 'false', audio_track, 'false', resolution, pipe, startingChannelNumber)
|
|
2839
2887
|
|
|
2840
2888
|
res.writeHead(200, {'Content-Type': 'audio/x-mpegurl'})
|
|
2841
2889
|
res.end(body)
|
|
@@ -2861,6 +2909,11 @@ app.get('/calendar.ics', async function(req, res) {
|
|
|
2861
2909
|
if ( req.query.excludeTeams ) {
|
|
2862
2910
|
excludeTeams = req.query.excludeTeams.toUpperCase().split(',')
|
|
2863
2911
|
}
|
|
2912
|
+
|
|
2913
|
+
let audio_track = false
|
|
2914
|
+
if ( req.query.audio_track ) {
|
|
2915
|
+
audio_track = req.query.audio_track
|
|
2916
|
+
}
|
|
2864
2917
|
|
|
2865
2918
|
let includeBlackouts = 'false'
|
|
2866
2919
|
if ( req.query.includeBlackouts ) {
|
|
@@ -2884,7 +2937,7 @@ app.get('/calendar.ics', async function(req, res) {
|
|
|
2884
2937
|
|
|
2885
2938
|
let server = (req.headers['x-forwarded-proto'] ? req.headers['x-forwarded-proto'] : 'http') + '://' + req.headers.host + http_root
|
|
2886
2939
|
|
|
2887
|
-
var body = await session.getTVData('calendar', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles)
|
|
2940
|
+
var body = await session.getTVData('calendar', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles, audio_track)
|
|
2888
2941
|
|
|
2889
2942
|
res.writeHead(200, {'Content-Type': 'text/calendar'})
|
|
2890
2943
|
res.end(body)
|
|
@@ -2915,6 +2968,11 @@ app.get('/guide.xml', async function(req, res) {
|
|
|
2915
2968
|
excludeTeams = req.query.excludeTeams.toUpperCase().split(',')
|
|
2916
2969
|
}
|
|
2917
2970
|
|
|
2971
|
+
let audio_track = false
|
|
2972
|
+
if ( req.query.audio_track ) {
|
|
2973
|
+
audio_track = req.query.audio_track
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2918
2976
|
let includeBlackouts = 'false'
|
|
2919
2977
|
if ( req.query.includeBlackouts ) {
|
|
2920
2978
|
includeBlackouts = req.query.includeBlackouts
|
|
@@ -2942,7 +3000,7 @@ app.get('/guide.xml', async function(req, res) {
|
|
|
2942
3000
|
|
|
2943
3001
|
let server = (req.headers['x-forwarded-proto'] ? req.headers['x-forwarded-proto'] : 'http') + '://' + req.headers.host + http_root
|
|
2944
3002
|
|
|
2945
|
-
var body = await session.getTVData('guide', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles, offAir)
|
|
3003
|
+
var body = await session.getTVData('guide', mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles, audio_track, offAir)
|
|
2946
3004
|
|
|
2947
3005
|
res.end(body)
|
|
2948
3006
|
})
|
package/package.json
CHANGED
package/session.js
CHANGED
|
@@ -1886,6 +1886,7 @@ class sessionClass {
|
|
|
1886
1886
|
if ( (nationalArray.length == 2) && (nationalArray[1] == nationalCount) ) {
|
|
1887
1887
|
this.debuglog('matched national event')
|
|
1888
1888
|
mediaInfo = await this.check_media_state(broadcast, cache_data.dates[0].games[j].status.abstractGameState, mediaDate, cache_data.dates[0].games[j].gamePk)
|
|
1889
|
+
mediaInfo.teamType = 'Home'
|
|
1889
1890
|
break
|
|
1890
1891
|
}
|
|
1891
1892
|
|
|
@@ -1897,6 +1898,7 @@ class sessionClass {
|
|
|
1897
1898
|
if ( (freeArray.length == 2) && (freeArray[1] == freeCount) ) {
|
|
1898
1899
|
this.debuglog('matched free event')
|
|
1899
1900
|
mediaInfo = await this.check_media_state(broadcast, cache_data.dates[0].games[j].status.abstractGameState, mediaDate, cache_data.dates[0].games[j].gamePk)
|
|
1901
|
+
mediaInfo.teamType = 'Home'
|
|
1900
1902
|
break
|
|
1901
1903
|
}
|
|
1902
1904
|
|
|
@@ -1910,6 +1912,11 @@ class sessionClass {
|
|
|
1910
1912
|
} else {
|
|
1911
1913
|
this.debuglog('matched team for event')
|
|
1912
1914
|
mediaInfo = await this.check_media_state(broadcast, cache_data.dates[0].games[j].status.abstractGameState, mediaDate, cache_data.dates[0].games[j].gamePk)
|
|
1915
|
+
if ( team.toUpperCase() == away_team ) {
|
|
1916
|
+
mediaInfo.teamType = 'Away'
|
|
1917
|
+
} else {
|
|
1918
|
+
mediaInfo.teamType = 'Home'
|
|
1919
|
+
}
|
|
1913
1920
|
break
|
|
1914
1921
|
}
|
|
1915
1922
|
}
|
|
@@ -2193,7 +2200,7 @@ class sessionClass {
|
|
|
2193
2200
|
}
|
|
2194
2201
|
|
|
2195
2202
|
// get TV data (channels or guide)
|
|
2196
|
-
async getTVData(dataType, mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles='false', offAir='false', resolution='best', pipe='false', startingChannelNumber=1) {
|
|
2203
|
+
async getTVData(dataType, mediaType, includeTeams, excludeTeams, includeLevels, includeOrgs, server, includeBlackouts, includeTeamsInTitles='false', audio_track=false, offAir='false', resolution='best', pipe='false', startingChannelNumber=1) {
|
|
2197
2204
|
try {
|
|
2198
2205
|
this.debuglog('getTVData for ' + dataType)
|
|
2199
2206
|
|
|
@@ -2531,6 +2538,9 @@ class sessionClass {
|
|
|
2531
2538
|
if ( streamMediaType == 'Video' ) {
|
|
2532
2539
|
stream += '&resolution=' + resolution
|
|
2533
2540
|
}
|
|
2541
|
+
if ( audio_track ) {
|
|
2542
|
+
stream += '&audio_track=' + audio_track
|
|
2543
|
+
}
|
|
2534
2544
|
if ( includeBlackouts == 'true' ) stream += '&includeBlackouts=' + includeBlackouts
|
|
2535
2545
|
if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
|
|
2536
2546
|
if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
|
|
@@ -2550,6 +2560,13 @@ class sessionClass {
|
|
|
2550
2560
|
title = this.channelsFormattedTitle(subtitle, cache_data.dates[i].games[j].gameDate)
|
|
2551
2561
|
} else {
|
|
2552
2562
|
title = 'MLB: ' + subtitle + ' (' + station
|
|
2563
|
+
if ( audio_track ) {
|
|
2564
|
+
title += ' with'
|
|
2565
|
+
if ( audio_track.toLowerCase() == 'spanish' ) {
|
|
2566
|
+
title += ' Spanish'
|
|
2567
|
+
}
|
|
2568
|
+
title += ' Radio'
|
|
2569
|
+
}
|
|
2553
2570
|
if ( language == 'es' ) {
|
|
2554
2571
|
title += ' Spanish'
|
|
2555
2572
|
}
|
|
@@ -2566,6 +2583,14 @@ class sessionClass {
|
|
|
2566
2583
|
description += ' Spanish'
|
|
2567
2584
|
}
|
|
2568
2585
|
description += ' Radio'
|
|
2586
|
+
} else {
|
|
2587
|
+
if ( audio_track ) {
|
|
2588
|
+
description += ' with'
|
|
2589
|
+
if ( audio_track.toLowerCase() == 'spanish' ) {
|
|
2590
|
+
description += ' Spanish'
|
|
2591
|
+
}
|
|
2592
|
+
description += ' Radio, if available'
|
|
2593
|
+
}
|
|
2569
2594
|
}
|
|
2570
2595
|
description += '. '
|
|
2571
2596
|
if ( cache_data.dates[i].games[j].seriesDescription != 'Regular Season' ) {
|
|
@@ -2628,6 +2653,9 @@ class sessionClass {
|
|
|
2628
2653
|
if ( streamMediaType == 'Video' ) {
|
|
2629
2654
|
location += '&resolution=' + resolution
|
|
2630
2655
|
}
|
|
2656
|
+
if ( audio_track ) {
|
|
2657
|
+
location += '&audio_track=' + audio_track
|
|
2658
|
+
}
|
|
2631
2659
|
if ( includeBlackouts == 'true' ) location += '&includeBlackouts=' + includeBlackouts
|
|
2632
2660
|
if ( this.protection.content_protect ) location += '&content_protect=' + this.protection.content_protect
|
|
2633
2661
|
calendar += await this.generate_ics_event(prefix, calendar_start, calendar_stop, subtitle, description, location)
|