feat: app端首页推荐

This commit is contained in:
guozhigq
2023-08-14 10:05:16 +08:00
parent 17b02d9ae9
commit 0d852987fa
9 changed files with 140 additions and 23 deletions

View File

@ -7,3 +7,10 @@ class StyleString {
static const Radius imgRadius = Radius.circular(10); static const Radius imgRadius = Radius.circular(10);
static const double aspectRatio = 16 / 10; static const double aspectRatio = 16 / 10;
} }
class Constants {
static const String appKey = '27eb53fc9058f8c3';
static const String thirdSign = '04224646d1fea004e79606d3b038c84a';
static const String thirdApi =
'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png';
}

View File

@ -58,6 +58,9 @@ class Request {
log("setCookie, ${e.toString()}"); log("setCookie, ${e.toString()}");
} }
} }
var cookieString =
cookie.map((cookie) => '${cookie.name}=${cookie.value}').join('; ');
dio.options.headers['cookie'] = cookieString;
} }
// 移除cookie // 移除cookie

View File

@ -1,6 +1,8 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/utils/storage.dart';
// import 'package:get/get.dart' hide Response; // import 'package:get/get.dart' hide Response;
class ApiInterceptor extends Interceptor { class ApiInterceptor extends Interceptor {
@ -13,8 +15,26 @@ class ApiInterceptor extends Interceptor {
handler.next(options); handler.next(options);
} }
Box setting = GStrorage.setting;
@override @override
void onResponse(Response response, ResponseInterceptorHandler handler) { void onResponse(Response response, ResponseInterceptorHandler handler) {
try {
if (response.statusCode == 302) {
List<String> locations = response.headers['location']!;
if (locations.isNotEmpty) {
if (locations.first.startsWith('https://www.mcbbs.net')) {
final uri = Uri.parse(locations.first);
final accessKey = uri.queryParameters['access_key'];
final mid = uri.queryParameters['mid'];
setting.put(UserBoxKey.accessKey, {'mid': mid, 'value': accessKey});
}
}
}
} catch (err) {
print('ApiInterceptor: $err');
}
handler.next(response); handler.next(response);
} }

View File

@ -1,4 +1,7 @@
import 'package:dio/dio.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/api.dart';
import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/model_hot_video_item.dart'; import 'package:pilipala/models/model_hot_video_item.dart';
import 'package:pilipala/models/user/fav_detail.dart'; import 'package:pilipala/models/user/fav_detail.dart';
@ -179,4 +182,19 @@ class UserHttp {
return {'status': false, 'msg': res.data['message']}; return {'status': false, 'msg': res.data['message']};
} }
} }
// 获取用户凭证
static Future thirdLogin() async {
var res = await Request().get(
'https://passport.bilibili.com/login/app/third',
data: {
'appkey': Constants.appKey,
'api': Constants.thirdApi,
'sign': Constants.thirdSign,
},
);
if (res.data['code'] == 0 && res.data['data']['has_login'] == 1) {
Request().get(res.data['data']['confirm_uri']);
}
}
} }

View File

