mlbserver 2025.8.20 → 2025.10.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.
- package/index.js +83 -0
- package/package.json +1 -1
- package/session.js +54 -4
package/index.js
CHANGED
|
@@ -2528,6 +2528,8 @@ app.get('/', async function(req, res) {
|
|
|
2528
2528
|
let example_streamURL = gamechanger_streamURL + '&' + gamechanger_types[i] + 'cludeTeams=' + include_teams
|
|
2529
2529
|
body += '• ' + gamechanger_types[i] + 'clude: <a href="' + http_root + '/embed.html?src=' + encodeURIComponent(example_streamURL) + '&startFrom=' + VALID_START_FROM[1] + content_protect_b + '">Embed</a> | <a href="' + example_streamURL + '">Stream</a> | <a href="' + http_root + '/chromecast.html?src=' + encodeURIComponent(example_streamURL) + content_protect_b + '">Chromecast</a> | <a href="' + http_root + '/advanced.html?src=' + encodeURIComponent(example_streamURL) + content_protect_b + '">Advanced</a> | <a href="' + http_root + '/kodi.strm?src=' + encodeURIComponent(example_streamURL) + content_protect_b + '">Kodi</a><br/>' + "\n"
|
|
2530
2530
|
}
|
|
2531
|
+
|
|
2532
|
+
body += '<p><span class="tooltip">Comskip link examples<span class="tooltiptext">You can generate a <a href="https://github.com/erikkaashoek/Comskip">Comskip</a>-style file to automatically skip sections (breaks, idle time, or non-action pitches) of games you record using DVR software when watched in compatible players. For example, if you record a game from your local OTA channel using Tvheadend, you can then fetch one of these Comskip files, put it in the same directory with the same name as your recorded video file, and Kodi will automatically skip those sections while you watch the video.<br><br>Specifying the team and broadcast_start_timestamp in the URL is required! For the timestamp, use the time your DVR software began the recording. This should be your local time in YYYY-MM-DDTHH:MM:SS format.<br><br>Specifying a skip_adjust value in the URL is recommended, to adjust for broadcast delays. This will vary across different channels and different video sources.<br><br>For the txt file format, specifying the video frame rate (fps) in the URL is also required. This will commonly be either 30, 59.94, or 60, depending on your video source.<br><br>Optionally, setting pad to "on" will generate random extra skips at the end, to help avoid timeline spoilers.</span></span>: <a href="' + http_root + '/comskip.edl?team=CHC&date=2025-10-01&pad=on&skip=pitches&skip_adjust=11&broadcast_start_timestamp=2025-10-01T14:00:00' + content_protect_a + '">comskip.edl</a> or <a href="' + http_root + '/comskip.txt?team=CHC&date=2025-10-01&pad=on&skip=pitches&skip_adjust=11&broadcast_start_timestamp=2025-10-01T14:00:00&fps=59.94' + content_protect_a + '">comskip.txt</a></p>' + "\n"
|
|
2531
2533
|
|
|
2532
2534
|
body += '</p></td></tr></table><br/>' + "\n"
|
|
2533
2535
|
|
|
@@ -3650,3 +3652,84 @@ app.get('/stream_finder_icon.png', async function(req, res) {
|
|
|
3650
3652
|
res.end('stream_finder_icon.png request error, check log')
|
|
3651
3653
|
}
|
|
3652
3654
|
})
|
|
3655
|
+
|
|
3656
|
+
function prepareReqForComskip(req) {
|
|
3657
|
+
req.query.mediaType = req.query.mediaType || VALID_MEDIA_TYPES[0]
|
|
3658
|
+
req.query.inning_half = req.query.inning_half || VALID_INNING_HALF[0]
|
|
3659
|
+
req.query.inning_number = req.query.inning_number || VALID_INNING_NUMBER[0]
|
|
3660
|
+
let skip = req.query.skip || VALID_SKIP[1]
|
|
3661
|
+
req.query.skip = VALID_SKIP.indexOf(skip)
|
|
3662
|
+
req.query.pad = req.query.pad || VALID_PAD[0]
|
|
3663
|
+
req.query.skip_adjust = parseInt(req.query.skip_adjust) || DEFAULT_SKIP_ADJUST
|
|
3664
|
+
return req
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3667
|
+
// Listen for Comskip EDL file requests
|
|
3668
|
+
app.get('/comskip.edl', async function(req, res) {
|
|
3669
|
+
if ( ! (await protect(req, res)) ) return
|
|
3670
|
+
|
|
3671
|
+
try {
|
|
3672
|
+
session.requestlog('comskip.edl', req)
|
|
3673
|
+
|
|
3674
|
+
req = prepareReqForComskip(req)
|
|
3675
|
+
|
|
3676
|
+
let comskip_markers = await session.getComskipMarkers(req)
|
|
3677
|
+
|
|
3678
|
+
var body = ''
|
|
3679
|
+
|
|
3680
|
+
for (var i=0; i<comskip_markers.length; i++) {
|
|
3681
|
+
body += comskip_markers[i].break_start.toFixed(3) + ' ' + comskip_markers[i].break_end.toFixed(3) + ' 3' + "\n"
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
var download_headers = {
|
|
3685
|
+
'Content-Disposition': 'attachment; filename="comskip.edl"'
|
|
3686
|
+
}
|
|
3687
|
+
res.writeHead(200, download_headers)
|
|
3688
|
+
|
|
3689
|
+
res.end(body)
|
|
3690
|
+
} catch (e) {
|
|
3691
|
+
session.log('comskip.edl request error : ' + e.message)
|
|
3692
|
+
res.end('comskip.edl request error, check log')
|
|
3693
|
+
}
|
|
3694
|
+
})
|
|
3695
|
+
|
|
3696
|
+
// Listen for Comskip TXT file requests
|
|
3697
|
+
app.get('/comskip.txt', async function(req, res) {
|
|
3698
|
+
if ( ! (await protect(req, res)) ) return
|
|
3699
|
+
|
|
3700
|
+
try {
|
|
3701
|
+
session.requestlog('comskip.txt', req)
|
|
3702
|
+
|
|
3703
|
+
var body = ''
|
|
3704
|
+
|
|
3705
|
+
if ( !req.query.fps ) {
|
|
3706
|
+
session.log('comskip.txt error : specifying the video FPS in the request URL is required')
|
|
3707
|
+
} else {
|
|
3708
|
+
let fps = req.query.fps
|
|
3709
|
+
|
|
3710
|
+
req = prepareReqForComskip(req)
|
|
3711
|
+
|
|
3712
|
+
let comskip_markers = await session.getComskipMarkers(req)
|
|
3713
|
+
|
|
3714
|
+
if ( comskip_markers.length > 0 ) {
|
|
3715
|
+
let last_marker = comskip_markers[comskip_markers.length-1].break_end
|
|
3716
|
+
|
|
3717
|
+
body = 'FILE PROCESSING COMPLETE ' + Math.round(last_marker * fps) + ' FRAMES AT ' + (fps * 100) + "\n" + '-------------------' + "\n"
|
|
3718
|
+
|
|
3719
|
+
for (var i=0; i<comskip_markers.length; i++) {
|
|
3720
|
+
body += Math.round(comskip_markers[i].break_start * fps) + "\t" + Math.round(comskip_markers[i].break_end * fps) + "\n"
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3725
|
+
var download_headers = {
|
|
3726
|
+
'Content-Disposition': 'attachment; filename="comskip.txt"'
|
|
3727
|
+
}
|
|
3728
|
+
res.writeHead(200, download_headers)
|
|
3729
|
+
|
|
3730
|
+
res.end(body)
|
|
3731
|
+
} catch (e) {
|
|
3732
|
+
session.log('comskip.txt request error : ' + e.message)
|
|
3733
|
+
res.end('comskip.txt request error, check log')
|
|
3734
|
+
}
|
|
3735
|
+
})
|
package/package.json
CHANGED
package/session.js
CHANGED
|
@@ -3252,7 +3252,7 @@ class sessionClass {
|
|
|
3252
3252
|
}
|
|
3253
3253
|
|
|
3254
3254
|
// Get skip markers into temporary cache
|
|
3255
|
-
async getSkipMarkers(gamePk, skip_type, start_inning, start_inning_half, streamURL, streamURLToken, skip_adjust) {
|
|
3255
|
+
async getSkipMarkers(gamePk, skip_type, start_inning, start_inning_half, streamURL, streamURLToken, skip_adjust, broadcast_start_timestamp=false) {
|
|
3256
3256
|
try {
|
|
3257
3257
|
this.debuglog('getSkipMarkers')
|
|
3258
3258
|
|
|
@@ -3276,9 +3276,11 @@ class sessionClass {
|
|
|
3276
3276
|
// assume the game starts in a break
|
|
3277
3277
|
let break_start = 0
|
|
3278
3278
|
|
|
3279
|
-
// Get the broadcast start time first -- event times will be relative to this
|
|
3280
|
-
|
|
3281
|
-
|
|
3279
|
+
// Get the broadcast start time first, if necessary -- event times will be relative to this
|
|
3280
|
+
if ( !broadcast_start_timestamp ) {
|
|
3281
|
+
let variantPlaylist = await this.getVariantPlaylist(streamURL, streamURLToken)
|
|
3282
|
+
broadcast_start_timestamp = await this.getBroadcastStart(variantPlaylist)
|
|
3283
|
+
}
|
|
3282
3284
|
|
|
3283
3285
|
if ( broadcast_start_timestamp ) {
|
|
3284
3286
|
this.debuglog('getSkipMarkers broadcast start detected as ' + broadcast_start_timestamp)
|
|
@@ -5409,6 +5411,54 @@ class sessionClass {
|
|
|
5409
5411
|
}
|
|
5410
5412
|
return title
|
|
5411
5413
|
}
|
|
5414
|
+
|
|
5415
|
+
async getComskipMarkers(req) {
|
|
5416
|
+
try {
|
|
5417
|
+
let gamePk = req.query.gamePk
|
|
5418
|
+
|
|
5419
|
+
if ( !gamePk && req.query.team ) {
|
|
5420
|
+
let mediaType = req.query.mediaType
|
|
5421
|
+
let level = req.query.level || 'MLB'
|
|
5422
|
+
let includeBlackouts = 'true'
|
|
5423
|
+
let mediaInfo = await this.getMediaId(decodeURIComponent(req.query.team), decodeURIComponent(level), mediaType, req.query.date, req.query.game, includeBlackouts)
|
|
5424
|
+
gamePk = mediaInfo.gamePk
|
|
5425
|
+
}
|
|
5426
|
+
|
|
5427
|
+
if ( !req.query.broadcast_start_timestamp ) {
|
|
5428
|
+
this.log('comskip error : specifying the broadcast_start_timestamp in the URL is required, should be your local time in YYYY-MM-DDTHH:MM:SS format')
|
|
5429
|
+
return []
|
|
5430
|
+
}
|
|
5431
|
+
let broadcast_start_timestamp = new Date(req.query.broadcast_start_timestamp)
|
|
5432
|
+
|
|
5433
|
+
let inning_half = req.query.inning_half
|
|
5434
|
+
let inning_number = req.query.inning_number
|
|
5435
|
+
let skip_type = req.query.skip
|
|
5436
|
+
let pad = req.query.pad
|
|
5437
|
+
|
|
5438
|
+
let streamURL = 'false'
|
|
5439
|
+
let streamURLToken = 'false'
|
|
5440
|
+
|
|
5441
|
+
let skip_adjust = parseInt(req.query.skip_adjust)
|
|
5442
|
+
|
|
5443
|
+
await this.getSkipMarkers(gamePk, skip_type, inning_number, inning_half, streamURL, streamURLToken, skip_adjust, broadcast_start_timestamp)
|
|
5444
|
+
|
|
5445
|
+
let comskip_markers = this.temp_cache[gamePk].skip_markers
|
|
5446
|
+
|
|
5447
|
+
if ( (pad == 'on') && (comskip_markers.length > 0) ) {
|
|
5448
|
+
let last_marker = comskip_markers[comskip_markers.length-1].break_end
|
|
5449
|
+
let pad_time = last_marker + Math.floor(Math.random() * 7200) + 3600
|
|
5450
|
+
while ( last_marker < pad_time ) {
|
|
5451
|
+
let pad_start = last_marker + ((Math.floor(Math.random() * 15000) + 75000) / 1000)
|
|
5452
|
+
last_marker = pad_start + ((Math.floor(Math.random() * 15000) + 75000) / 1000)
|
|
5453
|
+
comskip_markers.push({'break_start': pad_start, 'break_end': last_marker})
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
|
|
5457
|
+
return comskip_markers
|
|
5458
|
+
} catch(e) {
|
|
5459
|
+
this.log('getComskipMarkers error : ' + e.message)
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5412
5462
|
}
|
|
5413
5463
|
|
|
5414
5464
|
module.exports = sessionClass
|