Skip to content

Commit

Permalink
Replaced consumet data provider by consumet.ts implementation moved t…
Browse files Browse the repository at this point in the history
…o Dart.

This is done because of consumet/api.consumet.org#486
  • Loading branch information
Kylart committed Oct 3, 2023
1 parent e475399 commit 834a796
Show file tree
Hide file tree
Showing 30 changed files with 563 additions and 696 deletions.
1 change: 0 additions & 1 deletion lib/data/consumet/consumet.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export 'providers/providers.dart';
export 'models/models.dart';
2 changes: 2 additions & 0 deletions lib/data/consumet/extractors/extractors.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'gogocdn.dart';
export 'streamsb.dart';
163 changes: 163 additions & 0 deletions lib/data/consumet/extractors/gogocdn.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import 'dart:convert';

import 'package:encrypt/encrypt.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart';

import '../models/models.dart';

class CDNKeys {
CDNKeys({
required this.key,
required this.secondKey,
required this.iv,
});

final Key key;
final Key secondKey;
final IV iv;
}

/// Adapted from `https://github.com/consumet/consumet.ts/blob/master/src/extractors/gogocdn.ts`
class GogoCDN extends Extractor {
final client = Client();
final serverName = 'goload';

final _keys = CDNKeys(
key: Key.fromUtf8('37911490979715163134003223491201'),
secondKey: Key.fromUtf8('54674138327930866480207815084989'),
iv: IV.fromUtf8('3134003223491201'),
);

var referrer = '';

@override
Future<List<VideoSource>> extract(Uri uri) async {
referrer = uri.toString();

final List<VideoSource> results = [];

final page = await client.get(uri);
final document = parse(page.body);

final encyptedParams =
_generateEncryptedAjaxParams(document, uri.queryParameters['id'] ?? '');

final encryptedData = await client.get(
Uri(
scheme: uri.scheme,
host: uri.host,
path: 'encrypt-ajax.php',
query: encyptedParams,
),
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
);

final decryptedData = _decryptAjaxData(
json.decode(encryptedData.body)['data'],
);
if (decryptedData['source'] == null) throw NoEpisodeSourceException;

final String? url = decryptedData['source'][0]['file'];

if (url?.contains('.m3u8') == true) {
final resResult = await client.get(Uri.parse(url!));
final regexp = RegExp(r'(RESOLUTION=)(.*)(\s*?)(\s*.*)');
final resolutions = regexp.allMatches(resResult.body);
final baseUrl = url.substring(0, url.lastIndexOf('/'));

for (final resolution in resolutions) {
final res = resolution[0] as String;

results.add(
VideoSource(
url: '$baseUrl/${res.split('\n')[1]}',
isM3U8: (baseUrl + res.split('\n')[1]).contains('.m3u8'),
quality: '${res.split('\n')[0].split('x')[1].split(',')[0]}p',
),
);
}

decryptedData['source'].forEach((dynamic source) {
results.add(
VideoSource(
url: url,
isM3U8: source['file'].contains('.m3u8'),
quality: 'default',
),
);
});
} else {
decryptedData['source'].forEach((dynamic source) {
results.add(
VideoSource(
url: source['file'],
isM3U8: source['file'].contains('.m3u8'),
quality: source.label.split(' ')[0] + 'p',
),
);
});
}

decryptedData['source_bk'].forEach((dynamic source) {
results.add(
VideoSource(
url: source['file'],
isM3U8: source['file'].contains('.m3u8'),
quality: 'backup',
),
);
});

return results;
}

String _generateEncryptedAjaxParams(
Document document,
String id,
) {
final encrypter = Encrypter(
AES(
_keys.key,
mode: AESMode.cbc,
),
);

final encryptedKey = encrypter.encrypt(
id,
iv: _keys.iv,
);

final scriptValue = document
.querySelector("script[data-name='episode']")
?.attributes["data-value"];

if (scriptValue == null) throw NoEpisodeSourceException;

final decryptedToken = encrypter.decrypt(
Encrypted.from64(scriptValue),
iv: _keys.iv,
);

return 'id=${encryptedKey.base64}&alias=$decryptedToken';
}

Map<String, dynamic> _decryptAjaxData(String encryptedData) {
final encrypter = Encrypter(
AES(
_keys.secondKey,
mode: AESMode.cbc,
),
);

final decryptedData = encrypter.decrypt(
Encrypted.from64(encryptedData),
iv: _keys.iv,
);

return json.decode(decryptedData);
}
}
81 changes: 81 additions & 0 deletions lib/data/consumet/extractors/streamsb.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'dart:convert';

import 'package:http/http.dart';

import '../models/models.dart';
import '../utils/utils.dart';

/// Adapted from `https://github.com/consumet/consumet.ts/blob/master/src/extractors/streamsb.ts`
class StreamSB extends Extractor {
final host = 'https://streamsss.net/sources50';
final host2 = 'https://watchsb.com/sources50';

final client = Client();

String payload(String hex) =>
'566d337678566f743674494a7c7c${hex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362';

@override
Future<List<VideoSource>> extract(Uri uri) async {
final List<VideoSource> results = [];
Map<String, String> headers = {
'watchsb': 'sbstream',
'User-Agent': userAgent,
'Referer': uri.toString(),
};

var id = uri.toString().split('/e/').lastOrNull;
if (id?.contains('html') == true) id = id?.split('.html').firstOrNull;

if (id == null) throw 'cannot find ID';

final res = await client.get(
Uri.parse(
'$host/${payload(utf8.encode(id).map((e) => e.toRadixString(16)).join())}',
),
headers: headers,
);
final jsonResponse = json.decode(res.body);

if (jsonResponse['stream_data'] == null) {
throw 'No source found. Try a different server.';
}

headers = {
'User-Agent': userAgent,
'Referer': uri.toString().split('e/').first,
};

final m3u8Urls = await client.get(
Uri.parse(jsonResponse['stream_data']['file']),
headers: headers,
);

final videoList = m3u8Urls.body.split('#EXT-X-STREAM-INF:');

for (final video in videoList) {
if (!video.contains('m3u8')) continue;

final url = video.split('\n')[1];
final quality = video.split('RESOLUTION=')[1].split(',')[0].split('x')[1];

results.add(
VideoSource(
url: url,
quality: '${quality}p',
isM3U8: true,
),
);
}

results.add(
VideoSource(
url: jsonResponse['stream_data']['file'],
quality: 'auto',
isM3U8: jsonResponse['stream_data']['file'].contains('.m3u8'),
),
);

return results;
}
}
4 changes: 0 additions & 4 deletions lib/data/consumet/models/anime/anime.dart

This file was deleted.

This file was deleted.

Loading

0 comments on commit 834a796

Please sign in to comment.