Skip to main content

Overview

The main module is the entry point for the Cricfy Kodi plugin. It handles URL routing, UI navigation, provider/channel listing, and video playback setup.

Functions

build_url()

Constructs a Kodi plugin URL with query parameters.
def build_url(query)
query
dict
required
Dictionary of query parameters to encode in the URL
Returns:
url
str
Kodi plugin URL in format plugin://plugin.video.cricfy/?key1=value1&key2=value2
Example:
url = build_url({
    'mode': 'list_channels',
    'url': 'https://example.com/playlist.m3u',
    'title': 'Sports'
})
print(url)
# plugin://plugin.video.cricfy/?mode=list_channels&url=https%3A%2F%2F...

list_providers()

Lists all available providers in the Kodi UI.
def list_providers()
Behavior:
  1. Fetches providers using get_providers()
  2. Creates a folder item for each provider with:
    • Title from title field
    • Thumbnail/icon from image field (with fallback to default unknown icon)
    • URL linking to channel list for that provider
  3. Skips providers with invalid or missing catLink URLs
  4. Calls xbmcplugin.endOfDirectory() to finalize the listing
Provider Data Structure: Each provider from get_providers() contains:
{
    "title": "Sports Network",
    "image": "https://example.com/logo.png",
    "catLink": "https://example.com/channels.m3u"
}
UI Flow:
Cricfy Plugin Root
├── Provider 1 [Folder]
├── Provider 2 [Folder]
└── Provider 3 [Folder]
Example: When the user opens the Cricfy plugin, this function displays the provider list. Each provider is clickable and navigates to its channel list.

list_channels()

Fetches and displays channels for a specific provider.
def list_channels(provider_url)
provider_url
str
required
M3U playlist URL for the provider (from catLink field)
Behavior:
  1. Validates the provider URL (must start with http)
  2. Fetches channels using get_channels(provider_url)
  3. Creates a playable list item for each channel with:
    • Title and metadata (title, genre/group)
    • Thumbnail from tvg_logo
    • IsPlayable property set to true
  4. Shows error notification if URL is invalid or fetch fails
  5. Finalizes directory listing
Channel List Item Structure: For each channel:
li = xbmcgui.ListItem(label=ch.title)
li.setArt({'thumb': ch.tvg_logo, 'icon': ch.tvg_logo})
li.setInfo('video', {'title': ch.title, 'genre': ch.group_title})
li.setProperty('IsPlayable', 'true')
URL Parameters: Channels link to playback mode with:
  • mode='play'
  • provider_url: Original provider URL (for re-fetching channels)
  • channel_title: Channel title for identification
UI Flow:
Provider Name
├── Channel 1 [Playable]
├── Channel 2 [Playable]
└── Channel 3 [Playable]
Error Handling:
  • Invalid URL: Shows notification “Invalid provider URL”
  • Empty channels: Shows notification “No channels found”
  • Fetch error: Shows notification “Failed to fetch playlist content”
All errors call xbmcplugin.endOfDirectory() to prevent UI hanging
Example: When user clicks a provider folder, this function fetches and displays all channels from that provider’s M3U playlist.

play_video()

Resolves channel URL and configures Kodi for video playback.
def play_video(provider_url, channel_title)
provider_url
str
required
Provider M3U URL (used to fetch channels)
channel_title
str
required
Title of the channel to play (used to find the channel in the list)
Behavior:
  1. Fetches channels from provider_url
  2. Finds the channel matching channel_title
  3. Extracts streaming configuration (URL, headers, DRM)
  4. Configures Inputstream Adaptive for HLS/DASH/DRM streams
  5. Sets up HTTP headers (User-Agent, Referer, Cookie)
  6. Configures DRM license if present
  7. Calls xbmcplugin.setResolvedUrl() to start playback
Stream Configuration: The function extracts from the PlaylistItem:
  • url - Stream URL
  • user_agent - Custom User-Agent header
  • cookie - Authentication cookie
  • referer - Referer header
  • license_string - DRM license key/URL
  • headers - Additional HTTP headers
