[verified] Publish ReelBox source under GPLv3
This commit is contained in:
commit
db2b505ca3
445 files changed
+105274
No files matched your search
@@ -0,0 +1,132 @@
|
||||
import 'api_service.dart';
|
||||
import 'content_policy.dart';
|
||||
|
||||
class HomeBanner {
|
||||
const HomeBanner._({
|
||||
required this.titleEn,
|
||||
required this.titleFa,
|
||||
required this.subtitleEn,
|
||||
required this.subtitleFa,
|
||||
required this.target,
|
||||
required this.isAdvertisement,
|
||||
this.image,
|
||||
});
|
||||
|
||||
final String titleEn, titleFa, subtitleEn, subtitleFa;
|
||||
final Uri target;
|
||||
final Uri? image;
|
||||
final bool isAdvertisement;
|
||||
String title(bool persian) => persian ? titleFa : titleEn;
|
||||
String subtitle(bool persian) => persian ? subtitleFa : subtitleEn;
|
||||
|
||||
static final telegram = HomeBanner._(
|
||||
titleEn: 'ReelBox updates',
|
||||
titleFa: 'تازههای ریلباکس',
|
||||
subtitleEn: 'Updates and announcements',
|
||||
subtitleFa: 'بهروزرسانیها و اطلاعیهها',
|
||||
target: Uri.parse('https://t.me/ReelBoxApp'),
|
||||
isAdvertisement: false,
|
||||
);
|
||||
}
|
||||
|
||||
/// Only configured advertisements are parsed. The official Telegram entry is
|
||||
/// fixed in the client and can never be replaced or relabelled by server data.
|
||||
List<HomeBanner> parseHomeBanners(dynamic raw) {
|
||||
final result = <HomeBanner>[HomeBanner.telegram];
|
||||
if (raw is! Map || raw['banners'] is! List) return result;
|
||||
for (final row in (raw['banners'] as List).take(20)) {
|
||||
if (result.length == 6) break;
|
||||
if (row is! Map) continue;
|
||||
final en = _label(row['title_en'], 80);
|
||||
final fa = _label(row['title_fa'] ?? row['title_en'], 80);
|
||||
final subtitleEn = _label(row['subtitle_en'] ?? '', 180);
|
||||
final subtitleFa = _label(
|
||||
row['subtitle_fa'] ?? row['subtitle_en'] ?? '',
|
||||
180,
|
||||
);
|
||||
final target = _https(row['target_url']);
|
||||
final imageValue = row['image_url'];
|
||||
final image = imageValue == null || imageValue == ''
|
||||
? null
|
||||
: _https(imageValue);
|
||||
if (en == null ||
|
||||
en.isEmpty ||
|
||||
fa == null ||
|
||||
fa.isEmpty ||
|
||||
subtitleEn == null ||
|
||||
subtitleFa == null ||
|
||||
target == null ||
|
||||
(imageValue != null && imageValue != '' && image == null)) {
|
||||
continue;
|
||||
}
|
||||
result.add(
|
||||
HomeBanner._(
|
||||
titleEn: en,
|
||||
titleFa: fa,
|
||||
subtitleEn: subtitleEn,
|
||||
subtitleFa: subtitleFa,
|
||||
target: target,
|
||||
image: image,
|
||||
isAdvertisement: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
return List.unmodifiable(result);
|
||||
}
|
||||
|
||||
String? _label(dynamic value, int limit) {
|
||||
if (value is! String ||
|
||||
value.length > limit ||
|
||||
RegExp(r'[\x00-\x1f\x7f\u202a-\u202e\u2066-\u2069]').hasMatch(value) ||
|
||||
!ContentPolicy.allowsText(value)) {
|
||||
return null;
|
||||
}
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
Uri? _https(dynamic value) {
|
||||
if (value is! String ||
|
||||
value.length > 2048 ||
|
||||
RegExp(r'[\x00-\x20\x7f\\]').hasMatch(value) ||
|
||||
RegExp(
|
||||
r'%(?![0-9a-fA-F]{2})|%(?:0[0-9a-f]|1[0-9a-f]|7f)',
|
||||
caseSensitive: false,
|
||||
).hasMatch(value) ||
|
||||
!ContentPolicy.allowsUrl(value)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final uri = Uri.parse(value);
|
||||
if (uri.scheme != 'https' ||
|
||||
uri.host.isEmpty ||
|
||||
uri.userInfo.isNotEmpty ||
|
||||
uri.port != 443 ||
|
||||
uri.host.length > 253 ||
|
||||
!uri.host
|
||||
.split('.')
|
||||
.every(
|
||||
(part) =>
|
||||
RegExp(r'^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$')
|
||||
.hasMatch(part),
|
||||
)) {
|
||||
return null;
|
||||
}
|
||||
return uri;
|
||||
} on FormatException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses only the existing trusted metadata transport, never a config URL.
|
||||
class HomeBannerService {
|
||||
const HomeBannerService(this.api);
|
||||
final ApiService api;
|
||||
Future<List<HomeBanner>> load() async {
|
||||
try {
|
||||
return parseHomeBanners(await api.get('banners/'));
|
||||
} catch (_) {
|
||||
// Announcements remain reachable when the metadata service is offline.
|
||||
return [HomeBanner.telegram];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user