mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
mod: app端推荐参数补充,统一部分代码位置
This commit is contained in:
@@ -18,6 +18,13 @@ class Constants {
|
|||||||
static const String thirdApi =
|
static const String thirdApi =
|
||||||
'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png';
|
'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png';
|
||||||
|
|
||||||
|
static const String traceId =
|
||||||
|
'11111111111111111111111111111111:1111111111111111:0:0';
|
||||||
|
static const String userAgent =
|
||||||
|
'Mozilla/5.0 BiliDroid/1.46.2 (bbcallen@gmail.com) os/android model/vivo mobi_app/android_hd build/1462100 channel/yingyongbao innerVer/1462100 osVer/14 network/2';
|
||||||
|
static const String statistics = '%7B%22appId%22%3A5%2C%22platform%22%3A3%2C%22version%22%3A%221.46.2%22%2C%22abtest%22%3A%22%22%7D';
|
||||||
|
//Uri.encodeComponent('{"appId": 5,"platform": 3,"version": "1.46.2","abtest": ""}');
|
||||||
|
|
||||||
//内容来自 https://passport.bilibili.com/web/generic/country/list
|
//内容来自 https://passport.bilibili.com/web/generic/country/list
|
||||||
static const List<Map<String, dynamic>> internationalDialingPrefix = [
|
static const List<Map<String, dynamic>> internationalDialingPrefix = [
|
||||||
{"id": 1, "cname": "中国大陆", "country_id": "86"},
|
{"id": 1, "cname": "中国大陆", "country_id": "86"},
|
||||||
|
|||||||
@@ -187,8 +187,8 @@ class VideoCardV extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
if (videoItem.goto == 'av')
|
if (videoItem.goto == 'av')
|
||||||
Positioned(
|
Positioned(
|
||||||
right: 0,
|
right: -5,
|
||||||
bottom: 0,
|
bottom: -2,
|
||||||
child: VideoPopupMenu(
|
child: VideoPopupMenu(
|
||||||
size: 29,
|
size: 29,
|
||||||
iconSize: 17,
|
iconSize: 17,
|
||||||
@@ -239,10 +239,9 @@ class VideoContent extends StatelessWidget {
|
|||||||
fs: 9,
|
fs: 9,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
if (videoItem.rcmdReason != null &&
|
if (videoItem.rcmdReason != null) ...[
|
||||||
videoItem.rcmdReason.content != '') ...[
|
|
||||||
PBadge(
|
PBadge(
|
||||||
text: videoItem.rcmdReason.content,
|
text: videoItem.rcmdReason,
|
||||||
stack: 'normal',
|
stack: 'normal',
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'color',
|
type: 'color',
|
||||||
@@ -280,7 +279,7 @@ class VideoContent extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (videoItem.goto == 'av') const SizedBox(width: 24)
|
if (videoItem.goto == 'av') const SizedBox(width: 10)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -307,7 +306,7 @@ class VideoStat extends StatelessWidget {
|
|||||||
view: videoItem.stat.view,
|
view: videoItem.stat.view,
|
||||||
goto: videoItem.goto,
|
goto: videoItem.goto,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 6),
|
||||||
if (videoItem.goto != 'picture')
|
if (videoItem.goto != 'picture')
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
@@ -315,16 +314,23 @@ class VideoStat extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
if (videoItem is RecVideoItemModel) ...<Widget>[
|
if (videoItem is RecVideoItemModel) ...<Widget>[
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
RichText(
|
Expanded(
|
||||||
maxLines: 1,
|
flex: 0,
|
||||||
text: TextSpan(
|
child: RichText(
|
||||||
style: TextStyle(
|
maxLines: 1,
|
||||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
text: TextSpan(
|
||||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
style: TextStyle(
|
||||||
),
|
fontSize:
|
||||||
text: Utils.formatTimestampToRelativeTime(videoItem.pubdate)),
|
Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||||
),
|
color: Theme.of(context)
|
||||||
const SizedBox(width: 4),
|
.colorScheme
|
||||||
|
.outline
|
||||||
|
.withOpacity(0.8),
|
||||||
|
),
|
||||||
|
text:
|
||||||
|
Utils.formatTimestampToRelativeTime(videoItem.pubdate)),
|
||||||
|
)),
|
||||||
|
const SizedBox(width: 2),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,19 +5,27 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:encrypt/encrypt.dart';
|
import 'package:encrypt/encrypt.dart';
|
||||||
import '../common/constants.dart';
|
import '../common/constants.dart';
|
||||||
import '../models/login/index.dart';
|
import '../models/login/index.dart';
|
||||||
|
import '../utils/login.dart';
|
||||||
import '../utils/utils.dart';
|
import '../utils/utils.dart';
|
||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class LoginHttp {
|
class LoginHttp {
|
||||||
static String deviceId = genDeviceId();
|
static String deviceId = LoginUtils.genDeviceId();
|
||||||
static String buvid = genBuvid();
|
static String buvid = LoginUtils.buvid();
|
||||||
static String host = 'passport.bilibili.com';
|
static String host = 'passport.bilibili.com';
|
||||||
static String traceId =
|
static Map<String, String> headers = {
|
||||||
'11111111111111111111111111111111:1111111111111111:0:0';
|
'Host': host,
|
||||||
static String statistics = Uri.encodeComponent(
|
'buvid': buvid,
|
||||||
'{"appId": 5,"platform": 3,"version": "1.46.2","abtest": ""}');
|
'env': 'prod',
|
||||||
static String userAgent =
|
'app-key': 'android_hd',
|
||||||
'Mozilla/5.0 BiliDroid/1.46.2 (bbcallen@gmail.com) os/android model/vivo mobi_app/android_hd build/1462100 channel/yingyongbao innerVer/1462100 osVer/14 network/2';
|
'user-agent': Constants.userAgent,
|
||||||
|
'x-bili-trace-id': Constants.traceId,
|
||||||
|
'x-bili-aurora-eid': '',
|
||||||
|
'x-bili-aurora-zone': '',
|
||||||
|
'bili-http-engine': 'cronet',
|
||||||
|
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
||||||
|
};
|
||||||
|
|
||||||
static Future<Map<String, dynamic>> getHDcode() async {
|
static Future<Map<String, dynamic>> getHDcode() async {
|
||||||
var params = {
|
var params = {
|
||||||
'appkey': Constants.appKey,
|
'appkey': Constants.appKey,
|
||||||
@@ -117,7 +125,7 @@ class LoginHttp {
|
|||||||
'platform': 'android',
|
'platform': 'android',
|
||||||
if (recaptcha_token != null) 'recaptcha_token': recaptcha_token,
|
if (recaptcha_token != null) 'recaptcha_token': recaptcha_token,
|
||||||
's_locale': 'zh_CN',
|
's_locale': 'zh_CN',
|
||||||
'statistics': statistics,
|
'statistics': Constants.statistics,
|
||||||
'tel': tel,
|
'tel': tel,
|
||||||
'ts': (timestamp ~/ 1000).toString(),
|
'ts': (timestamp ~/ 1000).toString(),
|
||||||
};
|
};
|
||||||
@@ -126,18 +134,6 @@ class LoginHttp {
|
|||||||
Constants.appKey,
|
Constants.appKey,
|
||||||
Constants.appSec,
|
Constants.appSec,
|
||||||
);
|
);
|
||||||
var headers = {
|
|
||||||
'Host': host,
|
|
||||||
'buvid': buvid,
|
|
||||||
'env': 'prod',
|
|
||||||
'app-key': 'android_hd',
|
|
||||||
'user-agent': userAgent,
|
|
||||||
'x-bili-trace-id': traceId,
|
|
||||||
'x-bili-aurora-eid': '',
|
|
||||||
'x-bili-aurora-zone': '',
|
|
||||||
'bili-http-engine': 'cronet',
|
|
||||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
};
|
|
||||||
|
|
||||||
var res = await Request().post(
|
var res = await Request().post(
|
||||||
Api.appSmsCode,
|
Api.appSmsCode,
|
||||||
@@ -177,7 +173,7 @@ class LoginHttp {
|
|||||||
// 'mobi_app': 'android_hd',
|
// 'mobi_app': 'android_hd',
|
||||||
// 'platform': 'android',
|
// 'platform': 'android',
|
||||||
// 's_locale': 'zh_CN',
|
// 's_locale': 'zh_CN',
|
||||||
// 'statistics': statistics,
|
// 'statistics': Constants.statistics,
|
||||||
// 'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
// 'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
||||||
// };
|
// };
|
||||||
// String sign = Utils.appSign(
|
// String sign = Utils.appSign(
|
||||||
@@ -185,18 +181,6 @@ class LoginHttp {
|
|||||||
// Constants.appKey,
|
// Constants.appKey,
|
||||||
// Constants.appSec,
|
// Constants.appSec,
|
||||||
// );
|
// );
|
||||||
// var headers = {
|
|
||||||
// 'Host': host,
|
|
||||||
// 'buvid': buvid,
|
|
||||||
// 'env': 'prod',
|
|
||||||
// 'app-key': 'android_hd',
|
|
||||||
// 'user-agent': userAgent,
|
|
||||||
// 'x-bili-trace-id': traceId,
|
|
||||||
// 'x-bili-aurora-eid': '',
|
|
||||||
// 'x-bili-aurora-zone': '',
|
|
||||||
// 'bili-http-engine': 'cronet',
|
|
||||||
// 'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
// };
|
|
||||||
// var res = await Request().post(Api.getGuestId,
|
// var res = await Request().post(Api.getGuestId,
|
||||||
// queryParameters: {...params, 'sign': sign},
|
// queryParameters: {...params, 'sign': sign},
|
||||||
// options: Options(
|
// options: Options(
|
||||||
@@ -211,59 +195,6 @@ class LoginHttp {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
static String genBuvid() {
|
|
||||||
var mac = <String>[];
|
|
||||||
var random = Random();
|
|
||||||
|
|
||||||
for (var i = 0; i < 6; i++) {
|
|
||||||
var min = 0;
|
|
||||||
var max = 0xff;
|
|
||||||
var num = (random.nextInt(max - min + 1) + min).toRadixString(16);
|
|
||||||
mac.add(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
var md5Str = md5.convert(utf8.encode(mac.join(':'))).toString();
|
|
||||||
var md5Arr = md5Str.split('');
|
|
||||||
return 'XY${md5Arr[2]}${md5Arr[12]}${md5Arr[22]}$md5Str';
|
|
||||||
}
|
|
||||||
|
|
||||||
static String genDeviceId() {
|
|
||||||
// https://github.com/bilive/bilive_client/blob/2873de0532c54832f5464a4c57325ad9af8b8698/bilive/lib/app_client.ts#L62
|
|
||||||
final String yyyyMMddHHmmss = DateTime.now()
|
|
||||||
.toIso8601String()
|
|
||||||
.replaceAll(RegExp(r'[-:TZ]'), '')
|
|
||||||
.substring(0, 14);
|
|
||||||
|
|
||||||
final Random random = Random(); // Random.secure();
|
|
||||||
final String randomHex32 =
|
|
||||||
List.generate(32, (index) => random.nextInt(16).toRadixString(16))
|
|
||||||
.join();
|
|
||||||
final String randomHex16 =
|
|
||||||
List.generate(16, (index) => random.nextInt(16).toRadixString(16))
|
|
||||||
.join();
|
|
||||||
|
|
||||||
final String deviceID = randomHex32 + yyyyMMddHHmmss + randomHex16;
|
|
||||||
|
|
||||||
final List<int> bytes = RegExp(r'\w{2}')
|
|
||||||
.allMatches(deviceID)
|
|
||||||
.map((match) => int.parse(match.group(0)!, radix: 16))
|
|
||||||
.toList();
|
|
||||||
final int checksumValue = bytes.reduce((a, b) => a + b);
|
|
||||||
final String check = checksumValue
|
|
||||||
.toRadixString(16)
|
|
||||||
.substring(checksumValue.toRadixString(16).length - 2);
|
|
||||||
|
|
||||||
return deviceID + check;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String generateRandomString(int length) {
|
|
||||||
const chars =
|
|
||||||
'123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
||||||
final Random random = Random(); // Random.secure();
|
|
||||||
return List.generate(length, (index) => chars[random.nextInt(chars.length)])
|
|
||||||
.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
// app端密码登录
|
// app端密码登录
|
||||||
static Future loginByPwd({
|
static Future loginByPwd({
|
||||||
required String username,
|
required String username,
|
||||||
@@ -294,7 +225,7 @@ class LoginHttp {
|
|||||||
'device_platform': 'Android14vivo',
|
'device_platform': 'Android14vivo',
|
||||||
'disable_rcmd': '0',
|
'disable_rcmd': '0',
|
||||||
'dt': Uri.encodeComponent(Encrypter(RSA(publicKey: publicKey))
|
'dt': Uri.encodeComponent(Encrypter(RSA(publicKey: publicKey))
|
||||||
.encrypt(generateRandomString(16))
|
.encrypt(LoginUtils.generateRandomString(16))
|
||||||
.base64),
|
.base64),
|
||||||
'from_pv': 'main.homepage.avatar-nologin.all.click',
|
'from_pv': 'main.homepage.avatar-nologin.all.click',
|
||||||
'from_url': Uri.encodeComponent('bilibili://pegasus/promo'),
|
'from_url': Uri.encodeComponent('bilibili://pegasus/promo'),
|
||||||
@@ -308,7 +239,7 @@ class LoginHttp {
|
|||||||
'platform': 'android',
|
'platform': 'android',
|
||||||
if (recaptcha_token != null) 'recaptcha_token': recaptcha_token,
|
if (recaptcha_token != null) 'recaptcha_token': recaptcha_token,
|
||||||
's_locale': 'zh_CN',
|
's_locale': 'zh_CN',
|
||||||
'statistics': statistics,
|
'statistics': Constants.statistics,
|
||||||
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
||||||
'username': username,
|
'username': username,
|
||||||
};
|
};
|
||||||
@@ -322,18 +253,6 @@ class LoginHttp {
|
|||||||
print('$key: $value');
|
print('$key: $value');
|
||||||
return MapEntry<String, dynamic>(key, value);
|
return MapEntry<String, dynamic>(key, value);
|
||||||
});
|
});
|
||||||
final Map<String, String> headers = {
|
|
||||||
'Host': host,
|
|
||||||
'buvid': buvid,
|
|
||||||
'env': 'prod',
|
|
||||||
'app-key': 'android_hd',
|
|
||||||
'user-agent': userAgent,
|
|
||||||
'x-bili-trace-id': traceId,
|
|
||||||
'x-bili-aurora-eid': '',
|
|
||||||
'x-bili-aurora-zone': '',
|
|
||||||
'bili-http-engine': 'cronet',
|
|
||||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
};
|
|
||||||
var res = await Request().post(
|
var res = await Request().post(
|
||||||
Api.loginByPwdApi,
|
Api.loginByPwdApi,
|
||||||
data: data,
|
data: data,
|
||||||
@@ -345,7 +264,11 @@ class LoginHttp {
|
|||||||
);
|
);
|
||||||
print(res);
|
print(res);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {'status': true, 'data': res.data['data']};
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
'status': false,
|
'status': false,
|
||||||
@@ -383,7 +306,7 @@ class LoginHttp {
|
|||||||
// 'device_tourist_id': '',
|
// 'device_tourist_id': '',
|
||||||
'disable_rcmd': '0',
|
'disable_rcmd': '0',
|
||||||
'dt': Uri.encodeComponent(Encrypter(RSA(publicKey: publicKey))
|
'dt': Uri.encodeComponent(Encrypter(RSA(publicKey: publicKey))
|
||||||
.encrypt(generateRandomString(16))
|
.encrypt(LoginUtils.generateRandomString(16))
|
||||||
.base64),
|
.base64),
|
||||||
'from_pv': 'main.my-information.my-login.0.click',
|
'from_pv': 'main.my-information.my-login.0.click',
|
||||||
'from_url': Uri.encodeComponent('bilibili://user_center/mine'),
|
'from_url': Uri.encodeComponent('bilibili://user_center/mine'),
|
||||||
@@ -391,7 +314,7 @@ class LoginHttp {
|
|||||||
'mobi_app': 'android_hd',
|
'mobi_app': 'android_hd',
|
||||||
'platform': 'android',
|
'platform': 'android',
|
||||||
's_locale': 'zh_CN',
|
's_locale': 'zh_CN',
|
||||||
'statistics': statistics,
|
'statistics': Constants.statistics,
|
||||||
'tel': tel,
|
'tel': tel,
|
||||||
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
||||||
};
|
};
|
||||||
@@ -405,18 +328,6 @@ class LoginHttp {
|
|||||||
print('$key: $value');
|
print('$key: $value');
|
||||||
return MapEntry<String, dynamic>(key, value);
|
return MapEntry<String, dynamic>(key, value);
|
||||||
});
|
});
|
||||||
final Map<String, String> headers = {
|
|
||||||
'Host': host,
|
|
||||||
'buvid': buvid,
|
|
||||||
'env': 'prod',
|
|
||||||
'app-key': 'android_hd',
|
|
||||||
'user-agent': userAgent,
|
|
||||||
'x-bili-trace-id': traceId,
|
|
||||||
'x-bili-aurora-eid': '',
|
|
||||||
'x-bili-aurora-zone': '',
|
|
||||||
'bili-http-engine': 'cronet',
|
|
||||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
};
|
|
||||||
var res = await Request().post(
|
var res = await Request().post(
|
||||||
Api.logInByAppSms,
|
Api.logInByAppSms,
|
||||||
data: data,
|
data: data,
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/cupertino.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:hive/hive.dart';
|
||||||
import '../common/constants.dart';
|
import '../common/constants.dart';
|
||||||
@@ -13,10 +15,12 @@ import '../models/video_detail_res.dart';
|
|||||||
import '../utils/id_utils.dart';
|
import '../utils/id_utils.dart';
|
||||||
import '../utils/recommend_filter.dart';
|
import '../utils/recommend_filter.dart';
|
||||||
import '../utils/storage.dart';
|
import '../utils/storage.dart';
|
||||||
|
import '../utils/utils.dart';
|
||||||
import '../utils/wbi_sign.dart';
|
import '../utils/wbi_sign.dart';
|
||||||
import '../pages/mine/controller.dart';
|
import '../pages/mine/controller.dart';
|
||||||
import 'api.dart';
|
import 'api.dart';
|
||||||
import 'init.dart';
|
import 'init.dart';
|
||||||
|
import 'login.dart';
|
||||||
|
|
||||||
/// res.data['code'] == 0 请求正常返回结果
|
/// res.data['code'] == 0 请求正常返回结果
|
||||||
/// res.data['data'] 为结果
|
/// res.data['data'] 为结果
|
||||||
@@ -31,91 +35,130 @@ class VideoHttp {
|
|||||||
|
|
||||||
// 首页推荐视频
|
// 首页推荐视频
|
||||||
static Future rcmdVideoList({required int ps, required int freshIdx}) async {
|
static Future rcmdVideoList({required int ps, required int freshIdx}) async {
|
||||||
try {
|
var res = await Request().get(
|
||||||
var res = await Request().get(
|
Api.recommendListWeb,
|
||||||
Api.recommendListWeb,
|
data: {
|
||||||
data: {
|
'version': 1,
|
||||||
'version': 1,
|
'feed_version': 'V8',
|
||||||
'feed_version': 'V8',
|
'homepage_ver': 1,
|
||||||
'homepage_ver': 1,
|
'ps': ps,
|
||||||
'ps': ps,
|
'fresh_idx': freshIdx,
|
||||||
'fresh_idx': freshIdx,
|
'brush': freshIdx,
|
||||||
'brush': freshIdx,
|
'fresh_type': 4
|
||||||
'fresh_type': 4
|
},
|
||||||
},
|
);
|
||||||
);
|
if (res.data['code'] == 0) {
|
||||||
if (res.data['code'] == 0) {
|
List<RecVideoItemModel> list = [];
|
||||||
List<RecVideoItemModel> list = [];
|
List<int> blackMidsList = localCache
|
||||||
List<int> blackMidsList = localCache
|
.get(LocalCacheKey.blackMidsList, defaultValue: [-1])
|
||||||
.get(LocalCacheKey.blackMidsList, defaultValue: [-1])
|
.map<int>((e) => e as int)
|
||||||
.map<int>((e) => e as int)
|
.toList();
|
||||||
.toList();
|
for (var i in res.data['data']['item']) {
|
||||||
for (var i in res.data['data']['item']) {
|
//过滤掉live与ad,以及拉黑用户
|
||||||
//过滤掉live与ad,以及拉黑用户
|
if (i['goto'] == 'av' &&
|
||||||
if (i['goto'] == 'av' &&
|
(i['owner'] != null &&
|
||||||
(i['owner'] != null &&
|
!blackMidsList.contains(i['owner']['mid']))) {
|
||||||
!blackMidsList.contains(i['owner']['mid']))) {
|
RecVideoItemModel videoItem = RecVideoItemModel.fromJson(i);
|
||||||
RecVideoItemModel videoItem = RecVideoItemModel.fromJson(i);
|
if (!RecommendFilter.filter(videoItem)) {
|
||||||
if (!RecommendFilter.filter(videoItem)) {
|
list.add(videoItem);
|
||||||
list.add(videoItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {'status': true, 'data': list};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'data': [], 'msg': res.data['message']};
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
return {'status': true, 'data': list};
|
||||||
return {'status': false, 'data': [], 'msg': err.toString()};
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加额外的loginState变量模拟未登录状态
|
// 添加额外的loginState变量模拟未登录状态
|
||||||
static Future rcmdVideoListApp(
|
static Future rcmdVideoListApp(
|
||||||
{bool loginStatus = true, required int freshIdx}) async {
|
{bool loginStatus = true, required int freshIdx}) async {
|
||||||
try {
|
var data = {
|
||||||
var res = await Request().get(
|
'access_key': loginStatus
|
||||||
Api.recommendListApp,
|
? (localCache
|
||||||
data: {
|
.get(LocalCacheKey.accessKey, defaultValue: {})['value'] ??
|
||||||
'idx': freshIdx,
|
'')
|
||||||
'flush': '5',
|
: '',
|
||||||
'column': '4',
|
'appkey': Constants.appKey,
|
||||||
'device': 'pad',
|
'build': '1462100',
|
||||||
'device_type': 0,
|
'c_locale': 'zh_CN',
|
||||||
'device_name': 'vivo',
|
'channel': 'yingyongbao',
|
||||||
'pull': freshIdx == 0 ? 'true' : 'false',
|
'column': '4',
|
||||||
'appkey': Constants.appKey,
|
'device': 'pad',
|
||||||
'access_key': loginStatus
|
'device_name': 'vivo',
|
||||||
? (localCache.get(LocalCacheKey.accessKey,
|
'device_type': '0',
|
||||||
defaultValue: {})['value'] ??
|
'disable_rcmd': '0',
|
||||||
'')
|
'flush': '5',
|
||||||
: ''
|
'fnval': '976',
|
||||||
},
|
'fnver': '0',
|
||||||
);
|
'force_host': '2', //使用https
|
||||||
if (res.data['code'] == 0) {
|
'fourk': '1',
|
||||||
List<RecVideoItemAppModel> list = [];
|
'guidance': '0',
|
||||||
List<int> blackMidsList = localCache
|
'https_url_req': '0',
|
||||||
.get(LocalCacheKey.blackMidsList, defaultValue: [-1])
|
'idx': freshIdx.toString(),
|
||||||
.map<int>((e) => e as int)
|
'mobi_app': 'android_hd',
|
||||||
.toList();
|
'network': 'wifi',
|
||||||
for (var i in res.data['data']['items']) {
|
'platform': 'android',
|
||||||
// 屏蔽推广和拉黑用户
|
'player_net': '1',
|
||||||
if (i['card_goto'] != 'ad_av' &&
|
'pull': freshIdx == 0 ? 'true' : 'false',
|
||||||
(!enableRcmdDynamic ? i['card_goto'] != 'picture' : true) &&
|
'qn': '32',
|
||||||
(i['args'] != null &&
|
'recsys_mode': '0',
|
||||||
!blackMidsList.contains(i['args']['up_mid']))) {
|
's_locale': 'zh_CN',
|
||||||
RecVideoItemAppModel videoItem = RecVideoItemAppModel.fromJson(i);
|
'splash_id': '',
|
||||||
if (!RecommendFilter.filter(videoItem)) {
|
'statistics': Constants.statistics,
|
||||||
list.add(videoItem);
|
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
||||||
}
|
'voice_balance': '0'
|
||||||
|
};
|
||||||
|
String sign = Utils.appSign(
|
||||||
|
data,
|
||||||
|
Constants.appKey,
|
||||||
|
Constants.appSec,
|
||||||
|
);
|
||||||
|
data['sign'] = sign;
|
||||||
|
|
||||||
|
var res = await Request().get(
|
||||||
|
Api.recommendListApp,
|
||||||
|
data: data,
|
||||||
|
options: Options(headers: {
|
||||||
|
'Host': 'app.bilibili.com',
|
||||||
|
'buvid': LoginHttp.buvid,
|
||||||
|
'fp_local':
|
||||||
|
'1111111111111111111111111111111111111111111111111111111111111111',
|
||||||
|
'fp_remote':
|
||||||
|
'1111111111111111111111111111111111111111111111111111111111111111',
|
||||||
|
'session_id': '11111111',
|
||||||
|
'env': 'prod',
|
||||||
|
'app-key': 'android_hd',
|
||||||
|
'User-Agent': Constants.userAgent,
|
||||||
|
'x-bili-trace-id': Constants.traceId,
|
||||||
|
'x-bili-aurora-eid': '',
|
||||||
|
'x-bili-aurora-zone': '',
|
||||||
|
'bili-http-engine': 'cronet',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
List<RecVideoItemAppModel> list = [];
|
||||||
|
List<int> blackMidsList = localCache
|
||||||
|
.get(LocalCacheKey.blackMidsList, defaultValue: [-1])
|
||||||
|
.map<int>((e) => e as int)
|
||||||
|
.toList();
|
||||||
|
for (var i in res.data['data']['items']) {
|
||||||
|
// 屏蔽推广和拉黑用户
|
||||||
|
if (i['card_goto'] != 'ad_av' &&
|
||||||
|
i['card_goto'] != 'ad_web_s' &&
|
||||||
|
i['ad_info'] == null &&
|
||||||
|
(!enableRcmdDynamic ? i['card_goto'] != 'picture' : true) &&
|
||||||
|
(i['args'] != null &&
|
||||||
|
!blackMidsList.contains(i['args']['up_id']))) {
|
||||||
|
RecVideoItemAppModel videoItem = RecVideoItemAppModel.fromJson(i);
|
||||||
|
if (!RecommendFilter.filter(videoItem)) {
|
||||||
|
list.add(videoItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {'status': true, 'data': list};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'data': [], 'msg': res.data['message']};
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
return {'status': true, 'data': list};
|
||||||
return {'status': false, 'data': [], 'msg': err.toString()};
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class RecVideoItemAppModel {
|
|||||||
String? title;
|
String? title;
|
||||||
int? isFollowed;
|
int? isFollowed;
|
||||||
RcmdOwner? owner;
|
RcmdOwner? owner;
|
||||||
RcmdReason? rcmdReason;
|
String? rcmdReason;
|
||||||
String? goto;
|
String? goto;
|
||||||
int? param;
|
int? param;
|
||||||
String? uri;
|
String? uri;
|
||||||
@@ -66,14 +66,10 @@ class RecVideoItemAppModel {
|
|||||||
//duration = json['cover_right_text'];
|
//duration = json['cover_right_text'];
|
||||||
title = json['title'];
|
title = json['title'];
|
||||||
owner = RcmdOwner.fromJson(json);
|
owner = RcmdOwner.fromJson(json);
|
||||||
rcmdReason = json['rcmd_reason_style'] != null
|
rcmdReason = json['bottom_rcmd_reason'] ?? json['top_rcmd_reason'];
|
||||||
? RcmdReason.fromJson(json['rcmd_reason_style'])
|
|
||||||
: null;
|
|
||||||
// 由于app端api并不会直接返回与owner的关注状态
|
// 由于app端api并不会直接返回与owner的关注状态
|
||||||
// 所以借用推荐原因是否为“已关注”、“新关注”判别关注状态,从而与web端接口等效
|
// 所以借用推荐原因是否为“已关注”、“新关注”判别关注状态,从而与web端接口等效
|
||||||
String rcmdReasonContent = rcmdReason?.content ?? '';
|
isFollowed = (rcmdReason == '已关注') || (rcmdReason == '新关注') ? 1 : 0;
|
||||||
isFollowed =
|
|
||||||
(rcmdReasonContent == '已关注') || (rcmdReasonContent == '新关注') ? 1 : 0;
|
|
||||||
// 如果是,就无需再显示推荐原因,交由view统一处理即可
|
// 如果是,就无需再显示推荐原因,交由view统一处理即可
|
||||||
if (isFollowed == 1) {
|
if (isFollowed == 1) {
|
||||||
rcmdReason = null;
|
rcmdReason = null;
|
||||||
@@ -86,7 +82,7 @@ class RecVideoItemAppModel {
|
|||||||
if (json['goto'] == 'bangumi') {
|
if (json['goto'] == 'bangumi') {
|
||||||
bangumiView = json['cover_left_text_1'];
|
bangumiView = json['cover_left_text_1'];
|
||||||
bangumiFollow = json['cover_left_text_2'];
|
bangumiFollow = json['cover_left_text_2'];
|
||||||
bangumiBadge = json['badge'];
|
bangumiBadge = json['cover_right_text'];
|
||||||
}
|
}
|
||||||
|
|
||||||
cardType = json['card_type'];
|
cardType = json['card_type'];
|
||||||
@@ -129,18 +125,6 @@ class RcmdOwner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RcmdReason {
|
|
||||||
RcmdReason({
|
|
||||||
this.content,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? content;
|
|
||||||
|
|
||||||
RcmdReason.fromJson(Map<String, dynamic> json) {
|
|
||||||
content = json["text"] ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ThreePoint {
|
class ThreePoint {
|
||||||
ThreePoint({
|
ThreePoint({
|
||||||
this.dislikeReasons,
|
this.dislikeReasons,
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class RecVideoItemModel {
|
|||||||
@HiveField(11)
|
@HiveField(11)
|
||||||
int? isFollowed;
|
int? isFollowed;
|
||||||
@HiveField(12)
|
@HiveField(12)
|
||||||
RcmdReason? rcmdReason;
|
String? rcmdReason;
|
||||||
|
|
||||||
RecVideoItemModel.fromJson(Map<String, dynamic> json) {
|
RecVideoItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
id = json["id"];
|
id = json["id"];
|
||||||
@@ -61,9 +61,10 @@ class RecVideoItemModel {
|
|||||||
owner = Owner.fromJson(json["owner"]);
|
owner = Owner.fromJson(json["owner"]);
|
||||||
stat = Stat.fromJson(json["stat"]);
|
stat = Stat.fromJson(json["stat"]);
|
||||||
isFollowed = json["is_followed"] ?? 0;
|
isFollowed = json["is_followed"] ?? 0;
|
||||||
rcmdReason = json["rcmd_reason"] != null
|
// rcmdReason = json["rcmd_reason"] != null
|
||||||
? RcmdReason.fromJson(json["rcmd_reason"])
|
// ? RcmdReason.fromJson(json["rcmd_reason"])
|
||||||
: RcmdReason(content: '');
|
// : RcmdReason(content: '');
|
||||||
|
rcmdReason = json["rcmd_reason"]?['content'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,19 +90,19 @@ class Stat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiveType(typeId: 2)
|
// @HiveType(typeId: 2)
|
||||||
class RcmdReason {
|
// class RcmdReason {
|
||||||
RcmdReason({
|
// RcmdReason({
|
||||||
this.reasonType,
|
// this.reasonType,
|
||||||
this.content,
|
// this.content,
|
||||||
});
|
// });
|
||||||
@HiveField(0)
|
// @HiveField(0)
|
||||||
int? reasonType;
|
// int? reasonType;
|
||||||
@HiveField(1)
|
// @HiveField(1)
|
||||||
String? content = '';
|
// String? content = '';
|
||||||
|
//
|
||||||
RcmdReason.fromJson(Map<String, dynamic> json) {
|
// RcmdReason.fromJson(Map<String, dynamic> json) {
|
||||||
reasonType = json["reason_type"];
|
// reasonType = json["reason_type"];
|
||||||
content = json["content"] ?? '';
|
// content = json["content"] ?? '';
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class RecVideoItemModelAdapter extends TypeAdapter<RecVideoItemModel> {
|
|||||||
owner: fields[9] as Owner?,
|
owner: fields[9] as Owner?,
|
||||||
stat: fields[10] as Stat?,
|
stat: fields[10] as Stat?,
|
||||||
isFollowed: fields[11] as int?,
|
isFollowed: fields[11] as int?,
|
||||||
rcmdReason: fields[12] as RcmdReason?,
|
rcmdReason: fields[12] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,40 +115,40 @@ class StatAdapter extends TypeAdapter<Stat> {
|
|||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
typeId == other.typeId;
|
typeId == other.typeId;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
class RcmdReasonAdapter extends TypeAdapter<RcmdReason> {
|
// class RcmdReasonAdapter extends TypeAdapter<RcmdReason> {
|
||||||
@override
|
// @override
|
||||||
final int typeId = 2;
|
// final int typeId = 2;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
RcmdReason read(BinaryReader reader) {
|
// RcmdReason read(BinaryReader reader) {
|
||||||
final numOfFields = reader.readByte();
|
// final numOfFields = reader.readByte();
|
||||||
final fields = <int, dynamic>{
|
// final fields = <int, dynamic>{
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
// for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
};
|
// };
|
||||||
return RcmdReason(
|
// return RcmdReason(
|
||||||
reasonType: fields[0] as int?,
|
// reasonType: fields[0] as int?,
|
||||||
content: fields[1] as String?,
|
// content: fields[1] as String?,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
void write(BinaryWriter writer, RcmdReason obj) {
|
// void write(BinaryWriter writer, RcmdReason obj) {
|
||||||
writer
|
// writer
|
||||||
..writeByte(2)
|
// ..writeByte(2)
|
||||||
..writeByte(0)
|
// ..writeByte(0)
|
||||||
..write(obj.reasonType)
|
// ..write(obj.reasonType)
|
||||||
..writeByte(1)
|
// ..writeByte(1)
|
||||||
..write(obj.content);
|
// ..write(obj.content);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
int get hashCode => typeId.hashCode;
|
// int get hashCode => typeId.hashCode;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
bool operator ==(Object other) =>
|
// bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
// identical(this, other) ||
|
||||||
other is RcmdReasonAdapter &&
|
// other is RcmdReasonAdapter &&
|
||||||
runtimeType == other.runtimeType &&
|
// runtimeType == other.runtimeType &&
|
||||||
typeId == other.typeId;
|
// typeId == other.typeId;
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:PiliPalaX/http/video.dart';
|
import 'package:PiliPalaX/http/video.dart';
|
||||||
@@ -11,7 +12,6 @@ class RcmdController extends GetxController {
|
|||||||
int _currentPage = 0;
|
int _currentPage = 0;
|
||||||
// RxList<RecVideoItemAppModel> appVideoList = <RecVideoItemAppModel>[].obs;
|
// RxList<RecVideoItemAppModel> appVideoList = <RecVideoItemAppModel>[].obs;
|
||||||
// RxList<RecVideoItemModel> webVideoList = <RecVideoItemModel>[].obs;
|
// RxList<RecVideoItemModel> webVideoList = <RecVideoItemModel>[].obs;
|
||||||
bool isLoadingMore = true;
|
|
||||||
OverlayEntry? popupDialog;
|
OverlayEntry? popupDialog;
|
||||||
Box setting = GStorage.setting;
|
Box setting = GStorage.setting;
|
||||||
RxInt crossAxisCount = 2.obs;
|
RxInt crossAxisCount = 2.obs;
|
||||||
@@ -35,9 +35,6 @@ class RcmdController extends GetxController {
|
|||||||
|
|
||||||
// 获取推荐
|
// 获取推荐
|
||||||
Future queryRcmdFeed(type) async {
|
Future queryRcmdFeed(type) async {
|
||||||
if (isLoadingMore == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (type == 'onRefresh') {
|
if (type == 'onRefresh') {
|
||||||
_currentPage = 0;
|
_currentPage = 0;
|
||||||
}
|
}
|
||||||
@@ -75,17 +72,22 @@ class RcmdController extends GetxController {
|
|||||||
_currentPage += 1;
|
_currentPage += 1;
|
||||||
// 若videoList数量太小,可能会影响翻页,此时再次请求
|
// 若videoList数量太小,可能会影响翻页,此时再次请求
|
||||||
// 为避免请求到的数据太少时还在反复请求,要求本次返回数据大于1条才触发
|
// 为避免请求到的数据太少时还在反复请求,要求本次返回数据大于1条才触发
|
||||||
if (res['data'].length > 1 && videoList.length < 22) {
|
if (res['data'].length > 1 && videoList.length < 24) {
|
||||||
queryRcmdFeed('onLoad');
|
Future.delayed(const Duration(milliseconds: 300), () {
|
||||||
|
if (videoList.length < 24) queryRcmdFeed('onLoad');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
if (res['data'].length < 5) {
|
||||||
|
SmartDialog.showToast("仅请求到${res['data'].length}条");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast("${res['msg']},请尝试(重新)登录");
|
||||||
}
|
}
|
||||||
isLoadingMore = false;
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下拉刷新
|
// 下拉刷新
|
||||||
Future onRefresh() async {
|
Future onRefresh() async {
|
||||||
isLoadingMore = true;
|
|
||||||
queryRcmdFeed('onRefresh');
|
queryRcmdFeed('onRefresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ class _RcmdPageState extends State<RcmdPage>
|
|||||||
scrollController.position.maxScrollExtent - 200) {
|
scrollController.position.maxScrollExtent - 200) {
|
||||||
EasyThrottle.throttle(
|
EasyThrottle.throttle(
|
||||||
'my-throttler', const Duration(milliseconds: 200), () {
|
'my-throttler', const Duration(milliseconds: 200), () {
|
||||||
_rcmdController.isLoadingMore = true;
|
|
||||||
_rcmdController.onLoad();
|
_rcmdController.onLoad();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -99,23 +98,17 @@ class _RcmdPageState extends State<RcmdPage>
|
|||||||
Map data = snapshot.data as Map;
|
Map data = snapshot.data as Map;
|
||||||
if (data['status']) {
|
if (data['status']) {
|
||||||
return Obx(
|
return Obx(
|
||||||
() {
|
() => contentGrid(
|
||||||
if (_rcmdController.isLoadingMore &&
|
_rcmdController,
|
||||||
_rcmdController.videoList.isEmpty) {
|
_rcmdController.videoList.isEmpty
|
||||||
return contentGrid(_rcmdController, []);
|
? []
|
||||||
} else {
|
: _rcmdController.videoList),
|
||||||
// 显示视频列表
|
|
||||||
return contentGrid(
|
|
||||||
_rcmdController, _rcmdController.videoList);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return HttpError(
|
return HttpError(
|
||||||
errMsg: data == null ? "" : data['msg'],
|
errMsg: data == null ? "" : data['msg'],
|
||||||
fn: () {
|
fn: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_rcmdController.isLoadingMore = true;
|
|
||||||
_futureBuilderFuture =
|
_futureBuilderFuture =
|
||||||
_rcmdController.queryRcmdFeed('init');
|
_rcmdController.queryRcmdFeed('init');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,4 +57,41 @@ class LoginUtils {
|
|||||||
String uuid = getUUID() + getUUID();
|
String uuid = getUUID() + getUUID();
|
||||||
return 'XY${uuid.substring(0, 35).toUpperCase()}';
|
return 'XY${uuid.substring(0, 35).toUpperCase()}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String genDeviceId() {
|
||||||
|
// https://github.com/bilive/bilive_client/blob/2873de0532c54832f5464a4c57325ad9af8b8698/bilive/lib/app_client.ts#L62
|
||||||
|
final String yyyyMMddHHmmss = DateTime.now()
|
||||||
|
.toIso8601String()
|
||||||
|
.replaceAll(RegExp(r'[-:TZ]'), '')
|
||||||
|
.substring(0, 14);
|
||||||
|
|
||||||
|
final Random random = Random(); // Random.secure();
|
||||||
|
final String randomHex32 =
|
||||||
|
List.generate(32, (index) => random.nextInt(16).toRadixString(16))
|
||||||
|
.join();
|
||||||
|
final String randomHex16 =
|
||||||
|
List.generate(16, (index) => random.nextInt(16).toRadixString(16))
|
||||||
|
.join();
|
||||||
|
|
||||||
|
final String deviceID = randomHex32 + yyyyMMddHHmmss + randomHex16;
|
||||||
|
|
||||||
|
final List<int> bytes = RegExp(r'\w{2}')
|
||||||
|
.allMatches(deviceID)
|
||||||
|
.map((match) => int.parse(match.group(0)!, radix: 16))
|
||||||
|
.toList();
|
||||||
|
final int checksumValue = bytes.reduce((a, b) => a + b);
|
||||||
|
final String check = checksumValue
|
||||||
|
.toRadixString(16)
|
||||||
|
.substring(checksumValue.toRadixString(16).length - 2);
|
||||||
|
|
||||||
|
return deviceID + check;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String generateRandomString(int length) {
|
||||||
|
const chars =
|
||||||
|
'123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||||
|
final Random random = Random(); // Random.secure();
|
||||||
|
return List.generate(length, (index) => chars[random.nextInt(chars.length)])
|
||||||
|
.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ class Utils {
|
|||||||
if (!emptyStatCheck(videoItem.stat.danmu)) {
|
if (!emptyStatCheck(videoItem.stat.danmu)) {
|
||||||
semanticsLabel += ',${Utils.numFormat(videoItem.stat.danmu)}弹幕';
|
semanticsLabel += ',${Utils.numFormat(videoItem.stat.danmu)}弹幕';
|
||||||
}
|
}
|
||||||
if (videoItem.rcmdReason != null && videoItem.rcmdReason.content != '') {
|
if (videoItem.rcmdReason != null) {
|
||||||
semanticsLabel += ',${videoItem.rcmdReason.content}';
|
semanticsLabel += ',${videoItem.rcmdReason}';
|
||||||
}
|
}
|
||||||
if (!emptyStatCheck(videoItem.duration) &&
|
if (!emptyStatCheck(videoItem.duration) &&
|
||||||
(videoItem.duration is! int || videoItem.duration > 0)) {
|
(videoItem.duration is! int || videoItem.duration > 0)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user