Skip to content

[plugin.video.mlbtv@matrix] 2026.4.9+matrix.1#4768

Open
eracknaphobia wants to merge 1 commit intoxbmc:matrixfrom
eracknaphobia:plugin.video.mlbtv@matrix
Open

[plugin.video.mlbtv@matrix] 2026.4.9+matrix.1#4768
eracknaphobia wants to merge 1 commit intoxbmc:matrixfrom
eracknaphobia:plugin.video.mlbtv@matrix

Conversation

@eracknaphobia
Copy link
Copy Markdown

Add-on details:

Watch every out-of-market regular season game in the office or on the go. The #1 LIVE
Streaming Sports Service

Description of changes:

        - playback fix for Kodi 22
        - Game Changer and Stream Finder fixes
        - affiliate team updates for 2026
        - restored Watch All Recaps option and removed spoilers from it
        - restored Big Inning schedule
        - skip timing adjustment for overturned pitches
        - added MASN live stream for entitled subscribers
        - do not show game state or inning when No Spoilers is enabled

Checklist:

  • My code follows the add-on rules and piracy stance of this project.
  • I have read the CONTRIBUTING document
  • Each add-on submission should be a single commit with using the following style: [plugin.video.foo] v1.0.0

@kodiai
Copy link
Copy Markdown

kodiai bot commented Apr 16, 2026

Kodiai Addon Check

Addon Level Message
plugin.video.mlbtv WARN 403 Client Error: Forbidden for url: https://forum.kodi.tv/showthread.php?tid=262745
plugin.video.mlbtv WARN Required dependency script.module.pytz does not require a minimum version, available: 2023.3.0+matrix.1
plugin.video.mlbtv WARN Required dependency script.module.beautifulsoup4 does not require a minimum version, available: 4.12.2
plugin.video.mlbtv WARN Required dependency script.module.requests does not require a minimum version, available: 2.31.0
plugin.video.mlbtv WARN Required dependency inputstream.adaptive does not require a minimum version, available: 19.0.7
plugin.video.mlbtv WARN Required dependency script.module.kodi-six does not require a minimum version, available: 0.1.3.1
plugin.video.mlbtv WARN Required dependency script.module.dateutil does not require a minimum version, available: 2.8.2
plugin.video.mlbtv WARN Complex entry point. Check: main.py
plugin.video.mlbtv WARN Complex entry point. Check: service.py
plugin.video.mlbtv WARN We found no problems and 9 warnings, please check the logfile.

0 error(s), 10 warning(s) found.

@kodiai
Copy link
Copy Markdown

kodiai bot commented Apr 16, 2026

Kodiai Review Summary

What Changed

Updates MLB.TV addon to version 2026.4.9+matrix.1 with Kodi 22 playback fixes, Game Changer/Stream Finder improvements, affiliate team updates, restored Big Inning schedule, and no-spoiler enhancements.

Reviewed: core logic

Strengths

  • ✅ Proper version-based conditional logic for Kodi 22 compatibility (globals.py:442-453)
  • ✅ Improved spoiler handling now correctly hides game state and inning information (mlb.py:289-305)
  • ✅ Game Changer now uses playlist API instead of executebuiltin for more reliable playback control (mlbmonitor.py:1640-1647)

Observations

Impact

[MAJOR] plugin.video.mlbtv/resources/lib/mlb.py (1491): Null pointer dereference in title.replace()
Causes AttributeError crash when no 'Condensed Game' highlight exists for a game. The variable title is initialized to None at line 1473, and may remain None if the search loop (lines 1476-1488) finds no matching highlight.

[MAJOR] plugin.video.mlbtv/resources/lib/mlb.py (631-639): Missing error handling for ESPN API response
Causes unhandled exception when ESPN API structure changes or returns errors. Code directly accesses nested keys ['page']['buckets'][0]['contents'] and ['utc'], ['streams'], ['durationInSeconds'] without validation.

