Skip to content

Commit

Permalink
Auto-update RSS task
Browse files Browse the repository at this point in the history
  • Loading branch information
Muska-Ami committed Sep 4, 2024
1 parent 52a18e9 commit 4f51556
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 54 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ MioFeed - Modern RSS reader
- [x] 时间排序
- [x] 主题功能
- [ ] 订阅分组
- [ ] 定时订阅拉取任务
- [x] 定时订阅拉取任务
- [ ] 自定义渲染功能

## 一些已知问题
Expand Down
4 changes: 4 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import 'package:miofeed/storages/settings_storage.dart';
import 'package:miofeed/tasks/task.dart';
import 'package:miofeed/ui/home.dart';
import 'package:miofeed/ui/settings.dart';
import 'package:miofeed/ui/settings/about.dart';
import 'package:miofeed/ui/settings/render.dart';
import 'package:miofeed/ui/settings/rss_subscribe.dart';
import 'package:miofeed/ui/settings/theme.dart';
import 'package:miofeed/storages/rss/rss_cache.dart';
import 'package:miofeed/utils/app_info.dart';
import 'package:miofeed/utils/shared_data.dart';

const String title = "MioFeed";
Expand All @@ -21,6 +23,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SharedData.init();
await RssCache.readAllToRemCache();
await AppInfo.init();

await _initSelfConfig();
Task.register();
Expand Down Expand Up @@ -103,6 +106,7 @@ class MyApp extends StatelessWidget {
const RssSubSettingUI(title: title),
'/settings/theme': (context) => ThemeSettingUI(title: title),
'/settings/render': (context) => RenderSettingUI(title: title),
'/about': (context) => AboutUI(title: title),
},
home: HomeUI(title: title),
);
Expand Down
4 changes: 4 additions & 0 deletions lib/models/task_basic.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
abstract class TaskBasic {
late Function? callback;
startUp({Function? callback});
}
7 changes: 7 additions & 0 deletions lib/storages/rss/rss_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ class RssCache {
'data': feed,
});
static Future<void> removeMemCache(rss) async => rssList.remove(rss);
static Future<void> removeMemCacheBySubName(String name) async {
late final Map<String, dynamic> res;
for (var item in rssList) {
if (item['sub'].name == name) res = item;
}
rssList.remove(res);
}
static get rssMemCache => rssList;

static Future<void> readAllToRemCache() async {
Expand Down
46 changes: 46 additions & 0 deletions lib/tasks/android_subscribe_update.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:background_fetch/background_fetch.dart';
import 'package:miofeed/tasks/subscribe_update.dart';

class AndroidSubscribeUpdateTask {
@pragma('vm:entry-point')
static void backgroundFetchHeadlessTask(HeadlessTask task) async {
String taskId = task.taskId;
bool isTimeout = task.timeout;
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
print("[BackgroundFetch] Headless task timed-out: $taskId");
BackgroundFetch.finish(taskId);
return;
}
print('[BackgroundFetch] Headless event received.');
// Do your work here...
await SubscribeUpdateTask.run();
BackgroundFetch.finish(taskId);
}
}

// void _onClickEnable(enabled) {
// setState(() {
// _enabled = enabled;
// });
// if (enabled) {
// BackgroundFetch.start().then((int status) {
// print('[BackgroundFetch] start success: $status');
// }).catchError((e) {
// print('[BackgroundFetch] start FAILURE: $e');
// });
// } else {
// BackgroundFetch.stop().then((int status) {
// print('[BackgroundFetch] stop success: $status');
// });
// }
// }
//
// void _onClickStatus() async {
// int status = await BackgroundFetch.status;
// print('[BackgroundFetch] status: $status');
// setState(() {
// _status = status;
// });
// }
118 changes: 76 additions & 42 deletions lib/tasks/subscribe_update.dart
Original file line number Diff line number Diff line change
@@ -1,44 +1,78 @@
import 'package:background_fetch/background_fetch.dart';