Inputstream Adaptive Setup:
if '.mpd' in url or '.m3u8' in url or '.m3u' in url or license_string:
    li.setProperty('inputstream', 'inputstream.adaptive')
    
    # Set headers for manifest and stream
    li.setProperty('inputstream.adaptive.manifest_headers', encoded_headers)
    li.setProperty('inputstream.adaptive.stream_headers', encoded_headers)
DRM Configuration:
Two DRM license formats are supported:
  1. Clearkey Hex Pair (format: key:kid):
    # Example: "a1b2c3d4e5f6:1a2b3c4d5e6f"
    drm_config = f"org.w3.clearkey|{license_string}"
    li.setProperty('inputstream.adaptive.drm_legacy', drm_config)
    
  2. License Server URL:
    # Example: "https://license.example.com/proxy"
    drm_config = f"org.w3.clearkey|{license_string}|{headers}"
    li.setProperty('inputstream.adaptive.drm_legacy', drm_config)
    
Header Encoding: Headers are encoded as key=value pairs joined with &:
stream_headers = [
    'User-Agent=Mozilla/5.0',
    'Referer=https://example.com',
    'Cookie=session=abc123'
]
encoded = '&'.join(stream_headers)
# "User-Agent=Mozilla/5.0&Referer=https://example.com&Cookie=session=abc123"
Headers are also appended to URL with pipe separator:
url += '|' + encoded_headers
# "https://stream.m3u8|User-Agent=...&Referer=...&Cookie=..."
Error Handling:
Shows error notification if:
  • Channel is not found in the provider’s channel list
  • Provider URL fetch fails
  • Any exception occurs during URL resolution
Error: “Failed to resolve channel URL”
Example: When user clicks a channel, this function:
  1. Re-fetches the provider’s channels (from cache if available)
  2. Finds the selected channel by title
  3. Configures Kodi to play the stream with proper headers and DRM

router()

Routes requests to the appropriate handler based on URL parameters.
def router(param_string)
param_string
str
required
Query string from Kodi (e.g., "mode=list_channels&url=https://...")
Routing Logic:
ModeFunction CalledParameters
None (root)list_providers()-
list_channelslist_channels()url
playplay_video()provider_url, channel_title
OtherError notification-
Example Routes:
# Root - show providers
router("")  # mode=None
→ list_providers()

# Show channels for a provider
router("mode=list_channels&url=https://example.com/playlist.m3u")
→ list_channels("https://example.com/playlist.m3u")

# Play a channel
router("mode=play&provider_url=https://...&channel_title=ESPN")
→ play_video("https://...", "ESPN")

# Invalid mode
router("mode=invalid")
→ Shows "Not implemented" error notification
URL Parameter Parsing:
params = dict(parse_qsl(param_string))
# "mode=play&title=ESPN" → {'mode': 'play', 'title': 'ESPN'}
Example: This is the main entry point called by Kodi:
if __name__ == '__main__':
    router(sys.argv[2][1:])  # Remove leading '?' from query string

Module Variables

VariableValueDescription
BASE_URLsys.argv[0]Kodi plugin base URL (plugin://plugin.video.cricfy/)
ADDON_HANDLEint(sys.argv[1])Kodi handle for this plugin instance
Kodi Arguments: Kodi passes these arguments to the plugin:
  • sys.argv[0] - Plugin URL
  • sys.argv[1] - Handle ID (integer)
  • sys.argv[2] - Query string (with leading ?)

┌─────────────────────┐
│  Plugin Root        │
│  list_providers()   │
└──────────┬──────────┘
           │ Click provider

┌─────────────────────┐
│  Channel List       │
│  list_channels()    │
└──────────┬──────────┘
           │ Click channel

┌─────────────────────┐
│  Video Playback     │
│  play_video()       │
└─────────────────────┘

Dependencies

  • urllib.parse - URL encoding/decoding
  • sys - Kodi arguments
  • re - DRM license pattern matching
  • xbmcgui - Kodi UI components
  • xbmcplugin - Kodi plugin API
  • lib.providers - Provider and channel fetching
  • lib.req - HTTP utilities
  • lib.logger - Error logging

Build docs developers (and LLMs) love