@ -1,5 +1,7 @@
import 'dart:developer'; import 'dart:developer';
import 'package:hive/hive.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/api.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
@ -9,12 +11,15 @@ import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/user/fav_folder.dart';
import 'package:pilipala/models/video/play/url.dart'; import 'package:pilipala/models/video/play/url.dart';
import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/utils/storage.dart';
/// res.data['code'] == 0 请求正常返回结果 /// res.data['code'] == 0 请求正常返回结果
/// res.data['data'] 为结果 /// res.data['data'] 为结果
/// 返回{'status': bool, 'data': List} /// 返回{'status': bool, 'data': List}
/// view层根据 status 判断渲染逻辑 /// view层根据 status 判断渲染逻辑
class VideoHttp { class VideoHttp {
static Box setting = GStrorage.setting;
// 首页推荐视频 // 首页推荐视频
static Future rcmdVideoList({required int ps, required int freshIdx}) async { static Future rcmdVideoList({required int ps, required int freshIdx}) async {
try { try {
@ -55,6 +60,9 @@ class VideoHttp {
'device_type': 0, 'device_type': 0,
'device_name': 'vivo', 'device_name': 'vivo',
'pull': freshIdx == 0 ? 'true' : 'false', 'pull': freshIdx == 0 ? 'true' : 'false',
'appkey': Constants.appKey,
'access_key':
setting.get(UserBoxKey.accessKey, defaultValue: {})['value'] ?? ''
}, },
); );
if (res.data['code'] == 0) { if (res.data['code'] == 0) {

View File

@ -1,3 +1,5 @@
import 'dart:developer';
class RecVideoItemAppModel { class RecVideoItemAppModel {
RecVideoItemAppModel({ RecVideoItemAppModel({
this.id, this.id,
@ -11,30 +13,60 @@ class RecVideoItemAppModel {
this.isFollowed, this.isFollowed,
this.owner, this.owner,
this.rcmdReason, this.rcmdReason,
this.goto,
this.param,
this.uri,
this.talkBack,
this.bangumiView,
this.bangumiFollow,
this.bangumiBadge,
}); });
int? id; int? id;
int? aid; int? aid;
int? bvid; String? bvid;
int? cid; int? cid;
String? pic; String? pic;
Stat? stat; Stat? stat;
int? duration; String? duration;
String? title; String? title;
int? isFollowed; int? isFollowed;
Owner? owner; Owner? owner;
String? rcmdReason; RcmdReason? rcmdReason;
String? goto;
String? param;
String? uri;
String? talkBack;
// 番剧
String? bangumiView;
String? bangumiFollow;
String? bangumiBadge;
RecVideoItemAppModel.fromJson(Map<String, dynamic> json) { RecVideoItemAppModel.fromJson(Map<String, dynamic> json) {
id = json['player_args']['aid']; id = json['player_args'] != null
aid = json['player_args']['aid']; ? json['player_args']['aid']
cid = json['player_args']['cid']; : int.parse(json['param'] ?? '-1');
aid = json['player_args'] != null ? json['player_args']['aid'] : -1;
cid = json['player_args'] != null ? json['player_args']['cid'] : -1;
pic = json['cover']; pic = json['cover'];
stat = Stat.fromJson(json); stat = Stat.fromJson(json);
duration = json['player_args']['duration']; duration = json['cover_right_text'];
title = json['title']; title = json['title'];
isFollowed = 0; isFollowed = 0;
owner = Owner.fromJson(json); owner = Owner.fromJson(json);
rcmdReason = json['rcmd_reason_style'] != null
? RcmdReason.fromJson(json['rcmd_reason_style'])
: null;
goto = json['goto'];
param = json['param'];
uri = json['uri'];
talkBack = json['talk_back'];
if (json['goto'] == 'bangumi') {
bangumiView = json['cover_left_text_1'];
bangumiFollow = json['cover_left_text_2'];
bangumiBadge = json['badge'];
}
} }
} }
@ -42,15 +74,15 @@ class Stat {
Stat({ Stat({
this.view, this.view,
this.like, this.like,
this.danmaku, this.danmu,
}); });
String? view; String? view;
String? like; String? like;
String? danmaku; String? danmu;
Stat.fromJson(Map<String, dynamic> json) { Stat.fromJson(Map<String, dynamic> json) {
view = json["cover_left_text_1"]; view = json["cover_left_text_1"];
danmaku = json['cover_left_text_2']; danmu = json['cover_left_text_2'];
} }
} }
@ -58,8 +90,29 @@ class Owner {
Owner({this.name}); Owner({this.name});
String? name; String? name;
int? mid;
Owner.fromJson(Map<String, dynamic> json) { Owner.fromJson(Map<String, dynamic> json) {
name = json['args']['up_name']; if (json['goto'] == 'bangumi') {
log(json.toString());
}
name = json['goto'] == 'av'
? json['args']['up_name']
: json['desc_button'] != null
? json['desc_button']['text']
: '';
mid = json['args']['up_id'] ?? -1;
}
}
class RcmdReason {
RcmdReason({
this.content,
});
String? content;
RcmdReason.fromJson(Map<String, dynamic> json) {
content = json["title"] ?? '';
} }
} }

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/index.dart'; import 'package:pilipala/http/index.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/common/tab_type.dart'; import 'package:pilipala/models/common/tab_type.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
@ -54,6 +55,7 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
defaultSearch.value = res.data['data']['name']; defaultSearch.value = res.data['data']['name'];
} }
UserHttp.thirdLogin();
} }
// 更新登录状态 // 更新登录状态

View File

@ -2,15 +2,16 @@ import 'package:flutter/cupertino.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/home/rcmd/result.dart';
import 'package:pilipala/models/model_rec_video_item.dart'; import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
class RcmdController extends GetxController { class RcmdController extends GetxController {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
int count = 12; int count = 12;
int _currentPage = 1; int _currentPage = 0;
int crossAxisCount = 2; int crossAxisCount = 2;
RxList<RecVideoItemModel> videoList = [RecVideoItemModel()].obs; RxList<RecVideoItemAppModel> videoList = [RecVideoItemAppModel()].obs;
bool isLoadingMore = false; bool isLoadingMore = false;
bool flag = false; bool flag = false;
OverlayEntry? popupDialog; OverlayEntry? popupDialog;
@ -19,19 +20,22 @@ class RcmdController extends GetxController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
if (recVideo.get('cacheList') != null && // if (recVideo.get('cacheList') != null &&
recVideo.get('cacheList').isNotEmpty) { // recVideo.get('cacheList').isNotEmpty) {
List<RecVideoItemModel> list = []; // List<RecVideoItemModel> list = [];
for (var i in recVideo.get('cacheList')) { // for (var i in recVideo.get('cacheList')) {
list.add(i); // list.add(i);
} // }
videoList.value = list; // videoList.value = list;
} // }
} }
// 获取推荐 // 获取推荐
Future queryRcmdFeed(type) async { Future queryRcmdFeed(type) async {
var res = await VideoHttp.rcmdVideoList( if (type == 'onRefresh') {
_currentPage = 0;
}
var res = await VideoHttp.rcmdVideoListApp(
ps: count, ps: count,
freshIdx: _currentPage, freshIdx: _currentPage,
); );
@ -47,7 +51,7 @@ class RcmdController extends GetxController {
} else if (type == 'onLoad') { } else if (type == 'onLoad') {
videoList.addAll(res['data']); videoList.addAll(res['data']);
} }
recVideo.put('cacheList', res['data']); // recVideo.put('cacheList', res['data']);
_currentPage += 1; _currentPage += 1;
} }
isLoadingMore = false; isLoadingMore = false;

View File

@ -63,6 +63,8 @@ class UserBoxKey {
static const String userMid = 'userMid'; static const String userMid = 'userMid';
// 登录状态 // 登录状态
static const String userLogin = 'userLogin'; static const String userLogin = 'userLogin';
// 凭证
static const String accessKey = 'accessKey';
} }
class SettingBoxKey { class SettingBoxKey {