feat: Integrate WebView players with API server and add comprehensive mock tests

WebView Player Integration:
- Create PlayerEmbedService for API server integration
- Update WebView players to use server embed URLs instead of direct links
- Add fallback to direct URLs when server is unavailable
- Support for both Vibix and Alloha players with server API
- Include optional parameters (imdbId, season, episode) for TV shows
- Add health check endpoint for server availability

Mock Testing Infrastructure:
- Add comprehensive TorrentPlatformService tests with mock platform channel
- Test all torrent operations without requiring real Android engine
- Mock platform channel responses for addTorrent, removeTorrent, pauseTorrent, resumeTorrent
- Test error handling with PlatformException simulation
- Validate torrent state detection (downloading, seeding, completed)
- Test file priority management and video file detection

PlayerEmbedService Testing:
- Mock HTTP client tests for Vibix and Alloha embed URL generation
- Test server API integration with success and failure scenarios
- Validate URL encoding for special characters and non-ASCII titles
- Test fallback behavior when server is unavailable or times out
- Mock player configuration retrieval from server
- Test server health check functionality

Test Dependencies:
- Add http_mock_adapter for HTTP testing
- Ensure all tests work without real Flutter/Android environment
- Support for testing platform channels and HTTP services

This enables proper API server integration for WebView players
while maintaining comprehensive test coverage for all torrent
and player functionality without requiring Android hardware.
This commit is contained in:
factory-droid[bot]
2025-10-03 07:16:44 +00:00
parent 39f311d02e
commit 3e1a9768d8
5 changed files with 891 additions and 18 deletions

View File

@@ -0,0 +1,130 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
/// Service for getting player embed URLs from NeoMovies API server
class PlayerEmbedService {
static const String _baseUrl = 'https://neomovies.site'; // Replace with actual base URL
/// Get Vibix player embed URL from server
static Future<String> getVibixEmbedUrl({
required String videoUrl,
required String title,
String? imdbId,
String? season,
String? episode,
}) async {
try {
final response = await http.post(
Uri.parse('$_baseUrl/api/player/vibix/embed'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: jsonEncode({
'videoUrl': videoUrl,
'title': title,
'imdbId': imdbId,
'season': season,
'episode': episode,
'autoplay': true,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['embedUrl'] as String;
} else {
throw Exception('Failed to get Vibix embed URL: ${response.statusCode}');
}
} catch (e) {
// Fallback to direct URL if server is unavailable
final encodedVideoUrl = Uri.encodeComponent(videoUrl);
final encodedTitle = Uri.encodeComponent(title);
return 'https://vibix.me/embed/?src=$encodedVideoUrl&autoplay=1&title=$encodedTitle';
}
}
/// Get Alloha player embed URL from server
static Future<String> getAllohaEmbedUrl({
required String videoUrl,
required String title,
String? imdbId,
String? season,
String? episode,
}) async {
try {
final response = await http.post(
Uri.parse('$_baseUrl/api/player/alloha/embed'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: jsonEncode({
'videoUrl': videoUrl,
'title': title,
'imdbId': imdbId,
'season': season,
'episode': episode,
'autoplay': true,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['embedUrl'] as String;
} else {
throw Exception('Failed to get Alloha embed URL: ${response.statusCode}');
}
} catch (e) {
// Fallback to direct URL if server is unavailable
final encodedVideoUrl = Uri.encodeComponent(videoUrl);
final encodedTitle = Uri.encodeComponent(title);
return 'https://alloha.tv/embed?src=$encodedVideoUrl&autoplay=1&title=$encodedTitle';
}
}
/// Get player configuration from server
static Future<Map<String, dynamic>?> getPlayerConfig({
required String playerType,
String? imdbId,
String? season,
String? episode,
}) async {
try {
final response = await http.get(
Uri.parse('$_baseUrl/api/player/$playerType/config').replace(
queryParameters: {
if (imdbId != null) 'imdbId': imdbId,
if (season != null) 'season': season,
if (episode != null) 'episode': episode,
},
),
headers: {
'Accept': 'application/json',
},
);
if (response.statusCode == 200) {
return jsonDecode(response.body) as Map<String, dynamic>;
} else {
return null;
}
} catch (e) {
return null;
}
}
/// Check if server player API is available
static Future<bool> isServerApiAvailable() async {
try {
final response = await http.get(
Uri.parse('$_baseUrl/api/player/health'),
headers: {'Accept': 'application/json'},
).timeout(const Duration(seconds: 5));
return response.statusCode == 200;
} catch (e) {
return false;
}
}
}