mirror of
https://github.com/R0m1k3/xtremobile.git
synced 2026-10-20 13:48:18 +02:00
feat: Introduce mobile Xtream IPTV service and provider files, remove numerous temporary analysis and build log files, and add a Claude settings file.
This commit is contained in:
1 parent
ef97c6dc90
commit
0010fe12ba
50 files changed
+119
-3688
No files matched your search
@@ -5,6 +5,7 @@
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'dart:async';
|
||||
import '../models/xtream_models.dart' as model;
|
||||
import 'package:xtremobile/core/models/playlist_config.dart';
|
||||
import 'package:xtremobile/core/api/api_client.dart';
|
||||
@@ -53,16 +54,27 @@ class XtreamServiceMobile {
|
||||
}
|
||||
|
||||
/// Get live channels for a category (with batch EPG support)
|
||||
/// If categoryId is empty, fetches ALL channels from all categories
|
||||
Future<List<model.Channel>> getLiveChannels(String categoryId) async {
|
||||
try {
|
||||
final queryParams = {
|
||||
'username': _username,
|
||||
'password': _password,
|
||||
'action': 'get_live_streams',
|
||||
};
|
||||
|
||||
// Only add category_id if specified
|
||||
if (categoryId.isNotEmpty) {
|
||||
queryParams['category_id'] = categoryId;
|
||||
}
|
||||
|
||||
if (kDebugMode) {
|
||||
print('🔍 Loading live channels with params: $queryParams');
|
||||
}
|
||||
|
||||
final response = await _dio.get(
|
||||
'$_baseUrl/player_api.php',
|
||||
queryParameters: {
|
||||
'username': _username,
|
||||
'password': _password,
|
||||
'action': 'get_live_streams',
|
||||
'category_id': categoryId,
|
||||
},
|
||||
queryParameters: queryParams,
|
||||
options: Options(
|
||||
receiveTimeout: const Duration(seconds: 15),
|
||||
sendTimeout: const Duration(seconds: 15),
|
||||
@@ -70,9 +82,22 @@ class XtreamServiceMobile {
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 && response.data is List) {
|
||||
return (response.data as List)
|
||||
final channels = (response.data as List)
|
||||
.map((e) => model.Channel.fromJson(e))
|
||||
.toList();
|
||||
|
||||
if (kDebugMode) {
|
||||
final categories = channels.map((c) => c.categoryName).toSet();
|
||||
print(
|
||||
'✅ Loaded ${channels.length} channels with ${categories.length} categories: $categories',
|
||||
);
|
||||
}
|
||||
|
||||
return channels;
|
||||
}
|
||||
|
||||
if (kDebugMode) {
|
||||
print('⚠️ Unexpected response status: ${response.statusCode}');
|
||||
}
|
||||
return [];
|
||||
} catch (e) {
|
||||
@@ -183,6 +208,53 @@ class XtreamServiceMobile {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get live TV categories
|
||||
Future<List<model.Category>> getLiveCategories() async {
|
||||
try {
|
||||
if (kDebugMode) print('🔍 Loading live TV categories with 8s timeout...');
|
||||
|
||||
final response = await _dio
|
||||
.get(
|
||||
'$_baseUrl/player_api.php',
|
||||
queryParameters: {
|
||||
'username': _username,
|
||||
'password': _password,
|
||||
'action': 'get_live_categories',
|
||||
},
|
||||
options: Options(
|
||||
receiveTimeout: const Duration(seconds: 8),
|
||||
sendTimeout: const Duration(seconds: 8),
|
||||
),
|
||||
)
|
||||
.timeout(const Duration(seconds: 8));
|
||||
|
||||
if (response.statusCode == 200 && response.data is List) {
|
||||
final categories = (response.data as List)
|
||||
.map((e) => model.Category.fromJson(e))
|
||||
.toList();
|
||||
|
||||
if (kDebugMode) {
|
||||
print('✅ Loaded ${categories.length} live categories');
|
||||
}
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
if (kDebugMode) {
|
||||
print('⚠️ Failed to load categories (status: ${response.statusCode})');
|
||||
}
|
||||
return [];
|
||||
} on TimeoutException {
|
||||
if (kDebugMode) {
|
||||
print('⏱️ Timeout loading live categories - will fallback to loading all channels');
|
||||
}
|
||||
return [];
|
||||
} catch (e) {
|
||||
if (kDebugMode) print('❌ Error loading live categories: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Get VOD categories
|
||||
Future<List<model.Category>> getVodCategories() async {
|
||||
try {
|
||||
@@ -209,16 +281,23 @@ class XtreamServiceMobile {
|
||||
}
|
||||
|
||||
/// Get movies by category
|
||||
/// If categoryId is empty, fetches ALL movies from all categories
|
||||
Future<List<model.VodItem>> getMoviesByCategory(String categoryId) async {
|
||||
try {
|
||||
final queryParams = {
|
||||
'username': _username,
|
||||
'password': _password,
|
||||
'action': 'get_vod_streams',
|
||||
};
|
||||
|
||||
// Only add category_id if specified
|
||||
if (categoryId.isNotEmpty) {
|
||||
queryParams['category_id'] = categoryId;
|
||||
}
|
||||
|
||||
final response = await _dio.get(
|
||||
'$_baseUrl/player_api.php',
|
||||
queryParameters: {
|
||||
'username': _username,
|
||||
'password': _password,
|
||||
'action': 'get_vod_streams',
|
||||
'category_id': categoryId,
|
||||
},
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
if (response.statusCode == 200 && response.data is List) {
|
||||
return (response.data as List)
|
||||
|
||||
@@ -17,14 +17,34 @@ final mobileXtreamServiceProvider =
|
||||
});
|
||||
|
||||
/// Mobile-specific live channels provider
|
||||
/// Loads ALL channels from ALL categories
|
||||
final mobileLiveChannelsProvider =
|
||||
FutureProvider.family<List<model.Channel>, PlaylistConfig>(
|
||||
(ref, playlist) async {
|
||||
final service = await ref.watch(mobileXtreamServiceProvider(playlist).future);
|
||||
// Correction: getLiveChannels returns List<Channel>, and we now need a selected category
|
||||
// If no category is selected, we might want to load all or first category.
|
||||
// For now, let's assume it should return all channels or handle category selection elsewhere.
|
||||
return service.getLiveChannels("");
|
||||
|
||||
// Strategy: Try to load categories first (with timeout)
|
||||
// If categories load successfully, load channels for each category
|
||||
// If categories fail/timeout, load all channels at once
|
||||
List<model.Category> categories = [];
|
||||
try {
|
||||
categories = await service.getLiveCategories();
|
||||
} catch (e) {
|
||||
// Silently fall back to loading all channels
|
||||
}
|
||||
|
||||
if (categories.isNotEmpty) {
|
||||
// Load channels from each category and combine them
|
||||
final allChannels = <model.Channel>[];
|
||||
for (final category in categories) {
|
||||
final channels = await service.getLiveChannels(category.categoryId);
|
||||
allChannels.addAll(channels);
|
||||
}
|
||||
return allChannels;
|
||||
}
|
||||
|
||||
// Fallback: Load all channels without category filter
|
||||
return service.getLiveChannels("");
|
||||
});
|
||||
|
||||
/// Mobile-specific movies provider
|
||||
|
||||
Reference in new issue
Block a user