[MEDIUM] plugin.video.mlbtv/resources/lib/globals.py (98): Truncated team ID in affiliate data
Los Angeles Angels entry ends with "56" while all other team IDs are 3-4 digits (e.g., "559", "561", "6482"). This appears to be a data truncation error that could cause incorrect affiliate team matching.

Suggestions

  • Optional: Add try-except blocks around external API calls to handle network errors and unexpected response formats gracefully
  • Future consideration: Extract the Big Inning schedule parsing logic into a separate method for better testability

Verdict

🔴 Address before merging -- 3 blocking issue(s) found

Review Details
  • Files reviewed: 5

  • Lines changed: +191 -101

  • Profile: balanced (auto, lines changed: 292)

  • Contributor experience: coarse-fallback (using coarse fallback signals only)

  • Findings: 0 critical, 4 major, 2 medium, 0 minor (includes 3 from summary observations)

  • Review completed: 2026-04-16T20:22:07.720Z

  • Total wall-clock: 4m 1s

  • Phase timings:

    • queue wait: 0ms
    • workspace preparation: 23s
    • retrieval/context assembly: 2.3s
    • executor handoff: 17s
    • remote runtime: 3m 15s
    • publication: 227ms (degraded: captured before publication completed)
  • Tokens: 156 in / 6,565 out | 0.3919

  • Keyword parsing: No keywords detected

break

if (n == 0):
title = title.replace('Condensed Game', 'Game Recap')
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] Null pointer dereference causes crash when title is None

The variable title is initialized to None at line 1473. If no highlight with displayName == 'Condensed Game' is found in the loop (lines 1476-1488), title remains None. Calling .replace() on None raises AttributeError: 'NoneType' object has no attribute 'replace'.

This crashes when processing games that don't have a 'Condensed Game' highlight.

Suggested change
title = title.replace('Condensed Game', 'Game Recap')
if (n == 0) and title is not None:
title = title.replace('Condensed Game', 'Game Recap')

Comment on lines +631 to +639
for content in json_source['page']['buckets'][0]['contents']:
big_inning_date = content['utc'][0:10]
big_inning_start = str(easternToLocal(parse(content['utc'][0:19])))
for stream in content['streams']:
big_inning_end = str(easternToLocal(parse(content['utc'][0:19]) + timedelta(seconds=stream['durationInSeconds'])))
if big_inning_date not in big_inning_schedule:
big_inning_schedule[big_inning_date] = []
big_inning_schedule[big_inning_date].append({'start': big_inning_start, 'end': big_inning_end})
break
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] Missing error handling for ESPN API JSON parsing

The code directly accesses nested dictionary keys without validation:

  • json_source['page']['buckets'][0]['contents'] - no check if keys exist or buckets is non-empty
  • content['utc'][0:10] and content['utc'][0:19] - no check if 'utc' key exists
  • content['streams'] - no check if key exists
  • stream['durationInSeconds'] - no check if key exists

If ESPN changes their API structure or returns an error response, this causes KeyError or IndexError, breaking Big Inning schedule functionality.

Suggested change
for content in json_source['page']['buckets'][0]['contents']:
big_inning_date = content['utc'][0:10]
big_inning_start = str(easternToLocal(parse(content['utc'][0:19])))
for stream in content['streams']:
big_inning_end = str(easternToLocal(parse(content['utc'][0:19]) + timedelta(seconds=stream['durationInSeconds'])))
if big_inning_date not in big_inning_schedule:
big_inning_schedule[big_inning_date] = []
big_inning_schedule[big_inning_date].append({'start': big_inning_start, 'end': big_inning_end})
break
big_inning_schedule = {}
try:
if 'page' in json_source and 'buckets' in json_source['page'] and len(json_source['page']['buckets']) > 0:
for content in json_source['page']['buckets'][0].get('contents', []):
if 'utc' in content and len(content['utc']) >= 19:
big_inning_date = content['utc'][0:10]
big_inning_start = str(easternToLocal(parse(content['utc'][0:19])))
for stream in content.get('streams', []):
if 'durationInSeconds' in stream:
big_inning_end = str(easternToLocal(parse(content['utc'][0:19]) + timedelta(seconds=stream['durationInSeconds'])))
if big_inning_date not in big_inning_schedule:
big_inning_schedule[big_inning_date] = []
big_inning_schedule[big_inning_date].append({'start': big_inning_start, 'end': big_inning_end})
break
except Exception as e:
xbmc.log('Error parsing Big Inning schedule: ' + str(e))

