mlbserver 2024.7.24 → 2024.7.25-3

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/README.md +12 -4
  2. package/package.json +1 -1
  3. package/session.js +12 -243
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
- # mlbserver
2
-
3
- Current version 2024.07.24
1
+ [![Docker release](https://img.shields.io/docker/v/tonywagner/mlbserver)](https://hub.docker.com/r/tonywagner/mlbserver)
2
+ [![NPM release](https://img.shields.io/npm/v/mlbserver)](https://www.npmjs.com/package/mlbserver)
3
+ ![License](https://img.shields.io/badge/license-MIT-blue)
4
+ [![Contributors](https://img.shields.io/github/contributors/tonywagner/mlbserver.svg)](https://github.com/tonywagner/mlbserver/graphs/contributors)
4
5
 
5
- Credit to https://github.com/tonycpsu/streamglob and https://github.com/mafintosh/hls-decryptor
6
+ # mlbserver
6
7
 
7
8
  ## Installation
8
9
 
@@ -135,6 +136,13 @@ h264_vaapi use VAAPI which is another abstraction API to access video accelerati
135
136
  h264_videotoolbox use videotoolbox an API to access hardware on OS X
136
137
  ```
137
138
 
139
+ ## Credits
140
+
141
+ https://github.com/tonycpsu/streamglob
142
+ https://github.com/mafintosh/hls-decryptor
143
+ https://github.com/eracknaphobia/plugin.video.mlbtv
144
+
145
+
138
146
  ## License
139
147
 
140
148
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlbserver",
3
- "version": "2024.07.24",
3
+ "version": "2024.07.25-3",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
package/session.js CHANGED
@@ -1472,46 +1472,11 @@ class sessionClass {
1472
1472
  })
1473
1473
  }
1474
1474
 
1475
- // API call
1476
- /*async getApiKeys() {
1477
- this.debuglog('getApiKeys')
1478
- let reqObj = {
1479
- url: 'https://www.mlb.com/tv/g632102/',
1480
- headers: {
1481
- 'User-agent': USER_AGENT,
1482
- 'Origin': 'https://www.mlb.com',
1483
- 'Accept-Encoding': 'gzip, deflate, br'
1484
- },
1485
- gzip: true
1486
- }
1487
- var response = await this.httpGet(reqObj)
1488
- if ( response ) {
1489
- // disabled because it's very big!
1490
- //this.debuglog('getApiKeys response : ' + response)
1491
- var parsed = response.match('"x-api-key","value":"([^"]+)"')
1492
- if ( parsed[1] ) {
1493
- this.data.xApiKey = parsed[1]
1494
- this.save_session_data()
1495
- } else {
1496
- this.log('getApiKeys xApiKey parse failure')
1497
- }
1498
- parsed = response.match('"clientApiKey":"([^"]+)"')
1499
- if ( parsed[1] ) {
1500
- this.data.clientApiKey = parsed[1]
1501
- this.save_session_data()
1502
- } else {
1503
- this.log('getApiKeys clientApiKey parse failure')
1504
- }
1505
- } else {
1506
- this.log('getApiKeys response failure')
1507
- }
1508
- }*/
1509
-
1510
1475
  // new API call
1511
1476
  async getDeviceId() {
1512
1477
  this.debuglog('getDeviceId')
1513
1478
  if ( !this.data.deviceId ) {
1514
- this.getSession()
1479
+ await this.getSession()
1515
1480
  }
1516
1481
  if ( this.data.deviceId ) {
1517
1482
  this.debuglog('using cached deviceId')
@@ -1525,7 +1490,7 @@ class sessionClass {
1525
1490
  async getSessionId() {
1526
1491
  this.debuglog('getSessionId')
1527
1492
  if ( !this.data.sessionId ) {
1528
- this.getSession()
1493
+ await this.getSession()
1529
1494
  }
1530
1495
  if ( this.data.sessionId ) {
1531
1496
  this.debuglog('using cached sessionId')
@@ -1651,204 +1616,6 @@ class sessionClass {
1651
1616
  }
1652
1617
  }
1653
1618
 
1654
- // API call
1655
- /*async getStreamURL(mediaId) {
1656
- this.debuglog('getStreamURL from ' + mediaId)
1657
- if ( this.cache.media && this.cache.media[mediaId] && this.cache.media[mediaId].streamURL && this.cache.media[mediaId].streamURLExpiry && (Date.parse(this.cache.media[mediaId].streamURLExpiry) > new Date()) ) {
1658
- this.debuglog('using cached streamURL')
1659
- return this.cache.media[mediaId].streamURL
1660
- } else if ( this.cache.media && this.cache.media[mediaId] && this.cache.media[mediaId].blackout && this.cache.media[mediaId].blackoutExpiry && (Date.parse(this.cache.media[mediaId].blackoutExpiry) > new Date()) ) {
1661
- this.log('mediaId recently blacked out, skipping')
1662
- } else {
1663
- let playbackURL = 'https://edge.svcs.mlb.com/media/' + mediaId + '/scenarios/browser~csai'
1664
- let reqObj = {
1665
- url: playbackURL,
1666
- simple: false,
1667
- headers: {
1668
- 'Authorization': await this.getBamAccessToken() || this.halt('missing bamAccessToken'),
1669
- 'User-agent': USER_AGENT,
1670
- 'Accept': 'application/vnd.media-service+json; version=1',
1671
- 'x-bamsdk-version': BAM_SDK_VERSION,
1672
- 'x-bamsdk-platform': PLATFORM,
1673
- 'Origin': 'https://www.mlb.com',
1674
- 'Accept-Encoding': 'gzip, deflate, br',
1675
- 'Content-type': 'application/json'
1676
- },
1677
- gzip: true
1678
- }
1679
- var response = await this.httpGet(reqObj)
1680
- if ( response && this.isValidJson(response) ) {
1681
- this.debuglog('getStreamURL response : ' + response)
1682
- let obj = JSON.parse(response)
1683
- if ( obj.errors ) {
1684
- this.log('getStreamURL error: ' + obj.errors[0])
1685
- if ( obj.errors[0] == 'blackout' ) {
1686
- this.markBlackoutError(mediaId)
1687
- }
1688
- return false
1689
- } else {
1690
- let streamURL = obj.stream.complete
1691
- this.debuglog('getStreamURL : ' + streamURL)
1692
- this.cacheStreamURL(mediaId, streamURL)
1693
- return streamURL
1694
- }
1695
- } else {
1696
- this.log('getStreamURL response failure')
1697
- }
1698
- }
1699
- }
1700
-
1701
- // API call
1702
- async getBamAccessToken() {
1703
- this.debuglog('getBamAccessToken')
1704
- if ( !this.data.bamAccessToken || !this.data.bamAccessTokenExpiry || (Date.parse(this.data.bamAccessTokenExpiry) < new Date()) ) {
1705
- this.debuglog('need to get new bamAccessToken')
1706
- let reqObj = {
1707
- url: BAM_TOKEN_URL,
1708
- headers: {
1709
- 'Authorization': 'Bearer ' + API_KEY,
1710
- 'User-agent': USER_AGENT,
1711
- 'Accept': 'application/vnd.media-service+json; version=1',
1712
- 'x-bamsdk-version': BAM_SDK_VERSION,
1713
- 'x-bamsdk-platform': PLATFORM,
1714
- 'Origin': 'https://www.mlb.com',
1715
- 'Accept-Encoding': 'gzip, deflate, br',
1716
- 'Content-type': 'application/x-www-form-urlencoded'
1717
- },
1718
- form: {
1719
- 'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
1720
- 'platform': 'browser',
1721
- 'subject_token': await this.getEntitlementToken() || this.halt('missing EntitlementToken'),
1722
- 'subject_token_type': 'urn:bamtech:params:oauth:token-type:account'
1723
- },
1724
- gzip: true
1725
- }
1726
- var response = await this.httpPost(reqObj)
1727
- if ( this.isValidJson(response) ) {
1728
- let obj = JSON.parse(response)
1729
- this.debuglog('getBamAccessToken : ' + obj.access_token)
1730
- this.debuglog('getBamAccessToken expires in : ' + obj.expires_in)
1731
- this.data.bamAccessToken = obj.access_token
1732
- this.data.bamAccessTokenExpiry = new Date(new Date().getTime() + obj.expires_in * 1000)
1733
- this.save_session_data()
1734
- return this.data.bamAccessToken
1735
- } else {
1736
- this.log('getBamAccessToken response failure')
1737
- }
1738
- } else {
1739
- return this.data.bamAccessToken
1740
- }
1741
- }
1742
-
1743
- // API call
1744
- async getEntitlementToken() {
1745
- this.debuglog('getEntitlementToken')
1746
- let reqObj = {
1747
- url: 'https://media-entitlement.mlb.com/api/v3/jwt',
1748
- headers: {
1749
- 'Authorization': 'Bearer ' + await this.getLoginToken() || this.halt('missing loginToken'),
1750
- 'Origin': 'https://www.mlb.com'
1751
- },
1752
- qs: {
1753
- 'os': PLATFORM,
1754
- 'did': await this.getDeviceId() || this.halt('missing deviceId'),
1755
- 'appname': 'mlbtv_web'
1756
- }
1757
- }
1758
- var response = await this.httpGet(reqObj)
1759
- if ( response ) {
1760
- this.debuglog('getEntitlementToken response : ' + response)
1761
- this.debuglog('getEntitlementToken : ' + response)
1762
- return response
1763
- } else {
1764
- this.log('getEntitlementToken response failure')
1765
- }
1766
- }
1767
-
1768
- async getDeviceId() {
1769
- this.debuglog('getDeviceId')
1770
- let reqObj = {
1771
- url: 'https://us.edge.bamgrid.com/session',
1772
- headers: {
1773
- 'Authorization': await this.getDeviceAccessToken() || this.halt('missing device_access_token'),
1774
- 'User-agent': USER_AGENT,
1775
- 'Origin': 'https://www.mlb.com',
1776
- 'Accept': 'application/vnd.session-service+json; version=1',
1777
- 'Accept-Encoding': 'gzip, deflate, br',
1778
- 'Accept-Language': 'en-US,en;q=0.5',
1779
- 'x-bamsdk-version': BAM_SDK_VERSION,
1780
- 'x-bamsdk-platform': PLATFORM,
1781
- 'Content-type': 'application/json',
1782
- 'TE': 'Trailers'
1783
- },
1784
- gzip: true
1785
- }
1786
- var response = await this.httpGet(reqObj)
1787
- if ( response && this.isValidJson(response) ) {
1788
- this.debuglog('getDeviceId response : ' + response)
1789
- let obj = JSON.parse(response)
1790
- this.debuglog('getDeviceId : ' + obj.device.id)
1791
- return obj.device.id
1792
- } else {
1793
- this.log('getDeviceId response failure')
1794
- }
1795
- }
1796
-
1797
- // API call
1798
- async getDeviceAccessToken() {
1799
- this.debuglog('getDeviceAccessToken')
1800
- let reqObj = {
1801
- url: BAM_TOKEN_URL,
1802
- headers: {
1803
- 'Authorization': 'Bearer ' + API_KEY,
1804
- 'Origin': 'https://www.mlb.com'
1805
- },
1806
- form: {
1807
- 'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
1808
- 'latitude': '0',
1809
- 'longitude': '0',
1810
- 'platform': 'browser',
1811
- 'subject_token': await this.getDevicesAssertion() || this.halt('missing devicesAssertion'),
1812
- 'subject_token_type': 'urn:bamtech:params:oauth:token-type:device'
1813
- }
1814
- }
1815
- var response = await this.httpPost(reqObj)
1816
- if ( this.isValidJson(response) ) {
1817
- this.debuglog('getDeviceAccessToken response : ' + response)
1818
- let obj = JSON.parse(response)
1819
- this.debuglog('getDeviceAccessToken : ' + obj.access_token)
1820
- return obj.access_token
1821
- } else {
1822
- this.log('getDeviceAccessToken response failure')
1823
- }
1824
- }
1825
-
1826
- // API call
1827
- async getDevicesAssertion() {
1828
- this.debuglog('getDevicesAssertion')
1829
- let reqObj = {
1830
- url: 'https://us.edge.bamgrid.com/devices',
1831
- headers: {
1832
- 'Authorization': 'Bearer ' + API_KEY,
1833
- 'Origin': 'https://www.mlb.com'
1834
- },
1835
- json: {
1836
- 'applicationRuntime': 'firefox',
1837
- 'attributes': {},
1838
- 'deviceFamily': 'browser',
1839
- 'deviceProfile': 'macosx'
1840
- }
1841
- }
1842
- var response = await this.httpPost(reqObj)
1843
- if ( response.assertion ) {
1844
- this.debuglog('getDevicesAssertion response : ' + JSON.stringify(response))
1845
- this.debuglog('getDevicesAssertion : ' + response.assertion)
1846
- return response.assertion
1847
- } else {
1848
- this.log('getDevicesAssertion response failure')
1849
- }
1850
- }*/
1851
-
1852
1619
  // API call
1853
1620
  async getLoginToken() {
1854
1621
  this.debuglog('getLoginToken')
@@ -2579,7 +2346,7 @@ class sessionClass {
2579
2346
  team = 'FREE.' + gameCounter['Free']
2580
2347
  }
2581
2348
 
2582
- let icon = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA&s'
2349
+ let icon = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA'
2583
2350
  if ( (cache_data.dates[i].games[j].teams['home'].team.id >= 108) && (cache_data.dates[i].games[j].teams['home'].team.id <= 158) && (cache_data.dates[i].games[j].teams['away'].team.id >= 108) && (cache_data.dates[i].games[j].teams['away'].team.id <= 158) ) {
2584
2351
  icon = 'https://img.mlbstatic.com/mlb-photos/image/upload/ar_167:215,c_crop/fl_relative,l_team:' + cache_data.dates[i].games[j].teams['home'].team.id + ':fill:spot.png,w_1.0,h_1,x_0.5,y_0,fl_no_overflow,e_distort:100p:0:200p:0:200p:100p:0:100p/fl_relative,l_team:' + cache_data.dates[i].games[j].teams['away'].team.id + ':logo:spot:current,w_0.38,x_-0.25,y_-0.16/fl_relative,l_team:' + cache_data.dates[i].games[j].teams['home'].team.id + ':logo:spot:current,w_0.38,x_0.25,y_0.16/w_750/team/' + cache_data.dates[i].games[j].teams['away'].team.id + '/fill/spot.png'
2585
2352
  }
@@ -2610,7 +2377,7 @@ class sessionClass {
2610
2377
  if ( (teamType == 'NATIONAL') && ((includeTeams.length == 0) || ((includeTeams.length > 0) && includeTeams.includes(teamType))) ) {
2611
2378
  //logo += '/image.svg?teamId=MLB'
2612
2379
  //if ( this.protection.content_protect ) logo += '&amp;content_protect=' + this.protection.content_protect
2613
- logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA&s'
2380
+ logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA'
2614
2381
  nationalChannels[channelid] = await this.create_channel_object(channelid, logo, stream, channelMediaType)
2615
2382
  } else {
2616
2383
  seriesId = cache_data.dates[i].games[j].teams[teamType].team.teamId
@@ -2776,7 +2543,7 @@ class sessionClass {
2776
2543
  let channelid = mediaType + '.GAMECHANGER'
2777
2544
  //let logo = server + '/image.svg?teamId=MLB'
2778
2545
  //if ( this.protection.content_protect ) logo += '&amp;content_protect=' + this.protection.content_protect
2779
- let logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA&s'
2546
+ let logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA'
2780
2547
  let stream = server + '/gamechanger.m3u8?resolution=' + resolution
2781
2548
  if ( this.protection.content_protect ) stream += '&content_protect=' + this.protection.content_protect
2782
2549
  if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
@@ -2823,7 +2590,7 @@ class sessionClass {
2823
2590
  let channelid = mediaType + '.MULTIVIEW'
2824
2591
  //let logo = server + '/image.svg?teamId=MLB'
2825
2592
  //if ( this.protection.content_protect ) logo += '&amp;content_protect=' + this.protection.content_protect
2826
- let logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA&s'
2593
+ let logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRi5AKF6eAu9Va9BzZzgw0PSsQXw8rXPiQLHA'
2827
2594
  let stream = server.replace(':' + this.data.port, ':' + this.data.multiviewPort) + this.data.multiviewStreamURLPath
2828
2595
  if ( pipe == 'true' ) stream = await this.convert_stream_to_pipe(stream, channelid)
2829
2596
  channels[channelid] = await this.create_channel_object(channelid, logo, stream, mediaType)
@@ -3737,6 +3504,8 @@ class sessionClass {
3737
3504
  end.setHours(end.getHours()+4)
3738
3505
  }
3739
3506
  }
3507
+ this.debuglog('Game changer start ' + start)
3508
+ this.debuglog('Game changer end ' + end)
3740
3509
  this.temp_cache.gamechanger = {
3741
3510
  date: today,
3742
3511
  start: start,
@@ -4226,7 +3995,7 @@ class sessionClass {
4226
3995
  for (var j = 0; j < games.length; j++) {
4227
3996
  let gamePk = games[j].gamePk.toString()
4228
3997
  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) ) {
4229
- this.debuglog('get_first_and_last_games first : ' + j)
3998
+ this.debuglog('get_first_and_last_games first : ' + j + ' ' + gamePk + ' at ' + games[j].gameDate)
4230
3999
  firstGameIndex = j
4231
4000
  break
4232
4001
  }
@@ -4235,7 +4004,7 @@ class sessionClass {
4235
4004
  for (var j = (games.length-1); j >= 0; j--) {
4236
4005
  let gamePk = games[j].gamePk.toString()
4237
4006
  if ( games[j].gameDate && !blackouts[gamePk] && !games[j].rescheduleDate && games[j].broadcasts && (await this.count_broadcasts(games[j].broadcasts, 'MLBTV') > 0) ) {
4238
- this.debuglog('get_first_and_last_games last : ' + j)
4007
+ this.debuglog('get_first_and_last_games last : ' + j + ' ' + gamePk + ' at ' + games[j].gameDate)
4239
4008
  lastGameIndex = j
4240
4009
  break
4241
4010
  }
@@ -4354,7 +4123,7 @@ class sessionClass {
4354
4123
  let xml_output = "\n" + ' <programme channel="' + channelid + '" start="' + start + '" stop="' + stop + '">' + "\n" +
4355
4124
  ' <title lang="en">' + title + '</title>' + "\n"
4356
4125
  if ( subtitle ) {
4357
- xml_output += ' <subtitle lang="en">' + subtitle + '</title>' + "\n"
4126
+ xml_output += ' <sub-title lang="en">' + subtitle + '</sub-title>' + "\n"
4358
4127
  }
4359
4128
  xml_output += ' <desc lang="en">' + description.trim() + '</desc>' + "\n" +
4360
4129
  ' <category lang="en">Sports</category>' + "\n" +
@@ -4362,7 +4131,7 @@ class sessionClass {
4362
4131
  ' <category lang="en">Sports event</category>' + "\n" +
4363
4132
  ' <icon src="' + icon + '"></icon>' + "\n"
4364
4133
  if ( teamId ) {
4365
- xml_output += ' <series-id system="team-id">{' + teamId + '</series-id>' + "\n"
4134
+ xml_output += ' <series-id system="team-id">' + teamId + '</series-id>' + "\n"
4366
4135
  }
4367
4136
  xml_output += ' <episode-num system="original-air-date">' + date + '</episode-num>' + "\n"
4368
4137
  if ( gamePk ) {