Skip to main content
The Cricfy Kodi Plugin follows a modular architecture designed for efficient content delivery and caching. The plugin fetches encrypted provider lists and channel playlists, decrypts them, and serves them through Kodi’s interface.

High-level architecture

The plugin operates in a request-response model:
  1. User interaction - User selects providers and channels through Kodi’s UI
  2. Provider fetch - Plugin retrieves encrypted provider data from Firebase Remote Config
  3. Decryption - Encrypted data is decrypted using AES encryption keys
  4. Channel parsing - M3U playlists are parsed into channel objects
  5. Playback - Resolved stream URLs are played with appropriate headers and DRM configuration

Entry Point

main.py handles routing and UI operations

Background Service

service.py prefetches providers on startup

Core Library

lib/ contains all business logic modules

Caching Layer

StorageServer provides persistent caching

Plugin structure

Main entry point (main.py)

The main.py file serves as the routing controller for the addon. It handles three primary modes:
  • Default mode - Lists all available providers from main.py:19-42
  • list_channels - Fetches and displays channels for a selected provider from main.py:45-87
  • play - Resolves and plays a selected channel from main.py:90-151
The router function (main.py:154-169) parses query parameters and dispatches to the appropriate handler based on the mode parameter.

Background service (service.py)

The background service performs initialization tasks:
  • Clears all cached data on startup from service.py:7
  • Prefetches provider list to warm up the cache from service.py:11
This ensures fresh data and improves initial loading performance.

Library modules (lib/)

All core functionality is organized in the lib/ directory:
  • config.py - Addon path resolution and cache initialization
  • providers.py - Provider and channel management with caching
  • m3u_parser.py - M3U playlist parsing logic
  • crypto_utils.py - AES encryption/decryption utilities
  • remote_config.py - Firebase Remote Config integration
  • req.py - HTTP request wrapper with custom headers
  • logger.py - Logging utilities for Kodi

Data flow

Provider retrieval flow

Channel playback flow

Routing system

The routing system in main.py uses URL query parameters to navigate between views:
def router(param_string):
  params = dict(parse_qsl(param_string))
  mode = params.get('mode')

  if mode is None:
    list_providers()
  elif mode == 'list_channels':
    list_channels(params.get('url'))
  elif mode == 'play':
    play_video(
      params.get('provider_url'),
      params.get('channel_title')
    )
URLs are built using the build_url() helper from main.py:15-16, which encodes parameters into query strings.

Caching strategy

The plugin implements a two-tier caching strategy using Kodi’s StorageServer:

Provider cache

  • Key: "cricfy_providers" from providers.py:11
  • TTL: 24 hours (configured in cache initialization)
  • Data: JSON array of provider objects
  • Invalidation: Manual via service.py or cache expiration

Channel cache

  • Key: "channels_{hash}" where hash is SHA256 of provider URL from providers.py:66
  • TTL: 3600 seconds (1 hour) from providers.py:12
  • Data: JSON object with channel list and fetch timestamp
  • Invalidation: Time-based check from providers.py:72
Caching significantly reduces network requests and improves response times for repeated queries.

Firebase Remote Config integration

The plugin uses Firebase Remote Config to dynamically retrieve API endpoints from remote_config.py:94-111. This allows changing backend URLs without updating the addon.

Configuration flow

  1. Generate random UUID as app instance ID from remote_config.py:28-29
  2. Build request payload with app metadata from remote_config.py:47-60
  3. Send POST request to Firebase Remote Config API from remote_config.py:72-77
  4. Extract cric_api2 or fall back to cric_api1 from remote_config.py:111
  5. Use API URL to fetch provider data from providers.py:33-40

Retry mechanism

The plugin attempts to fetch remote config up to 3 times before giving up from remote_config.py:99-106, ensuring resilience against temporary network failures.

Encryption and decryption

All provider data and some playlist content is encrypted using AES-256-CBC encryption.

Key management

Encryption keys are stored in secret files:
  • resources/secret1.txt - Primary AES key and IV (hex format: key:iv) from crypto_utils.py:9-12
  • resources/secret2.txt - Fallback AES key and IV
Keys are parsed into KeyInfo objects containing:
  • key: AES encryption key (bytes)
  • iv: Initialization vector (bytes)

Decryption process

Provider data decryption

From crypto_utils.py:42-63:
  1. Clean Base64 input (remove whitespace)
  2. Decode Base64 to ciphertext bytes
  3. Try decryption with each available key
  4. Remove PKCS5/7 padding
  5. Validate result (must start with {, [, or contain http)

M3U content decryption

From crypto_utils.py:88-128:
  1. Check if already plain M3U (starts with #EXTM3U, #EXTINF, or #KODIPROP)
  2. Extract encrypted parts using string slicing:
    • Part 1: bytes 0-10
    • Part 2: bytes 34 to -54
    • Part 3: last 10 bytes
  3. Extract IV (bytes 10-34) and key (bytes -54 to -10)
  4. Decode all parts from Base64
  5. Decrypt using extracted key and IV
  6. Unpad and return UTF-8 string
The decryption logic implements multiple fallback mechanisms to handle different encryption schemes and ensure maximum compatibility.

Build docs developers (and LLMs) love