feat: session secondary

Closes #837

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-09 21:32:16 +08:00
parent dea29054e6
commit a282baf5a2
25 changed files with 814 additions and 543 deletions

27
lib/grpc/dm.dart Normal file
View File

@@ -0,0 +1,27 @@
import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:fixnum/fixnum.dart';
class DmGrpc {
static Future<LoadingState<DmSegMobileReply>> dmSegMobile({
required int cid,
required int segmentIndex,
int type = 1,
}) async {
final res = await GrpcRepo.request(
GrpcUrl.dmSegMobile,
DmSegMobileReq(
oid: Int64(cid),
segmentIndex: Int64(segmentIndex),
type: type,
),
DmSegMobileReply.fromBuffer,
);
if (res['status']) {
return LoadingState.success(res['data']);
} else {
return const Error('');
}
}
}

29
lib/grpc/dyn.dart Normal file
View File

@@ -0,0 +1,29 @@
import 'package:PiliPlus/grpc/bilibili/app/dynamic/v1.pb.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
class DynGrpc {
// static Future dynSpace({
// required int uid,
// required int page,
// }) {
// return _request(
// GrpcUrl.dynSpace,
// DynSpaceReq(
// hostUid: Int64(uid),
// localTime: 8,
// page: Int64(page),
// from: 'space',
// ),
// DynSpaceRsp.fromBuffer,
// );
// }
static Future dynRed() {
return GrpcRepo.request(
GrpcUrl.dynRed,
DynRedReq(tabOffset: [TabOffset(tab: 1)]),
DynRedReply.fromBuffer,
onSuccess: (response) => response.dynRedItem.count.toInt(),
);
}
}

View File

