Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions lib/backend/m3u.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:open_tv/backend/sql.dart';
import 'package:open_tv/backend/utils.dart';
import 'package:open_tv/backend/utils.dart' show Utils, ProgressCallback;
import 'package:open_tv/models/channel.dart';
import 'package:open_tv/models/channel_http_headers.dart';
import 'package:open_tv/models/channel_preserve.dart';
Expand All @@ -20,9 +20,10 @@ final httpOriginRegex = RegExp(r'http-origin=(.+)');
final httpReferrerRegex = RegExp(r'http-referrer=(.+)');
final httpUserAgentRegex = RegExp(r'http-user-agent=(.+)');

Future<void> processM3U(Source source, bool wipe, [String? path]) async {
Future<void> processM3U(Source source, bool wipe, [String? path, ProgressCallback? onProgress]) async {
path ??= source.url;
List<ChannelPreserve>? preserve;
onProgress?.call("Parsing channels...");
var file = File(
path!,
).openRead().transform(utf8.decoder).transform(const LineSplitter());
Expand All @@ -37,6 +38,7 @@ Future<void> processM3U(Source source, bool wipe, [String? path]) async {
String? channelLine;
ChannelHttpHeaders? headers;
var httpHeadersSet = false;
int channelCount = 0;
await for (var line in file) {
final lineUpper = line.toUpperCase();
if (lineUpper.startsWith("#EXTINF")) {
Expand All @@ -49,6 +51,10 @@ Future<void> processM3U(Source source, bool wipe, [String? path]) async {
httpHeadersSet ? headers : null,
statements,
);
channelCount++;
if (channelCount % 100 == 0) {
onProgress?.call("Parsing channels ($channelCount found)...");
}
}
channelLine = line;
lastLine = null;
Expand All @@ -67,11 +73,13 @@ Future<void> processM3U(Source source, bool wipe, [String? path]) async {
}
if (channelLine != null && lastLine != null && lastLine.trim().isNotEmpty) {
commitChannel(channelLine, lastLine, headers, statements);
channelCount++;
}
statements.add(Sql.updateGroups());
if (preserve != null) {
statements.add(Sql.restorePreserve(preserve));
}
onProgress?.call("Saving to database ($channelCount channels)...");
await Sql.commitWrite(statements);
}

Expand Down Expand Up @@ -147,12 +155,13 @@ bool setChannelHeaders(String headerLine, ChannelHttpHeaders headers) {
return false;
}

Future<void> processM3UUrl(Source source, bool wipe) async {
var path = await downloadM3U(source.url!);
await processM3U(source, wipe, path);
Future<void> processM3UUrl(Source source, bool wipe, [ProgressCallback? onProgress]) async {
var path = await downloadM3U(source.url!, onProgress);
await processM3U(source, wipe, path, onProgress);
}

Future<String> downloadM3U(String urlStr) async {
Future<String> downloadM3U(String urlStr, [ProgressCallback? onProgress]) async {
onProgress?.call("Downloading playlist...");
final url = Uri.parse(urlStr);
final client = http.Client();
final request = http.Request('GET', url);
Expand Down
26 changes: 17 additions & 9 deletions lib/backend/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import 'package:open_tv/models/source_type.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';

typedef ProgressCallback = void Function(String message);

class Utils {
static String? _appDir;
static Future<String> get appDir async {
Expand All @@ -23,29 +25,35 @@ class Utils {
return join(tempDir, fileName);
}

static Future<void> refreshSource(Source source) async {
static Future<void> refreshSource(Source source, [ProgressCallback? onProgress]) async {
refreshedSeries.clear();
await processSource(source, true);
await processSource(source, true, onProgress);
}

static Future<void> processSource(Source source, [bool wipe = false]) async {
static Future<void> processSource(Source source, [bool wipe = false, ProgressCallback? onProgress]) async {
switch (source.sourceType) {
case SourceType.m3u:
await processM3U(source, wipe);
await processM3U(source, wipe, null, onProgress);
break;
case SourceType.m3uUrl:
await processM3UUrl(source, wipe);
await processM3UUrl(source, wipe, onProgress);
break;
case SourceType.xtream:
await getXtream(source, wipe);
await getXtream(source, wipe, onProgress);
break;
}
}

static Future<void> refreshAllSources() async {
static Future<void> refreshAllSources([ProgressCallback? onProgress]) async {
var sources = await Sql.getSources();
for (var source in sources) {
await refreshSource(source);
for (var i = 0; i < sources.length; i++) {
var source = sources[i];
ProgressCallback? sourceProgress;
if (onProgress != null) {
var prefix = sources.length > 1 ? "Refreshing ${source.name} (${i + 1}/${sources.length})\n" : "";
sourceProgress = (msg) => onProgress("$prefix$msg");
}
await refreshSource(source, sourceProgress);
}
}

Expand Down
8 changes: 7 additions & 1 deletion lib/backend/xtream.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';

import 'package:open_tv/backend/sql.dart';
import 'package:open_tv/backend/utils.dart' show ProgressCallback;
import 'package:open_tv/models/channel.dart';
import 'package:open_tv/models/channel_preserve.dart';
import 'package:open_tv/models/media_type.dart';
Expand All @@ -18,7 +19,7 @@ const String getLiveStreamCategories = "get_live_categories";
const String getVodCategories = "get_vod_categories";
const String liveStreamExtension = "ts";

Future<void> getXtream(Source source, bool wipe) async {
Future<void> getXtream(Source source, bool wipe, [ProgressCallback? onProgress]) async {
List<Future<void> Function(SqliteWriteContext, Map<String, String>)>
statements = [];
List<ChannelPreserve>? preserve;
Expand All @@ -28,6 +29,7 @@ Future<void> getXtream(Source source, bool wipe) async {
statements.add(Sql.wipeSource(source.id!));
}
source.urlOrigin = Uri.parse(source.url!).origin;
onProgress?.call("Fetching data...");
var results = await Future.wait([
getXtreamHttpData(getLiveStreams, source),
getXtreamHttpData(getLiveStreamCategories, source),
Expand All @@ -39,6 +41,7 @@ Future<void> getXtream(Source source, bool wipe) async {
int failCount = 0;
if (results[0] != null && results[1] != null) {
try {
onProgress?.call("Processing livestreams...");
processXtream(
statements,
processJsonList(results[0], XtreamStream.fromJson),
Expand All @@ -54,6 +57,7 @@ Future<void> getXtream(Source source, bool wipe) async {
}
if (results[2] != null && results[3] != null) {
try {
onProgress?.call("Processing movies...");
processXtream(
statements,
processJsonList(results[2], XtreamStream.fromJson),
Expand All @@ -70,6 +74,7 @@ Future<void> getXtream(Source source, bool wipe) async {

if (results[4] != null && results[5] != null) {
try {
onProgress?.call("Processing series...");
processXtream(
statements,
processJsonList(results[4], XtreamStream.fromJson),
Expand All @@ -91,6 +96,7 @@ Future<void> getXtream(Source source, bool wipe) async {
if (preserve != null) {
statements.add(Sql.restorePreserve(preserve));
}
onProgress?.call("Saving to database...");
await Sql.commitWrite(statements);
}

Expand Down
28 changes: 23 additions & 5 deletions lib/loading.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,36 @@ import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:loader_overlay/loader_overlay.dart';

Widget progressOverlayBuilder(dynamic progress) {
return Column(
children: [
const Spacer(flex: 2),
const SpinKitCircle(color: Colors.blue, size: 50),
if (progress != null) ...[
const SizedBox(height: 16),
Text(
progress.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 14,
decoration: TextDecoration.none,
),
textAlign: TextAlign.center,
),
],
const Spacer(flex: 1),
],
);
}

class Loading extends StatelessWidget {
final Widget child;
const Loading({super.key, required this.child});

@override
Widget build(BuildContext context) {
return LoaderOverlay(
overlayWidgetBuilder: (_) {
return const Center(
child: SpinKitPulsingGrid(color: Colors.blue, size: 50),
);
},
overlayWidgetBuilder: progressOverlayBuilder,
child: child,
);
}
Expand Down
9 changes: 7 additions & 2 deletions lib/settings_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:open_tv/select_dialog.dart';
import 'package:open_tv/edit_dialog.dart';
import 'package:open_tv/home.dart';
import 'package:open_tv/loading.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:open_tv/models/home_manager.dart';
import 'package:open_tv/models/id_data.dart';
import 'package:open_tv/models/settings.dart';
Expand Down Expand Up @@ -140,7 +141,9 @@ class _SettingsState extends State<SettingsView> {
onPressed: () async {
await Error.tryAsync(
() async {
await Utils.refreshSource(source);
await Utils.refreshSource(source, (msg) {
if (context.mounted) context.loaderOverlay.progress(msg);
});
},
context,
"Source has been refreshed successfully",
Expand Down Expand Up @@ -351,7 +354,9 @@ class _SettingsState extends State<SettingsView> {
children: [
IconButton(
onPressed: () async => await Error.tryAsync(
() async => await Utils.refreshAllSources(),
() async => await Utils.refreshAllSources((msg) {
if (context.mounted) context.loaderOverlay.progress(msg);
}),
context,
"Successfully refreshed all sources",
),
Expand Down
6 changes: 6 additions & 0 deletions lib/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:open_tv/backend/sql.dart';
import 'package:open_tv/backend/utils.dart';
import 'package:open_tv/loading.dart' show progressOverlayBuilder;
import 'package:open_tv/correction_modal.dart';
import 'package:open_tv/home.dart';
import 'package:open_tv/models/filters.dart';
Expand Down Expand Up @@ -69,6 +70,10 @@ class _SetupState extends State<Setup> {
? formValues[Steps.password]
: null,
),
false,
(msg) {
if (context.mounted) context.loaderOverlay.progress(msg);
},
);
},
context,
Expand Down Expand Up @@ -207,6 +212,7 @@ class _SetupState extends State<Setup> {
appBar: widget.showAppBar ? AppBar() : null,
body: SafeArea(
child: LoaderOverlay(
overlayWidgetBuilder: progressOverlayBuilder,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expand Down