Skip to content

Commit

Permalink
feat: anilist tracking (#155)
Browse files Browse the repository at this point in the history
* feat:get anilist data

change android manifeast for web auth
SettingKey.tmdbKay -> SettingKey.tmdbKey
add svg and web auth library

add in app webview

update anilist api

* initial desktop support

* feat(mobile):add anilist

* feat: anilist fully support on desktop

* feat: show snakbar

also change the position of tracking button

* fix: anilist ui for android

-add unbind button that only delete inapp instead of deleting anilist too
- redesign ui for android list editor

* anilist tracking page

* fix anilist tracking page

* anilist more page

* AniList binding page

* getMediaList by using id

* fix: edit list error

add auto update progress in anime

* Revert "fix: edit list error"

This reverts commit ca3f819.

* feat: desktop tracking dialog

* feat: android tracking dialog

* fix

* fix

* Refactor AnilistType usage in detail_tracking_button.dart

* Refactor Anilist tracking dialog and horizontal list widget

* Add auto-tracking feature and Anilist integration

* Fix Anilist token saving and cookie handling

* Fix error handling in AniListProvider and AnilistMorePage

* add i18n

* Update localization and UI text

---------

Co-authored-by: MiaoMint <miaomint@0u0.ren>
  • Loading branch information
appdevelpo and MiaoMint authored Jan 16, 2024
1 parent 4c40645 commit f663535
Show file tree
Hide file tree
Showing 39 changed files with 2,667 additions and 96 deletions.
36 changes: 34 additions & 2 deletions assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"hi": "हिंदी"
},
"common": {
"anime": "Anime",
"manga": "Manga",
"home": "Home",
"search": "Search",
"extension": "Extensions",
Expand All @@ -38,7 +40,11 @@
"delete": "Delete",
"delete-all": "Delete all",
"save": "Save",
"save-success": "Save success"
"save-success": "Save success",
"logout": "Logout",
"login": "Login",
"no-data": "No data",
"clear": "Clear"
},
"home": {
"continue-watching": "Continue",
Expand Down Expand Up @@ -81,6 +87,8 @@
"comic-reader-subtitle": "Default reader mode...",
"tracking": "Tracking",
"tracking-subtitle": "AniList...",
"auto-tracking": "Auto Tracking",
"auto-tracking-subtitle": "Automatically sync progress when finished watching / reading",
"about": "About",
"links": "Links",
"contributors": "Contributors",
Expand Down Expand Up @@ -119,6 +127,7 @@
},
"external-player-launching": "Launching {player}",
"detail": {
"tracking": "Tracking",
"favorite": "Favorite",
"favorited": "Favorited",
"continue-watching": "Continue {episode}",
Expand All @@ -129,7 +138,8 @@
"get-lastest-data-error": "Failed to get latest data",
"modify-tmdb-binding": "Modify TMDB Binding",
"no-tmdb-data": "No TMDB data matched, please bind the data yourself",
"tmdb-key-missing": "TMDB API Key missing, please fill in the settings"
"tmdb-key-missing": "TMDB API Key missing, please fill in the settings",
"tracker": "Tracking"
},
"video": {
"episodes": "Episodes",
Expand Down Expand Up @@ -219,5 +229,27 @@
"stop": "Stop",
"upgrade": "Upgrade",
"start": "Start"
},
"anilist":{
"title":"Anilist Tracking",
"login-hint-1": "Seems you haven't login into AniList yet",
"login-hint-2": "Please login into AniList first",
"status": "Status",
"score": "Score",
"watching": "Watching",
"reading": "reading",
"completed": "Completed",
"paused": "Paused",
"dropped": "Dropped",
"planning": "Planning",
"hold-on": "Hold on",
"re-watching": "Re-watching",
"re-reading": "Re-reading",
"start-date": "Start Date",
"end-date": "End Date",
"unbind":"Unbind",
"episodes":"Episodes",
"manga-chaper-read":"Manga Chaper Read: {chapters}",
"anime-episode-watch":"Anime Episode Watched: {episodes}"
}
}
30 changes: 29 additions & 1 deletion assets/i18n/zh.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"common": {
"anime": "动漫",
"manga": "漫画",
"home": "首页",
"search": "搜索",
"extension": "扩展",
Expand All @@ -25,7 +27,9 @@
"delete": "删除",
"delete-all": "删除全部",
"save": "保存",
"save-success": "保存成功"
"save-success": "保存成功",
"logout": "登出",
"clear": "清除"
},
"home": {
"continue-watching": "继续观看",
Expand Down Expand Up @@ -68,6 +72,8 @@
"comic-reader-subtitle": "默认阅读模式...",
"tracking": "追踪",
"tracking-subtitle": "AniList...",
"auto-tracking": "自动追踪观看/阅读进度",
"auto-tracking-subtitle": "结束观看/阅读后自动更新进度",
"about": "关于",
"links": "链接",
"contributors": "贡献者",
Expand Down Expand Up @@ -104,6 +110,7 @@
},
"external-player-launching": "正在启动 {player}",
"detail": {
"tracking": "追踪",
"favorite": "收藏",
"favorited": "已收藏",
"continue-watching": "继续 {episode}",
Expand Down Expand Up @@ -190,5 +197,26 @@
"stop": "停止",
"upgrade": "升级",
"start": "启动"
},
"anilist": {
"title": "Anilist 追踪",
"login-hint-1": "你需要登录 AniList 才能使用此功能",
"login-hint-2": "请登录后重试",
"status": "状态",
"score": "评分",
"watching": "观看中",
"reading": "阅读中",
"completed": "已完成",
"dropped": "已放弃",
"planning": "计划中",
"hold-on": "搁置中",
"re-watching": "重看中",
"re-reading": "重读中",
"start-date": "开始日期",
"end-date": "结束日期",
"unbind": "取消绑定",
"episodes": "进度",
"manga-chaper-read": "看过的漫画章节: {chapters}",
"anime-episode-watch": "看过的动画剧集: {episodes}"
}
}
Binary file added assets/icon/anilist.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 25 additions & 5 deletions lib/controllers/detail_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class DetailPageController extends GetxController {
final RxString error = ''.obs;
final RxBool isLoading = true.obs;
final RxInt selectEpGroup = 0.obs;
final RxString aniListID = ''.obs;
final Rx<TMDBDetail?> tmdb = Rx(null);
final Rx<ExtensionService?> runtime = Rx(null);
ExtensionType get type =>
Expand Down Expand Up @@ -143,6 +144,7 @@ class DetailPageController extends GetxController {
try {
_miruDetail = await DatabaseService.getMiruDetail(package, url);
_tmdbID = _miruDetail?.tmdbID ?? -1;
aniListID.value = _miruDetail?.aniListID ?? "";
await getDetail();
await getTMDBDetail();
await getHistory();
Expand All @@ -156,7 +158,7 @@ class DetailPageController extends GetxController {
// 修改 tmdb 绑定
modifyTMDBBinding() async {
// 判断是否有 key
if (MiruStorage.getSetting(SettingKey.tmdbKay) == "") {
if (MiruStorage.getSetting(SettingKey.tmdbKey) == "") {
showPlatformSnackbar(
context: currentContext,
content: 'detail.tmdb-key-missing'.i18n,
Expand Down Expand Up @@ -200,8 +202,13 @@ class DetailPageController extends GetxController {
getRemoteDeatil() async {
try {
detail = await runtime.value!.detail(url);
await DatabaseService.putMiruDetail(package, url, detail!,
tmdbID: _tmdbID);
await DatabaseService.putMiruDetail(
package,
url,
detail!,
tmdbID: _tmdbID,
anilistID: aniListID.value,
);
} catch (e) {
// 弹出错误信息
if (runtime.value == null) {
Expand Down Expand Up @@ -265,6 +272,16 @@ class DetailPageController extends GetxController {
url,
detail!,
tmdbID: _tmdbID,
anilistID: aniListID.value,
);
}

saveAniListIds() async {
await DatabaseService.putMiruDetail(
package,
url,
detail!,
anilistID: aniListID.value,
);
}

Expand All @@ -284,8 +301,10 @@ class DetailPageController extends GetxController {
}

refreshFavorite() async {
isFavorite.value =
await DatabaseService.isFavorite(package: package, url: url);
isFavorite.value = await DatabaseService.isFavorite(
package: package,
url: url,
);
}

toggleFavorite() async {
Expand Down Expand Up @@ -397,6 +416,7 @@ class DetailPageController extends GetxController {
title: detail!.title,
episodeGroupId: selectEpGroup,
detailUrl: url,
anilistID: aniListID.value,
),
);
}),
Expand Down
83 changes: 83 additions & 0 deletions lib/controllers/tracking_page_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'dart:io';

import 'package:flutter_windows_webview/flutter_windows_webview.dart';
import 'package:get/get.dart';
import 'package:miru_app/data/providers/anilist_provider.dart';
import 'package:miru_app/utils/miru_storage.dart';
import 'package:miru_app/views/pages/tracking/anilist_webview.dart';

class TrackingPageController extends GetxController {
final anilistIsLogin = false.obs;
final anilistOauthUrl = "".obs;
final anilistUserData = {}.obs;

Future<Map<String, dynamic>> initAnilistData() async {
final Map<String, dynamic> result = {};
result["userData"] = await AniListProvider.getuserData();
result["animeData"] =
await AniListProvider.getCollection(AnilistType.anime);
result["mangaData"] =
await AniListProvider.getCollection(AnilistType.manga);
return result;
}

_saveAnilistToken(String result) {
RegExp tokenRegex = RegExp(r'(?<=access_token=).+(?=&token_type)');
Match? re = tokenRegex.firstMatch(result);
if (re != null) {
String token = re.group(0)!;
updateAniListToken(token);
}
}

updateAniListToken(String accessToken) {
MiruStorage.setSetting(SettingKey.aniListToken, accessToken);
anilistIsLogin.value = true;
initAnilistData();
}

logoutAniList() {
MiruStorage.setSetting(SettingKey.aniListToken, "");
anilistIsLogin.value = false;
}

loginAniList() async {
const loginUrl =
"https://anilist.co/api/v2/oauth/authorize?client_id=16214&response_type=token";
if (Platform.isAndroid) {
final result = await Get.to(
() => const AnilistWebViewPage(url: loginUrl),
);
_saveAnilistToken(result);
return;
}
final webview = FlutterWindowsWebview();
webview.launchWebview(loginUrl, WebviewOptions(
onNavigation: (url) {
if (url.contains("miru-app")) {
_saveAnilistToken(url);
webview.getCookies("https://anilist.co").then((cookies) async {
for (final cookie in cookies.entries) {
await webview.setCookie(
name: cookie.key,
value: "",
domain: "anilist.co",
);
}
webview.close();
});
}
return false;
},
));
}

@override
void onInit() {
final token = MiruStorage.getSetting(SettingKey.aniListToken);
if (token != "") {
anilistIsLogin.value = true;
}
super.onInit();
}
}
9 changes: 9 additions & 0 deletions lib/controllers/watch/comic_controller.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart';
import 'package:miru_app/data/providers/anilist_provider.dart';
import 'package:miru_app/models/index.dart';
import 'package:miru_app/controllers/watch/reader_controller.dart';
import 'package:miru_app/data/services/database_service.dart';
Expand All @@ -16,6 +17,7 @@ class ComicController extends ReaderController<ExtensionMangaWatch> {
required super.episodeGroupId,
required super.runtime,
required super.cover,
required super.anilistID,
});
Map<String, MangaReadMode> readmode = {
'standard': MangaReadMode.standard,
Expand Down Expand Up @@ -159,6 +161,13 @@ class ComicController extends ReaderController<ExtensionMangaWatch> {
);
}
pageController.value.dispose();
if (MiruStorage.getSetting(SettingKey.autoTracking) && anilistID != "") {
AniListProvider.editList(
status: AnilistMediaListStatus.current,
progress: playIndex + 1,
mediaId: anilistID,
);
}
super.onClose();
}
}
1 change: 1 addition & 0 deletions lib/controllers/watch/novel_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class NovelController extends ReaderController<ExtensionFikushonWatch> {
required super.episodeGroupId,
required super.runtime,
required super.cover,
required super.anilistID,
});

// 字体大小
Expand Down
2 changes: 2 additions & 0 deletions lib/controllers/watch/reader_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ReaderController<T> extends GetxController {
final int episodeGroupId;
final ExtensionService runtime;
final String? cover;
final String anilistID;

ReaderController({
required this.title,
Expand All @@ -23,6 +24,7 @@ class ReaderController<T> extends GetxController {
required this.playIndex,
required this.episodeGroupId,
required this.runtime,
required this.anilistID,
this.cover,
});

Expand Down
12 changes: 12 additions & 0 deletions lib/controllers/watch/video_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:get/get.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:miru_app/data/providers/anilist_provider.dart';
import 'package:miru_app/data/providers/bt_server_provider.dart';
import 'package:miru_app/models/index.dart';
import 'package:miru_app/views/dialogs/bt_dialog.dart';
Expand All @@ -39,6 +40,7 @@ class VideoPlayerController extends GetxController {
final int playIndex;
final int episodeGroupId;
final ExtensionService runtime;
final String anilistID;

VideoPlayerController({
required this.title,
Expand All @@ -47,6 +49,7 @@ class VideoPlayerController extends GetxController {
required this.playIndex,
required this.episodeGroupId,
required this.runtime,
required this.anilistID,
});

final player = Player();
Expand Down Expand Up @@ -492,6 +495,15 @@ class VideoPlayerController extends GetxController {
DeviceOrientation.portraitDown,
]);
}

if (MiruStorage.getSetting(SettingKey.autoTracking) && anilistID != "") {
AniListProvider.editList(
status: AnilistMediaListStatus.current,
progress: playIndex + 1,
mediaId: anilistID,
);
}

super.onClose();
}
}
Expand Down
Loading

0 comments on commit f663535

Please sign in to comment.