@@ -2,20 +2,12 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/grpc/bilibili/app/dynamic/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/app/dynamic/v2.pb.dart';
import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart';
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/metadata.pb.dart';
import 'package:PiliPlus/grpc/bilibili/metadata/device.pb.dart';
import 'package:PiliPlus/grpc/bilibili/metadata/fawkes.pb.dart';
import 'package:PiliPlus/grpc/bilibili/metadata/locale.pb.dart';
import 'package:PiliPlus/grpc/bilibili/metadata/network.pb.dart' as network;
import 'package:PiliPlus/grpc/bilibili/metadata/restriction.pb.dart';
import 'package:PiliPlus/grpc/bilibili/pagination.pb.dart';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/utils/login_utils.dart';
@@ -24,8 +16,7 @@ import 'package:PiliPlus/utils/utils.dart';
import 'package:archive/archive.dart';
import 'package:dio/dio.dart';
import 'package:fixnum/fixnum.dart';
import 'package:protobuf/protobuf.dart' show GeneratedMessage, PbMap;
import 'package:uuid/uuid.dart';
import 'package:protobuf/protobuf.dart' show GeneratedMessage;
class GrpcUrl {
// static const playerOnline =
@@ -56,7 +47,12 @@ class GrpcUrl {
static const sendMsg = '$im/SendMsg';
static const shareList = '$im/ShareList';
static const sessionMain = '$im2/SessionMain';
static const sessionSecondary = '$im2/SessionSecondary';
static const clearUnread = '$im2/ClearUnread';
static const sessionUpdate = '$im2/SessionUpdate';
static const pinSession = '$im2/PinSession';
static const unpinSession = '$im2/UnpinSession';
static const deleteSessionList = '$im2/DeleteSessionList';
}
class GrpcRepo {
@@ -172,7 +168,7 @@ class GrpcRepo {
}
}
static Future<Map<String, dynamic>> _request(
static Future<Map<String, dynamic>> request(
url, GeneratedMessage request, Function grpcParser,
{Function? onSuccess}) async {
final response = await Request().post(HttpString.appBaseUrl + url,
@@ -231,194 +227,4 @@ class GrpcRepo {
// return {'status': true, 'data': response.items};
// });
// }
// static Future replyInfo({required int rpid}) {
// return _request(
// GrpcUrl.replyInfo,
// ReplyInfoReq(rpid: Int64(rpid)),
// ReplyInfoReply.fromBuffer,
// onSuccess: (response) => response.reply,
// );
// }
// static Future dynSpace({
// required int uid,
// required int page,
// }) {
// return _request(
// GrpcUrl.dynSpace,
// DynSpaceReq(
// hostUid: Int64(uid),
// localTime: 8,
// page: Int64(page),
// from: 'space',
// ),
// DynSpaceRsp.fromBuffer,
// );
// }
static Future mainList({
int type = 1,
required int oid,
required Mode mode,
required String? offset,
required Int64? cursorNext,
}) {
return _request(
GrpcUrl.mainList,
MainListReq(
oid: Int64(oid),
type: Int64(type),
rpid: Int64(0),
cursor: CursorReq(
mode: mode,
next: cursorNext,
),
// pagination: FeedPagination(offset: offset ?? ''),
),
MainListReply.fromBuffer,
);
}
static Future detailList({
int type = 1,
required int oid,
required int root,
required int rpid,
required Mode mode,
required String? offset,
}) {
return _request(
GrpcUrl.detailList,
DetailListReq(
oid: Int64(oid),
type: Int64(type),
root: Int64(root),
rpid: Int64(rpid),
scene: DetailListScene.REPLY,
mode: mode,
pagination: FeedPagination(offset: offset ?? ''),
),
DetailListReply.fromBuffer,
);
}
static Future dialogList({
int type = 1,
required int oid,
required int root,
required int dialog,
required String? offset,
}) {
return _request(
GrpcUrl.dialogList,
DialogListReq(
oid: Int64(oid),
type: Int64(type),
root: Int64(root),
dialog: Int64(dialog),
pagination: FeedPagination(offset: offset ?? ''),
),
DialogListReply.fromBuffer,
);
}
static Future dynRed() {
return _request(
GrpcUrl.dynRed,
DynRedReq(tabOffset: [TabOffset(tab: 1)]),
DynRedReply.fromBuffer,
onSuccess: (response) => response.dynRedItem.count.toInt(),
);
}
static Future dmSegMobile(
{required int cid, required int segmentIndex, int type = 1}) {
return _request(
GrpcUrl.dmSegMobile,
DmSegMobileReq(
oid: Int64(cid),
segmentIndex: Int64(segmentIndex),
type: type,
),
DmSegMobileReply.fromBuffer,
);
}
static Future sendMsg({
required int senderUid,
required int receiverId,
required String content,
MsgType msgType = MsgType.EN_MSG_TYPE_TEXT,
}) {
final devId = const Uuid().v4();
return _request(
GrpcUrl.sendMsg,
ReqSendMsg(
msg: Msg(
senderUid: Int64(senderUid),
receiverType: 1,
receiverId: Int64(receiverId),
msgType: msgType.value,
content: content,
timestamp: Int64(DateTime.now().millisecondsSinceEpoch ~/ 1000),
msgStatus: 0,
newFaceVersion: 1,
),
devId: devId,
),
RspSendMsg.fromBuffer,
);
}
static Future shareList({int size = 10}) {
return _request(
GrpcUrl.shareList,
ReqShareList(size: size),
RspShareList.fromBuffer,
);
}
static Future sessionMain({PbMap<int, Offset>? offset}) {
return _request(
GrpcUrl.sessionMain,
SessionMainReq(
paginationParams: PaginationParams(offsets: offset),
),
SessionMainReply.fromBuffer,
);
}
static Future clearUnread({
SessionPageType? pageType,
SessionId? sessionId,
}) {
return _request(
GrpcUrl.clearUnread,
ClearUnreadReq(
pageType: pageType,
sessionId: sessionId,
),
ClearUnreadReply.fromBuffer,
);
}
static Future opusSpaceFlow({
required int hostMid,
String? next,
required String filterType,
}) {
return _request(
GrpcUrl.opusSpaceFlow,
OpusSpaceFlowReq(
hostMid: Int64(hostMid),
pagination: Pagination(
pageSize: 20,
next: next,
),
filterType: filterType,
),
OpusSpaceFlowResp.fromBuffer,
);
}
}

146
lib/grpc/im.dart Normal file
View File

@@ -0,0 +1,146 @@
import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:fixnum/fixnum.dart';
import 'package:protobuf/protobuf.dart' show PbMap;
import 'package:uuid/uuid.dart';
class ImGrpc {
static Future sendMsg({
required int senderUid,
required int receiverId,
required String content,
MsgType msgType = MsgType.EN_MSG_TYPE_TEXT,
}) {
final devId = const Uuid().v4();
return GrpcRepo.request(
GrpcUrl.sendMsg,
ReqSendMsg(
msg: Msg(
senderUid: Int64(senderUid),
receiverType: 1,
receiverId: Int64(receiverId),
msgType: msgType.value,
content: content,
timestamp: Int64(DateTime.now().millisecondsSinceEpoch ~/ 1000),
msgStatus: 0,
newFaceVersion: 1,
),
devId: devId,
),
RspSendMsg.fromBuffer,
);
}
static Future shareList({int size = 10}) {
return GrpcRepo.request(
GrpcUrl.shareList,
ReqShareList(size: size),
RspShareList.fromBuffer,
);
}
static Future<LoadingState<SessionMainReply>> sessionMain({
PbMap<int, Offset>? offset,
}) async {
final res = await GrpcRepo.request(
GrpcUrl.sessionMain,
SessionMainReq(
paginationParams: PaginationParams(offsets: offset),
),
SessionMainReply.fromBuffer,
);
if (res['status']) {
return LoadingState.success(res['data']);
} else {
return LoadingState.error(res['msg']);
}
}
static Future<LoadingState<SessionSecondaryReply>> sessionSecondary({
PbMap<int, Offset>? offset,
SessionPageType? pageType,
}) async {
final res = await GrpcRepo.request(
GrpcUrl.sessionSecondary,
SessionSecondaryReq(
paginationParams: PaginationParams(offsets: offset),
pageType: pageType,
),
SessionSecondaryReply.fromBuffer,
);
if (res['status']) {
return LoadingState.success(res['data']);
} else {
return LoadingState.error(res['msg']);
}
}
static Future clearUnread({
SessionPageType? pageType,
SessionId? sessionId,
}) {
return GrpcRepo.request(
GrpcUrl.clearUnread,
ClearUnreadReq(
pageType: pageType,
sessionId: sessionId,
),
ClearUnreadReply.fromBuffer,
);
}
static Future sessionUpdate({
SessionPageType? pageType,
SessionId? sessionId,
}) {
return GrpcRepo.request(
GrpcUrl.sessionUpdate,
SessionUpdateReq(
pageType: pageType,
sessionId: sessionId,
),
SessionUpdateReply.fromBuffer,
);
}
static Future pinSession({
SessionId? sessionId,
Int64? topTimeMicros,
}) {
return GrpcRepo.request(
GrpcUrl.pinSession,
PinSessionReq(
sessionId: sessionId,
topTimeMicros: topTimeMicros,
),
PinSessionReply.fromBuffer,
);
}
static Future unpinSession({
SessionId? sessionId,
}) {
return GrpcRepo.request(
GrpcUrl.unpinSession,
UnPinSessionReq(
sessionId: sessionId,
),
UnPinSessionReply.fromBuffer,
);
}
static Future deleteSessionList({
SessionPageType? pageType,
}) {
return GrpcRepo.request(
GrpcUrl.deleteSessionList,
DeleteSessionListReq(
pageType: pageType,
),
DeleteSessionListReply.fromBuffer,
);
}
}

189
lib/grpc/reply.dart Normal file
View File

@@ -0,0 +1,189 @@
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart';
import 'package:PiliPlus/grpc/bilibili/pagination.pb.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/reply.dart';
import 'package:fixnum/fixnum.dart';
class ReplyGrpc {
// static Future replyInfo({required int rpid}) {
// return _request(
// GrpcUrl.replyInfo,
// ReplyInfoReq(rpid: Int64(rpid)),
// ReplyInfoReply.fromBuffer,
// onSuccess: (response) => response.reply,
// );
// }
// ref BiliRoamingX
static bool needRemoveGrpc(ReplyInfo reply) {
if ((reply.content.urls.isNotEmpty &&
reply.content.urls.values.any((url) {
return url.hasExtra() &&
(url.extra.goodsCmControl == 1 ||
url.extra.goodsItemId != 0 ||
url.extra.goodsPrefetchedCache.isNotEmpty);
})) ||
reply.content.message.contains(Constants.goodsUrlPrefix)) {
return true;
}
return false;
}
static Future<LoadingState<MainListReply>> mainList({
int type = 1,
required int oid,
required Mode mode,
required String? offset,
required Int64? cursorNext,
required bool antiGoodsReply,
}) async {
dynamic res = await GrpcRepo.request(
GrpcUrl.mainList,
MainListReq(
oid: Int64(oid),
type: Int64(type),
rpid: Int64(0),
cursor: CursorReq(
mode: mode,
next: cursorNext,
),
// pagination: FeedPagination(offset: offset ?? ''),
),
MainListReply.fromBuffer,
);
if (res['status']) {
MainListReply mainListReply = res['data'];
// keyword filter
if (ReplyHttp.replyRegExp.pattern.isNotEmpty) {
// upTop
if (mainListReply.hasUpTop() &&
ReplyHttp.replyRegExp
.hasMatch(mainListReply.upTop.content.message)) {
mainListReply.clearUpTop();
}
// replies
if (mainListReply.replies.isNotEmpty) {
mainListReply.replies.removeWhere((item) {
bool hasMatch =
ReplyHttp.replyRegExp.hasMatch(item.content.message);
// remove subreplies
if (!hasMatch) {
if (item.replies.isNotEmpty) {
item.replies.removeWhere((item) =>
ReplyHttp.replyRegExp.hasMatch(item.content.message));
}
}
return hasMatch;
});
}
}
// antiGoodsReply
if (antiGoodsReply) {
// upTop
if (mainListReply.hasUpTop() && needRemoveGrpc(mainListReply.upTop)) {
mainListReply.clearUpTop();
}
// replies
if (mainListReply.replies.isNotEmpty) {
mainListReply.replies.removeWhere((item) {
bool hasMatch = needRemoveGrpc(item);
// remove subreplies
if (!hasMatch) {
if (item.replies.isNotEmpty) {
item.replies.removeWhere(needRemoveGrpc);
}
}
return hasMatch;
});
}
}
return LoadingState.success(mainListReply);
} else {
return LoadingState.error(res['msg']);
}
}
static Future<LoadingState<DetailListReply>> detailList({
int type = 1,
required int oid,
required int root,
required int rpid,
required Mode mode,
required String? offset,
required bool antiGoodsReply,
}) async {
dynamic res = await GrpcRepo.request(
GrpcUrl.detailList,
DetailListReq(
oid: Int64(oid),
type: Int64(type),
root: Int64(root),
rpid: Int64(rpid),
scene: DetailListScene.REPLY,
mode: mode,
pagination: FeedPagination(offset: offset ?? ''),
),
DetailListReply.fromBuffer,
);
if (res['status']) {
DetailListReply detailListReply = res['data'];
if (ReplyHttp.replyRegExp.pattern.isNotEmpty) {
if (detailListReply.root.replies.isNotEmpty) {
detailListReply.root.replies.removeWhere(
(item) => ReplyHttp.replyRegExp.hasMatch(item.content.message));
}
}
if (antiGoodsReply) {
if (detailListReply.root.replies.isNotEmpty) {
detailListReply.root.replies.removeWhere(needRemoveGrpc);
}
}
return LoadingState.success(detailListReply);
} else {
return LoadingState.error(res['msg']);
}
}
static Future<LoadingState<DialogListReply>> dialogList({
int type = 1,
required int oid,
required int root,
required int dialog,
required String? offset,
required bool antiGoodsReply,
}) async {
dynamic res = await GrpcRepo.request(
GrpcUrl.dialogList,
DialogListReq(
oid: Int64(oid),
type: Int64(type),
root: Int64(root),
dialog: Int64(dialog),
pagination: FeedPagination(offset: offset ?? ''),
),
DialogListReply.fromBuffer,
);
if (res['status']) {
DialogListReply dialogListReply = res['data'];
if (ReplyHttp.replyRegExp.pattern.isNotEmpty) {
if (dialogListReply.replies.isNotEmpty) {
dialogListReply.replies.removeWhere(
(item) => ReplyHttp.replyRegExp.hasMatch(item.content.message));
}
}
if (antiGoodsReply) {
if (dialogListReply.replies.isNotEmpty) {
dialogListReply.replies.removeWhere(needRemoveGrpc);
}
}
return LoadingState.success(dialogListReply);
} else {
return LoadingState.error(res['msg']);
}
}
}

31
lib/grpc/space.dart Normal file
View File

@@ -0,0 +1,31 @@
import 'package:PiliPlus/grpc/bilibili/app/dynamic/v2.pb.dart';
import 'package:PiliPlus/grpc/bilibili/pagination.pb.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:fixnum/fixnum.dart';
class SpaceGrpc {
static Future<LoadingState<OpusSpaceFlowResp>> opusSpaceFlow({
required int hostMid,
String? next,
required String filterType,
}) async {
final res = await GrpcRepo.request(
GrpcUrl.opusSpaceFlow,
OpusSpaceFlowReq(
hostMid: Int64(hostMid),
pagination: Pagination(
pageSize: 20,
next: next,
),
filterType: filterType,
),
OpusSpaceFlowResp.fromBuffer,
);
if (res['status']) {
return LoadingState.success(res['data']);
} else {
return LoadingState.error(res['msg']);
}
}
}