MLB_TEAM_IDS = '108,109,110,111,112,113,114,115,116,117,118,119,120,121,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,158,159,160'

AFFILIATE_TEAM_IDS = {"Arizona Diamondbacks": "419,516,2310,5368", "Athletics": "237,400,499,524", "Atlanta Braves": "431,432,478,6325", "Baltimore Orioles": "418,488,548,568", "Boston Red Sox": "414,428,533,546", "Chicago Cubs": "451,521,550,553", "Chicago White Sox": "247,487,494,580", "Cincinnati Reds": "416,450,459,498", "Cleveland Guardians": "402,437,445,481", "Colorado Rockies": "259,342,486,538", "Detroit Tigers": "106,512,570,582", "Houston Astros": "482,573,3712,5434", "Kansas City Royals": "541,565,1350,3705", "Los Angeles Angels": "401,460,559,561", "Los Angeles Dodgers": "238,260,456,526", "Miami Marlins": "479,554,564,4124", "Milwaukee Brewers": "249,556,572,5015", "Minnesota Twins": "492,509,1960,3898", "New York Mets": "453,505,507,552", "New York Yankees": "531,537,587,1956", "Philadelphia Phillies": "427,522,566,1410", "Pittsburgh Pirates": "452,477,484,3390", "San Diego Padres": "103,510,584,4904", "San Francisco Giants": "105,461,476,3410", "Seattle Mariners": "403,515,529,574", "St. Louis Cardinals": "235,279,440,443", "Tampa Bay Rays": "233,234,421,2498", "Texas Rangers": "102,448,540,6324", "Toronto Blue Jays": "422,424,435,463", "Washington Nationals": "426,436,534,547"}
AFFILIATE_TEAM_IDS = {"Arizona Diamondbacks": "419,516,2310,5368", "Athletics": "237,400,499,524", "Atlanta Braves": "431,432,478,6325", "Baltimore Orioles": "418,493,548,568", "Boston Red Sox": "414,428,533,546", "Chicago Cubs": "451,521,550,553", "Chicago White Sox": "247,487,494,580", "Cincinnati Reds": "416,450,459,498", "Cleveland Guardians": "402,437,445,481", "Colorado Rockies": "259,342,486,538", "Detroit Tigers": "106,512,570,582", "Houston Astros": "482,573,3712,5434", "Kansas City Royals": "541,565,1350,3705", "Los Angeles Angels": "460,526,559,56", "Los Angeles Dodgers": "238,260,456,6482", "Miami Marlins": "479,554,564,4124", "Milwaukee Brewers": "249,556,572,5015", "Minnesota Twins": "492,509,1960,3898", "New York Mets": "453,505,507,552", "New York Yankees": "531,537,587,1956", "Philadelphia Phillies": "427,522,566,1410", "Pittsburgh Pirates": "452,477,484,3390", "San Diego Padres": "103,510,584,4904", "San Francisco Giants": "105,461,476,3410", "Seattle Mariners": "401,403,529,574", "St. Louis Cardinals": "235,279,440,443", "Tampa Bay Rays": "233,234,421,2498", "Texas Rangers": "102,448,540,6324", "Toronto Blue Jays": "422,424,435,463", "Washington Nationals": "426,436,534,547"}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Truncated team ID in Los Angeles Angels affiliate data

The Los Angeles Angels entry ends with "56" while all other team IDs in the dictionary are 3-4 digits (e.g., Baltimore: "493", LA Dodgers: "6482", Seattle: "401,403").

The previous value was "401,460,559,561" (from the diff), and the new value is "460,526,559,56" - this suggests "561" was intended to be the last value but got truncated to "56".

This could cause incorrect affiliate team matching for Los Angeles Angels minor league teams.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant