mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-09-23 01:22:17 +02:00
Reformat
This commit is contained in:
+164
-59
@@ -124,49 +124,67 @@ def setup_m3u_routes(app, manager, service):
|
||||
def get_m3u_decrypted():
|
||||
"""
|
||||
Generates decrypted M3U playlist for all configured providers.
|
||||
Only includes channels with ClearKey DRM or unencrypted channels.
|
||||
Returns cached version if available, otherwise generates new one.
|
||||
Fast generation - includes ALL channels with decrypted stream URLs.
|
||||
No filtering, no caching (very fast).
|
||||
|
||||
Example: http://localhost:7777/api/m3u/decrypted
|
||||
"""
|
||||
try:
|
||||
cache_file = "playlist_decrypted.m3u"
|
||||
|
||||
# Try to read cached file
|
||||
cached_content = service.vfs.read_text(cache_file)
|
||||
|
||||
if cached_content:
|
||||
logger.info("Serving cached decrypted M3U playlist for all providers")
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
'attachment; filename="playlist_decrypted.m3u8"'
|
||||
)
|
||||
return cached_content
|
||||
|
||||
# Cache doesn't exist, generate new M3U
|
||||
logger.info(
|
||||
"No valid cache found, generating decrypted M3U playlist for all providers"
|
||||
)
|
||||
return service._generate_m3u_decrypted_all(save_to_cache=True)
|
||||
logger.info("Generating fast decrypted M3U playlist for all providers")
|
||||
return service._generate_m3u_decrypted_fast(providers=None)
|
||||
|
||||
except Exception as api_err:
|
||||
logger.error(f"API Error in /api/m3u/decrypted: {str(api_err)}")
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
|
||||
@app.route("/api/m3u/decrypted/generate")
|
||||
def generate_m3u_decrypted():
|
||||
@app.route("/api/m3u/decrypted/filtered")
|
||||
def get_m3u_decrypted_filtered():
|
||||
"""
|
||||
Forces regeneration of decrypted M3U playlist for all providers and saves to cache.
|
||||
Generates filtered decrypted M3U playlist for all configured providers.
|
||||
Only includes channels with ClearKey DRM or unencrypted channels.
|
||||
Returns cached version if available, otherwise generates new one.
|
||||
|
||||
Example: http://localhost:7777/api/m3u/decrypted/generate
|
||||
Example: http://localhost:7777/api/m3u/decrypted/filtered
|
||||
"""
|
||||
try:
|
||||
logger.info("Force generating decrypted M3U playlist for all providers")
|
||||
return service._generate_m3u_decrypted_all(save_to_cache=True)
|
||||
cache_file = "playlist_decrypted_filtered.m3u"
|
||||
|
||||
# Try to read cached file
|
||||
cached_content = service.vfs.read_text(cache_file)
|
||||
|
||||
if cached_content:
|
||||
logger.info("Serving cached filtered decrypted M3U playlist for all providers")
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
'attachment; filename="playlist_decrypted_filtered.m3u8"'
|
||||
)
|
||||
return cached_content
|
||||
|
||||
# Cache doesn't exist, generate new M3U
|
||||
logger.info(
|
||||
"No valid cache found, generating filtered decrypted M3U playlist for all providers"
|
||||
)
|
||||
return service._generate_m3u_decrypted_filtered_all(save_to_cache=True)
|
||||
|
||||
except Exception as api_err:
|
||||
logger.error(f"API Error in /api/m3u/decrypted/generate: {str(api_err)}")
|
||||
logger.error(f"API Error in /api/m3u/decrypted/filtered: {str(api_err)}")
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
|
||||
@app.route("/api/m3u/decrypted/filtered/generate")
|
||||
def generate_m3u_decrypted_filtered():
|
||||
"""
|
||||
Forces regeneration of filtered decrypted M3U playlist for all providers and saves to cache.
|
||||
|
||||
Example: http://localhost:7777/api/m3u/decrypted/filtered/generate
|
||||
"""
|
||||
try:
|
||||
logger.info("Force generating filtered decrypted M3U playlist for all providers")
|
||||
return service._generate_m3u_decrypted_filtered_all(save_to_cache=True)
|
||||
|
||||
except Exception as api_err:
|
||||
logger.error(f"API Error in /api/m3u/decrypted/filtered/generate: {str(api_err)}")
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
|
||||
@@ -174,34 +192,14 @@ def setup_m3u_routes(app, manager, service):
|
||||
def get_m3u_decrypted_provider(provider):
|
||||
"""
|
||||
Generates decrypted M3U playlist for a specific provider.
|
||||
Only includes channels with ClearKey DRM or unencrypted channels.
|
||||
Returns cached version if available, otherwise generates new one.
|
||||
Fast generation - includes ALL channels with decrypted stream URLs.
|
||||
No filtering, no caching (very fast).
|
||||
|
||||
Example: http://localhost:7777/api/providers/rtlplus/m3u/decrypted
|
||||
"""
|
||||
try:
|
||||
cache_file = f"{provider}_decrypted.m3u"
|
||||
|
||||
# Try to read cached file
|
||||
cached_content = service.vfs.read_text(cache_file)
|
||||
|
||||
if cached_content:
|
||||
logger.info(
|
||||
f"Serving cached decrypted M3U playlist for provider '{provider}'"
|
||||
)
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
f'attachment; filename="{provider}_decrypted_playlist.m3u8"'
|
||||
)
|
||||
return cached_content
|
||||
|
||||
# Cache doesn't exist, generate new M3U
|
||||
logger.info(
|
||||
f"No valid cache found, generating decrypted M3U playlist for provider '{provider}'"
|
||||
)
|
||||
return service._generate_m3u_decrypted_provider(
|
||||
provider, save_to_cache=True
|
||||
)
|
||||
logger.info(f"Generating fast decrypted M3U playlist for provider '{provider}'")
|
||||
return service._generate_m3u_decrypted_fast(providers=provider)
|
||||
|
||||
except ValueError as val_err:
|
||||
logger.error(
|
||||
@@ -216,30 +214,76 @@ def setup_m3u_routes(app, manager, service):
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
|
||||
@app.route("/api/providers/<provider>/m3u/decrypted/generate")
|
||||
def generate_m3u_decrypted_provider(provider):
|
||||
@app.route("/api/providers/<provider>/m3u/decrypted/filtered")
|
||||
def get_m3u_decrypted_filtered_provider(provider):
|
||||
"""
|
||||
Forces regeneration of decrypted M3U playlist for a specific provider and saves to cache.
|
||||
Generates filtered decrypted M3U playlist for a specific provider.
|
||||
Only includes channels with ClearKey DRM or unencrypted channels.
|
||||
Returns cached version if available, otherwise generates new one.
|
||||
|
||||
Example: http://localhost:7777/api/providers/rtlplus/m3u/decrypted/generate
|
||||
Example: http://localhost:7777/api/providers/rtlplus/m3u/decrypted/filtered
|
||||
"""
|
||||
try:
|
||||
cache_file = f"{provider}_decrypted_filtered.m3u"
|
||||
|
||||
# Try to read cached file
|
||||
cached_content = service.vfs.read_text(cache_file)
|
||||
|
||||
if cached_content:
|
||||
logger.info(
|
||||
f"Serving cached filtered decrypted M3U playlist for provider '{provider}'"
|
||||
)
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
f'attachment; filename="{provider}_decrypted_filtered_playlist.m3u8"'
|
||||
)
|
||||
return cached_content
|
||||
|
||||
# Cache doesn't exist, generate new M3U
|
||||
logger.info(
|
||||
f"Force generating decrypted M3U playlist for provider '{provider}'"
|
||||
f"No valid cache found, generating filtered decrypted M3U playlist for provider '{provider}'"
|
||||
)
|
||||
return service._generate_m3u_decrypted_provider(
|
||||
return service._generate_m3u_decrypted_filtered_provider(
|
||||
provider, save_to_cache=True
|
||||
)
|
||||
|
||||
except ValueError as val_err:
|
||||
logger.error(
|
||||
f"API Error in /api/providers/{provider}/m3u/decrypted/generate: {str(val_err)}"
|
||||
f"API Error in /api/providers/{provider}/m3u/decrypted/filtered: {str(val_err)}"
|
||||
)
|
||||
response.status = 404
|
||||
return {"error": str(val_err)}
|
||||
except Exception as api_err:
|
||||
logger.error(
|
||||
f"API Error in /api/providers/{provider}/m3u/decrypted/generate: {str(api_err)}"
|
||||
f"API Error in /api/providers/{provider}/m3u/decrypted/filtered: {str(api_err)}"
|
||||
)
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
|
||||
@app.route("/api/providers/<provider>/m3u/decrypted/filtered/generate")
|
||||
def generate_m3u_decrypted_filtered_provider(provider):
|
||||
"""
|
||||
Forces regeneration of filtered decrypted M3U playlist for a specific provider and saves to cache.
|
||||
|
||||
Example: http://localhost:7777/api/providers/rtlplus/m3u/decrypted/filtered/generate
|
||||
"""
|
||||
try:
|
||||
logger.info(
|
||||
f"Force generating filtered decrypted M3U playlist for provider '{provider}'"
|
||||
)
|
||||
return service._generate_m3u_decrypted_filtered_provider(
|
||||
provider, save_to_cache=True
|
||||
)
|
||||
|
||||
except ValueError as val_err:
|
||||
logger.error(
|
||||
f"API Error in /api/providers/{provider}/m3u/decrypted/filtered/generate: {str(val_err)}"
|
||||
)
|
||||
response.status = 404
|
||||
return {"error": str(val_err)}
|
||||
except Exception as api_err:
|
||||
logger.error(
|
||||
f"API Error in /api/providers/{provider}/m3u/decrypted/filtered/generate: {str(api_err)}"
|
||||
)
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
@@ -348,3 +392,64 @@ def setup_m3u_routes(app, manager, service):
|
||||
logger.error(f"API Error in /api/m3u/subscribed/generate: {str(api_err)}")
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
|
||||
@app.route("/api/m3u/subscribed/decrypted")
|
||||
def get_m3u_subscribed_decrypted():
|
||||
"""
|
||||
Generate decrypted M3U playlist with only subscribed channels.
|
||||
Fast generation - no filtering, no caching.
|
||||
"""
|
||||
try:
|
||||
logger.info("Generating fast decrypted M3U playlist for subscribed channels")
|
||||
|
||||
# Check if media proxy is configured
|
||||
if not service.media_proxy_url:
|
||||
response.status = 503
|
||||
return {"error": "Media proxy not configured (MEDIA_PROXY_URL not set)"}
|
||||
|
||||
base_url = f"{request.urlparts.scheme}://{request.urlparts.netloc}"
|
||||
m3u_content = "#EXTM3U\n"
|
||||
|
||||
provider_list = manager.list_providers()
|
||||
for provider_name in provider_list:
|
||||
try:
|
||||
channels = manager.get_subscribed_channels(provider_name)
|
||||
|
||||
# Get provider label
|
||||
try:
|
||||
provider_instance = manager.get_provider(provider_name)
|
||||
provider_label = getattr(
|
||||
provider_instance, "provider_label", provider_name
|
||||
)
|
||||
except:
|
||||
provider_label = provider_name
|
||||
|
||||
for channel in channels:
|
||||
channel_id = channel.channel_id
|
||||
channel_name = channel.name
|
||||
channel_logo = channel.logo_url or ""
|
||||
|
||||
# Build decrypted stream URL
|
||||
stream_url = f"{base_url}/api/providers/{provider_name}/channels/{channel_id}/stream/decrypted/index.mpd"
|
||||
|
||||
# Add M3U entry
|
||||
m3u_content += f'#EXTINF:-1 tvg-id="{channel_id}" tvg-logo="{channel_logo}" group-title="{provider_label}",{channel_name}\n'
|
||||
m3u_content += "#KODIPROP:inputstream=inputstream.adaptive\n"
|
||||
m3u_content += f"{stream_url}\n"
|
||||
|
||||
except Exception as provider_err:
|
||||
logger.warning(
|
||||
f"Failed to process subscribed channels for '{provider_name}': {str(provider_err)}"
|
||||
)
|
||||
continue
|
||||
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
'attachment; filename="playlist_subscribed_decrypted.m3u8"'
|
||||
)
|
||||
return m3u_content
|
||||
|
||||
except Exception as api_err:
|
||||
logger.error(f"API Error in /api/m3u/subscribed/decrypted: {str(api_err)}")
|
||||
response.status = 500
|
||||
return {"error": f"Internal server error: {str(api_err)}"}
|
||||
+292
@@ -566,6 +566,298 @@ class UltimateService:
|
||||
|
||||
return m3u_content
|
||||
|
||||
def _generate_m3u_decrypted_fast(self, providers=None):
|
||||
"""
|
||||
Fast generation of decrypted M3U content for specified providers.
|
||||
Includes ALL channels with decrypted stream URLs.
|
||||
No DRM filtering, no caching - maximum speed.
|
||||
|
||||
Args:
|
||||
providers: List of provider names, or None for all providers
|
||||
|
||||
Returns:
|
||||
M3U content as string
|
||||
"""
|
||||
# Check if media proxy is configured
|
||||
if not self.media_proxy_url:
|
||||
logger.error("Cannot generate decrypted M3U: MEDIA_PROXY_URL not set")
|
||||
response.status = 503
|
||||
response.content_type = "application/json"
|
||||
return json.dumps(
|
||||
{"error": "Media proxy not configured (MEDIA_PROXY_URL not set)"}
|
||||
)
|
||||
|
||||
# Get base URL for absolute stream URLs
|
||||
base_url = f"{request.urlparts.scheme}://{request.urlparts.netloc}"
|
||||
|
||||
# Start M3U content
|
||||
m3u_content = "#EXTM3U\n"
|
||||
|
||||
# Determine which providers to process
|
||||
if providers is None:
|
||||
providers_to_process = self.manager.list_providers()
|
||||
else:
|
||||
providers_to_process = (
|
||||
[providers] if isinstance(providers, str) else providers
|
||||
)
|
||||
|
||||
channels_included = 0
|
||||
|
||||
for provider_name in providers_to_process:
|
||||
try:
|
||||
# Get channels for this provider
|
||||
channels = self.manager.get_channels(
|
||||
provider_name=provider_name, fetch_manifests=False
|
||||
)
|
||||
|
||||
# Get provider label
|
||||
try:
|
||||
provider_instance = self.manager.get_provider(provider_name)
|
||||
provider_label = provider_instance.provider_label
|
||||
except (AttributeError, KeyError, ValueError):
|
||||
provider_label = provider_name
|
||||
|
||||
# Process each channel - no DRM checks
|
||||
for channel in channels:
|
||||
channel_id = channel.channel_id
|
||||
channel_name = channel.name
|
||||
channel_logo = channel.logo_url or ""
|
||||
|
||||
# Build decrypted stream URL
|
||||
stream_url = f"{base_url}/api/providers/{provider_name}/channels/{channel_id}/stream/decrypted/index.mpd"
|
||||
|
||||
# Add M3U entry
|
||||
m3u_content += f'#EXTINF:-1 tvg-id="{channel_id}" tvg-logo="{channel_logo}" group-title="{provider_label}",{channel_name}\n'
|
||||
m3u_content += "#KODIPROP:inputstream=inputstream.adaptive\n"
|
||||
m3u_content += f"{stream_url}\n"
|
||||
|
||||
channels_included += 1
|
||||
|
||||
except Exception as provider_err:
|
||||
logger.warning(
|
||||
f"Failed to process provider '{provider_name}': {str(provider_err)}"
|
||||
)
|
||||
continue
|
||||
|
||||
logger.info(f"Fast decrypted M3U: included {channels_included} channels")
|
||||
|
||||
# Set appropriate headers
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
|
||||
if providers and isinstance(providers, str):
|
||||
# Single provider
|
||||
response.headers["Content-Disposition"] = (
|
||||
f'attachment; filename="{providers}_decrypted_playlist.m3u8"'
|
||||
)
|
||||
else:
|
||||
# All providers
|
||||
response.headers["Content-Disposition"] = (
|
||||
'attachment; filename="playlist_decrypted.m3u8"'
|
||||
)
|
||||
|
||||
return m3u_content
|
||||
|
||||
def _generate_m3u_decrypted_filtered_content(
|
||||
self, providers=None, save_to_cache=True, cache_filename=None
|
||||
):
|
||||
"""
|
||||
Internal method to generate filtered decrypted M3U content for specified providers.
|
||||
Only includes channels with ClearKey DRM or unencrypted channels.
|
||||
|
||||
Args:
|
||||
providers: List of provider names, or None for all providers
|
||||
save_to_cache: Whether to save to cache
|
||||
cache_filename: Cache filename to use
|
||||
|
||||
Returns:
|
||||
M3U content as string
|
||||
"""
|
||||
# Check if media proxy is configured
|
||||
if not self.media_proxy_url:
|
||||
logger.error("Cannot generate decrypted M3U: MEDIA_PROXY_URL not set")
|
||||
return None
|
||||
|
||||
# Get base URL for absolute stream URLs
|
||||
base_url = f"{request.urlparts.scheme}://{request.urlparts.netloc}"
|
||||
|
||||
# Start M3U content
|
||||
m3u_content = "#EXTM3U\n"
|
||||
|
||||
# Determine which providers to process
|
||||
if providers is None:
|
||||
# All providers
|
||||
providers_to_process = self.manager.list_providers()
|
||||
cache_filename = cache_filename or "playlist_decrypted_filtered.m3u"
|
||||
else:
|
||||
# Specific provider(s)
|
||||
providers_to_process = (
|
||||
[providers] if isinstance(providers, str) else providers
|
||||
)
|
||||
cache_filename = (
|
||||
cache_filename or f"{providers_to_process[0]}_decrypted_filtered.m3u"
|
||||
)
|
||||
|
||||
channels_included = 0
|
||||
channels_skipped = 0
|
||||
|
||||
for provider_name in providers_to_process:
|
||||
try:
|
||||
# Get channels for this provider
|
||||
channels = self.manager.get_channels(
|
||||
provider_name=provider_name, fetch_manifests=False
|
||||
)
|
||||
|
||||
# Get provider instance for label and proxy config
|
||||
try:
|
||||
provider_instance = self.manager.get_provider(provider_name)
|
||||
provider_label = provider_instance.provider_label
|
||||
except (AttributeError, KeyError, ValueError):
|
||||
provider_label = provider_name
|
||||
|
||||
# Get provider proxy URL if configured
|
||||
http_manager = self.manager.get_provider_http_manager(provider_name)
|
||||
provider_proxy_url = None
|
||||
if http_manager and http_manager.config.proxy_config:
|
||||
proxy_cfg = http_manager.config.proxy_config
|
||||
provider_proxy_url = (
|
||||
f"{proxy_cfg.proxy_type.value.lower()}://{proxy_cfg.host}:{proxy_cfg.port}"
|
||||
)
|
||||
|
||||
# Process each channel
|
||||
for channel in channels:
|
||||
channel_id = channel.channel_id
|
||||
channel_name = channel.name
|
||||
channel_logo = channel.logo_url or ""
|
||||
|
||||
# Try to get DRM configs
|
||||
try:
|
||||
drm_configs = self.manager.get_channel_drm_configs(
|
||||
provider_name=provider_name, channel_id=channel_id
|
||||
)
|
||||
|
||||
# Convert list of DRM configs to dict
|
||||
drm_dict = {}
|
||||
if isinstance(drm_configs, list):
|
||||
for config in drm_configs:
|
||||
if hasattr(config, "to_dict"):
|
||||
config_dict = config.to_dict()
|
||||
drm_dict.update(config_dict)
|
||||
elif isinstance(config, dict):
|
||||
drm_dict.update(config)
|
||||
elif isinstance(drm_configs, dict):
|
||||
drm_dict = drm_configs
|
||||
|
||||
# Check if channel has ClearKey DRM or is unencrypted
|
||||
has_clearkey = False
|
||||
is_unencrypted = False
|
||||
clearkey_data = None
|
||||
|
||||
if "org.w3.clearkey" in drm_dict:
|
||||
clearkey_data = drm_dict["org.w3.clearkey"]
|
||||
has_clearkey = True
|
||||
elif "none" in drm_dict:
|
||||
is_unencrypted = True
|
||||
|
||||
if has_clearkey and clearkey_data:
|
||||
# Channel has ClearKey - generate decrypted entry
|
||||
entry_content = self._generate_m3u_decrypted_channel_entry(
|
||||
base_url=base_url,
|
||||
provider_name=provider_name,
|
||||
provider_label=provider_label,
|
||||
channel=channel,
|
||||
clearkey_data=clearkey_data,
|
||||
provider_proxy_url=provider_proxy_url,
|
||||
)
|
||||
m3u_content += entry_content
|
||||
channels_included += 1
|
||||
elif is_unencrypted:
|
||||
# Explicitly unencrypted channel - include with direct stream URL
|
||||
stream_url = f"{base_url}/api/providers/{provider_name}/channels/{channel_id}/stream/index.mpd"
|
||||
m3u_content += f'#EXTINF:-1 tvg-id="{channel_id}" tvg-logo="{channel_logo}" group-title="{provider_label}",{channel_name}\n'
|
||||
m3u_content += f"{stream_url}\n"
|
||||
channels_included += 1
|
||||
else:
|
||||
# Channel has other DRM, is inaccessible, or unknown - skip
|
||||
channels_skipped += 1
|
||||
logger.debug(
|
||||
f"Skipping {provider_name}/{channel_id} - unsupported DRM or no access"
|
||||
)
|
||||
|
||||
except Exception as drm_err:
|
||||
# Could not get DRM info - skip channel
|
||||
logger.warning(
|
||||
f"Could not get DRM for {provider_name}/{channel_id}: {drm_err}"
|
||||
)
|
||||
channels_skipped += 1
|
||||
continue
|
||||
|
||||
except Exception as provider_err:
|
||||
logger.warning(
|
||||
f"Failed to process provider '{provider_name}': {str(provider_err)}"
|
||||
)
|
||||
continue
|
||||
|
||||
logger.info(
|
||||
f"Filtered decrypted M3U: included {channels_included} channels, skipped {channels_skipped}"
|
||||
)
|
||||
|
||||
# Save to cache if requested
|
||||
if save_to_cache and cache_filename:
|
||||
if self.vfs.write_text(cache_filename, m3u_content):
|
||||
logger.info(f"Filtered decrypted M3U playlist cached to {cache_filename}")
|
||||
else:
|
||||
logger.warning(
|
||||
f"Failed to cache filtered decrypted M3U playlist to {cache_filename}"
|
||||
)
|
||||
|
||||
return m3u_content
|
||||
|
||||
def _generate_m3u_decrypted_filtered_all(self, save_to_cache: bool = False) -> str:
|
||||
"""Internal method to generate filtered decrypted M3U for all providers."""
|
||||
logger.info("Generating filtered decrypted M3U playlist for all providers")
|
||||
m3u_content = self._generate_m3u_decrypted_filtered_content(
|
||||
providers=None, save_to_cache=save_to_cache
|
||||
)
|
||||
|
||||
if m3u_content is None:
|
||||
response.status = 503
|
||||
response.content_type = "application/json"
|
||||
return json.dumps(
|
||||
{"error": "Media proxy not configured (MEDIA_PROXY_URL not set)"}
|
||||
)
|
||||
|
||||
# Set appropriate headers for M3U
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
'attachment; filename="playlist_decrypted_filtered.m3u8"'
|
||||
)
|
||||
|
||||
return m3u_content
|
||||
|
||||
def _generate_m3u_decrypted_filtered_provider(
|
||||
self, provider: str, save_to_cache: bool = False
|
||||
) -> str:
|
||||
"""Internal method to generate filtered decrypted M3U for a specific provider."""
|
||||
logger.info(f"Generating filtered decrypted M3U playlist for provider '{provider}'")
|
||||
m3u_content = self._generate_m3u_decrypted_filtered_content(
|
||||
providers=provider, save_to_cache=save_to_cache
|
||||
)
|
||||
|
||||
if m3u_content is None:
|
||||
response.status = 503
|
||||
response.content_type = "application/json"
|
||||
return json.dumps(
|
||||
{"error": "Media proxy not configured (MEDIA_PROXY_URL not set)"}
|
||||
)
|
||||
|
||||
# Set appropriate headers for M3U
|
||||
response.content_type = "audio/x-mpegurl; charset=utf-8"
|
||||
response.headers["Content-Disposition"] = (
|
||||
f'attachment; filename="{provider}_decrypted_filtered_playlist.m3u8"'
|
||||
)
|
||||
|
||||
return m3u_content
|
||||
|
||||
def _generate_m3u_channel_entry(self, base_url, provider_name, channel):
|
||||
"""
|
||||
Generate M3U entry for a single channel.
|
||||
|
||||
Reference in New Issue
Block a user