Files
script.service.ultimate/lib/streaming_providers/base/models/subscription.py
T

134 lines
4.4 KiB
Python
Raw Normal View History

2025-12-22 14:32:36 +01:00
"""
Subscription models for provider packages and user entitlements.
"""
2026-01-06 16:41:03 +01:00
2025-12-22 14:32:36 +01:00
from dataclasses import dataclass, field
from datetime import datetime
2026-01-06 16:41:03 +01:00
from typing import Dict, List, Optional, Set
2025-12-22 14:32:36 +01:00
@dataclass
class SubscriptionPackage:
"""Represents a subscription package with provider-specific naming"""
package_id: str
"""Internal ID (e.g., 'sports_package_2024', 'joyn_plus')"""
name: str
"""Display name (e.g., 'Sports Package', 'Sky Sport', 'Joyn Plus')"""
description: Optional[str] = None
"""Optional description of the package"""
price_info: Optional[str] = None
"""Optional price information (e.g., '€9.99/month', 'included')"""
channel_ids: List[str] = field(default_factory=list)
"""List of channel IDs included in this package"""
metadata: Dict[str, any] = field(default_factory=dict)
"""Provider-specific metadata (e.g., {'sky_id': 'SPORT1', 'category': 'sports'})"""
@property
def channel_count(self) -> int:
"""Number of channels in this package"""
return len(self.channel_ids)
@dataclass
class UserSubscription:
"""User's subscription status for a provider"""
provider: str
"""Provider name (e.g., 'joyn', 'magenta')"""
country: str
"""Country code (e.g., 'DE', 'AT')"""
active: bool = False
"""Whether the subscription is currently active"""
packages: List[SubscriptionPackage] = field(default_factory=list)
"""All subscription packages the user has access to"""
accessible_channel_ids: Set[str] = field(default_factory=set)
"""Set of all channel IDs the user can access (derived from packages)"""
valid_from: Optional[datetime] = None
"""When the subscription becomes/starts valid"""
valid_until: Optional[datetime] = None
"""When the subscription expires"""
status_message: Optional[str] = None
"""Human-readable status message (e.g., 'Active until 2024-12-31')"""
billing_status: Optional[str] = None
"""Billing status (e.g., 'paid', 'trial', 'expired', 'cancelled')"""
def __post_init__(self):
"""Populate derived fields after initialization"""
self._update_derived_fields()
def _update_derived_fields(self):
"""Update derived fields like accessible_channel_ids"""
self.accessible_channel_ids.clear()
for package in self.packages:
self.accessible_channel_ids.update(package.channel_ids)
@property
def has_packages(self) -> bool:
"""Check if user has any packages"""
return len(self.packages) > 0
@property
def package_count(self) -> int:
"""Number of packages"""
return len(self.packages)
@property
def accessible_channel_count(self) -> int:
"""Number of accessible channels"""
return len(self.accessible_channel_ids)
@property
def package_names(self) -> List[str]:
"""List of package names for display"""
return [pkg.name for pkg in self.packages]
def to_dict(self) -> Dict:
"""Convert to dictionary for JSON serialization"""
return {
2026-01-06 16:41:03 +01:00
"provider": self.provider,
"country": self.country,
"active": self.active,
"has_packages": self.has_packages,
"package_count": self.package_count,
"package_names": self.package_names,
"accessible_channel_count": self.accessible_channel_count,
"valid_from": self.valid_from.isoformat() if self.valid_from else None,
"valid_until": self.valid_until.isoformat() if self.valid_until else None,
"status_message": self.status_message,
"billing_status": self.billing_status,
"packages": [
2025-12-22 14:32:36 +01:00
{
2026-01-06 16:41:03 +01:00
"package_id": pkg.package_id,
"name": pkg.name,
"description": pkg.description,
"price_info": pkg.price_info,
"channel_count": pkg.channel_count,
"metadata": pkg.metadata,
2025-12-22 14:32:36 +01:00
}
for pkg in self.packages
2026-01-06 16:41:03 +01:00
],
2025-12-22 14:32:36 +01:00
}
def add_package(self, package: SubscriptionPackage):
"""Add a package and update derived fields"""
self.packages.append(package)
self._update_derived_fields()
def can_access_channel(self, channel_id: str) -> bool:
"""Check if user can access a specific channel"""
2026-01-06 16:41:03 +01:00
return channel_id in self.accessible_channel_ids