class SubscribeUpdateTask {
@pragma('vm:entry-point')
static void backgroundFetchHeadlessTask(HeadlessTask task) async {
String taskId = task.taskId;
bool isTimeout = task.timeout;
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
print("[BackgroundFetch] Headless task timed-out: $taskId");
BackgroundFetch.finish(taskId);
return;
import 'package:dart_rss/domain/atom_feed.dart';
import 'package:dart_rss/domain/rss1_feed.dart';
import 'package:dart_rss/domain/rss_feed.dart';
import 'package:miofeed/models/task_basic.dart';
import 'package:miofeed/storages/rss/rss_storage.dart';

import '../models/rss.dart';
import '../models/universal_feed.dart';
import '../storages/rss/rss_cache.dart';
import '../utils/network/get_rss.dart';

class SubscribeUpdateTask extends TaskBasic {

static final _storage = RssStorage();

static Future<void> run() async {
final list = await _storage.getRssList() ?? [];
for (var sub in list) {
RSS data = await _storage.getRss(sub);

// 如果没开自动更新直接跳过
if (!data.autoUpdate) break;

print('Updating subscribe: $sub');

final url = data.subscribeUrl;
final String res;
try {
res = await NetworkGetRss().get(url);
} catch (e, s) {
print('Update RSS sub ${data.name} failed:');
print(e);
print(s);
return;
}
//print(res);
late final UniversalFeed parsed;
try {
final parsedData = _parse(res, data.type);
if (parsedData is AtomFeed) {
parsed = UniversalFeed.fromAtom(parsedData);
// print(data.items.first.links.first.href);
} else if (parsedData is RssFeed) {
parsed = UniversalFeed.fromRss(parsedData);
} else if (parsedData is Rss1Feed) {
parsed = UniversalFeed.fromRss1(parsedData);
}
} catch (e, s) {
print('Parse result for RSS sub ${data.name} failed:');
print(e);
print(s);
return;
}
data.data = parsed;
// print(parsed);
await RssCache.save(data, res);
await RssCache.removeMemCacheBySubName(sub);
await RssCache.toMemCache(data, data.data);
print('Update for subscribe finished: $sub');
}
}

static _parse(String data, int type) {
switch (type) {
case 0:
return AtomFeed.parse(data);
case 1:
return Rss1Feed.parse(data);
case 2:
return RssFeed.parse(data);
}
print('[BackgroundFetch] Headless event received.');
// Do your work here...
BackgroundFetch.finish(taskId);
}
}

// void _onClickEnable(enabled) {
// setState(() {
// _enabled = enabled;
// });
// if (enabled) {
// BackgroundFetch.start().then((int status) {
// print('[BackgroundFetch] start success: $status');
// }).catchError((e) {
// print('[BackgroundFetch] start FAILURE: $e');
// });
// } else {
// BackgroundFetch.stop().then((int status) {
// print('[BackgroundFetch] stop success: $status');
// });
// }
// }
//
// void _onClickStatus() async {
// int status = await BackgroundFetch.status;
// print('[BackgroundFetch] status: $status');
// setState(() {
// _status = status;
// });
// }

@override
startUp({Function? callback}) async {
await run();
}
}
23 changes: 15 additions & 8 deletions lib/tasks/task.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'dart:io';

import 'package:background_fetch/background_fetch.dart';
import 'package:miofeed/tasks/subscribe_update.dart';
import 'package:miofeed/tasks/android_subscribe_update.dart';
import 'package:miofeed/utils/task_scheduler.dart';

class Task {
static final _config = BackgroundFetchConfig(
Expand All @@ -16,12 +17,18 @@ class Task {
);

static Future<void> doConfigure() async {
int status = await BackgroundFetch.configure(
_config,
_callbackHandler,
_errorHandler,
);
print('[BackgroundFetch] configure success: $status');
if (Platform.isAndroid) {
int status = await BackgroundFetch.configure(
_config,
_callbackHandler,
_errorHandler,
);
print('[BackgroundFetch] configure success: $status');
} else if (Platform.isIOS) {

} else {
TaskScheduler.start();
}
}

static void _callbackHandler(String taskId) async {
Expand All @@ -41,7 +48,7 @@ class Task {
static void register() {
if (Platform.isAndroid) {
BackgroundFetch.registerHeadlessTask(
SubscribeUpdateTask.backgroundFetchHeadlessTask,
AndroidSubscribeUpdateTask.backgroundFetchHeadlessTask,
);
}
}
Expand Down
25 changes: 25 additions & 0 deletions lib/ui/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:get/get.dart';
import 'package:miofeed/controllers/navigator_controller.dart';
import 'package:miofeed/models/universal_feed.dart';
import 'package:miofeed/models/universal_item.dart';
import 'package:miofeed/tasks/subscribe_update.dart';
import 'package:miofeed/ui/paragraph.dart';
import 'package:miofeed/utils/after_layout.dart';
import 'package:miofeed/utils/paragraph_utils.dart';
Expand All @@ -26,6 +27,30 @@ class HomeUI extends StatelessWidget {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
actions: [
IconButton(
onPressed: () async {
progressbar.start();
await SubscribeUpdateTask.run();
progressbar.finish();
},
icon: const Icon(Icons.refresh),
),
IconButton(
onPressed: () async {
Get.dialog(
const SimpleDialog(
children: [
Center(
child: Text('Comming soon'),
)
],
),
);
},
icon: const Icon(Icons.search),
)
],
title: Text(title),
bottom: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 3),
Expand Down
9 changes: 9 additions & 0 deletions lib/ui/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ class SettingsUI extends StatelessWidget {
Get.toNamed('/settings/render');
},
),
InkWell(
child: const ListTile(
leading: Icon(Icons.info),
title: Text("关于"),
),
onTap: () async {
Get.toNamed('/about');
},
),
],
),
bottomNavigationBar: NavigationBarX().build(),
Expand Down
Loading

0 comments on commit 4f51556

Please sign in to comment.