mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: support requestUploadGroupPic
Signed-off-by: 白池 <whitechi73@outlook.com>
This commit is contained in:
parent
68ea62ea0b
commit
720313124c
21
app/proguard-rules.pro
vendored
21
app/proguard-rules.pro
vendored
@ -199,17 +199,36 @@
|
||||
|
||||
-keep class com.arthenica.ffmpegkit.NativeLoader { *; }
|
||||
|
||||
-keep class moe.fuqiuluo.** { *; }
|
||||
-keep class moe.fuqiuluo.shamrock.app.** { *; }
|
||||
-keep class moe.fuqiuluo.shamrock.ui.** { *; }
|
||||
-keep class moe.fuqiuluo.shamrock.MainActivity { *; }
|
||||
-keep class moe.fuqiuluo.shamrock.MainActivityKt { *; }
|
||||
-keep class moe.fuqiuluo.shamrock.Manifest { *; }
|
||||
|
||||
-keep class moe.fuqiuluo.shamrock.xposed.** { *; }
|
||||
-keep class moe.fuqiuluo.shamrock.helper.** { *; }
|
||||
|
||||
# tencent interfaces rules
|
||||
-keep class com.tencent.** { *; }
|
||||
-keep class com.qq.** { *; }
|
||||
-keep class com.google.gson.** { *; }
|
||||
-keep class de.** { *; }
|
||||
-keep class epic.** { *; }
|
||||
-keep class friendlist.** { *; }
|
||||
-keep class KQQ.** { *; }
|
||||
-keep class mqq.** { *; }
|
||||
-keep class msf.** { *; }
|
||||
-keep class oicq.** { *; }
|
||||
-keep class QQService.** { *; }
|
||||
-keep class SummaryCard.** { *; }
|
||||
-keep class tencent.** { *; }
|
||||
-keep class VIP.** { *; }
|
||||
|
||||
-keepclassmembers class * {
|
||||
native <methods>;
|
||||
}
|
||||
-keep class io.netty.** { *; }
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ data class NotOnlineImage(
|
||||
@ProtoNumber(7) val picMd5: ByteArray? = null,
|
||||
@ProtoNumber(8) val picHeight: UInt? = null,
|
||||
@ProtoNumber(9) val picWidth: UInt? = null,
|
||||
@ProtoNumber(10) val resId: ByteArray? = null,
|
||||
@ProtoNumber(10) val resId: ByteArray? = null, // md5 + ".jpg"
|
||||
@ProtoNumber(11) val flag: ByteArray? = null,
|
||||
@ProtoNumber(12) val thumbUrl: String? = null,
|
||||
@ProtoNumber(13) val original: UInt? = null,
|
||||
|
63
protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Req.kt
Normal file
63
protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Req.kt
Normal file
@ -0,0 +1,63 @@
|
||||
package protobuf.oidb.cmd0x388
|
||||
|
||||
import com.google.protobuf.Internal.EMPTY_BYTE_ARRAY
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import moe.fuqiuluo.symbols.Protobuf
|
||||
|
||||
@Serializable
|
||||
data class Cmd0x388ReqBody(
|
||||
@ProtoNumber(1) var netType: Int = 0,
|
||||
@ProtoNumber(2) var subCmd: Int = 0,
|
||||
@ProtoNumber(3) var msgTryUpImg: ArrayList<TryUpImgReq>? = null,
|
||||
// @ProtoNumber(4) var rpt_msg_getimg_url_req: ArrayList<GetImgUrlReq>? = null,
|
||||
@ProtoNumber(5) var msgTryUpPttReq: ArrayList<TryUpPttReq>? = null,
|
||||
// @ProtoNumber(6) var msgGetPttUrlReq: ArrayList<GetPttUrlReq>? = null,
|
||||
@ProtoNumber(7) var commandId: Int = 0,
|
||||
// @ProtoNumber(8) var rpt_msg_del_img_req: ArrayList<DelImgReq>? = null,
|
||||
@ProtoNumber(1001) var extension: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
): Protobuf<Cmd0x388ReqBody>
|
||||
|
||||
@Serializable
|
||||
data class TryUpImgReq(
|
||||
@ProtoNumber(1) var groupCode: Long = 0,
|
||||
@ProtoNumber(2) var srcUin: Long = 0,
|
||||
@ProtoNumber(3) var fileId: Long? = null,
|
||||
@ProtoNumber(4) var fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(5) var fileSize: Long = 0,
|
||||
@ProtoNumber(6) var fileName: String = "",
|
||||
@ProtoNumber(7) var srcTerm: Int = 0,
|
||||
@ProtoNumber(8) var platformType: Int = 0,
|
||||
@ProtoNumber(9) var buType: Int = 0,
|
||||
@ProtoNumber(10) var picWidth: Int = 0,
|
||||
@ProtoNumber(11) var picHeight: Int = 0,
|
||||
@ProtoNumber(12) var picType: Int = 0,
|
||||
@ProtoNumber(13) var buildVer: String = "",
|
||||
@ProtoNumber(14) var innerIp: Int = 0,
|
||||
@ProtoNumber(15) var appPicType: Int = 0,
|
||||
@ProtoNumber(16) var originalPic: Int = 0,
|
||||
@ProtoNumber(17) var fileIndex: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(18) var dstUin: Long = 0,
|
||||
@ProtoNumber(19) var srvUpload: Int? = null,
|
||||
@ProtoNumber(20) var transferUrl: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TryUpPttReq(
|
||||
@ProtoNumber(1) var groupCode: Long = 0,
|
||||
@ProtoNumber(2) var srcUin: Long = 0,
|
||||
@ProtoNumber(3) var fileId: Long = 0,
|
||||
@ProtoNumber(4) var fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(5) var fileSize: Long = 0,
|
||||
@ProtoNumber(6) var fileName: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(7) var srcTerm: Int = 0,
|
||||
@ProtoNumber(8) var platformType: Int = 0,
|
||||
@ProtoNumber(9) var buType: Int = 0,
|
||||
@ProtoNumber(10) var buildVer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(11) var innerIp: Int = 0,
|
||||
@ProtoNumber(12) var voiceLength: Int = 0,
|
||||
@ProtoNumber(13) var newUpChan: Boolean = false,
|
||||
@ProtoNumber(14) var codec: Int = 0,
|
||||
@ProtoNumber(15) var voiceType: Int = 0,
|
||||
@ProtoNumber(16) var buId: Int = 0,
|
||||
)
|
78
protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Rsp.kt
Normal file
78
protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Rsp.kt
Normal file
@ -0,0 +1,78 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package protobuf.oidb.cmd0x388
|
||||
|
||||
import com.google.protobuf.Internal.EMPTY_BYTE_ARRAY
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import moe.fuqiuluo.symbols.Protobuf
|
||||
|
||||
@Serializable
|
||||
data class Cmd0x388RspBody(
|
||||
@ProtoNumber(1) var clientIp: UInt = 0u,
|
||||
@ProtoNumber(2) var subCmd: UInt = 0u,
|
||||
@ProtoNumber(3) var msgTryUpImgRsp: ArrayList<TryUpImgRsp>? = null,
|
||||
@ProtoNumber(5) var msgTryUpPttRsp: ArrayList<TryUpPttRsp>? = null,
|
||||
): Protobuf<Cmd0x388RspBody>
|
||||
|
||||
@Serializable
|
||||
data class TryUpPttRsp(
|
||||
@ProtoNumber(1) var fileId: Long = 0,
|
||||
@ProtoNumber(2) var result: Int = 0,
|
||||
@ProtoNumber(3) var failMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(4) var fileExit: Boolean = false,
|
||||
@ProtoNumber(5) var upIp: List<Int>? = null,
|
||||
@ProtoNumber(6) var upPort: List<Int>? = null,
|
||||
@ProtoNumber(7) var upUkey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(8) var fileid: Long = 0,
|
||||
@ProtoNumber(9) var upOffset: Long = 0,
|
||||
@ProtoNumber(10) var blockSize: Long = 0,
|
||||
@ProtoNumber(11) var fileKey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(12) var channelType: Int = 0,
|
||||
@ProtoNumber(26) var msgUpIp6: ArrayList<IPv6Info>? = null,
|
||||
@ProtoNumber(27) var clientIp6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
): Protobuf<TryUpPttRsp>
|
||||
|
||||
@Serializable
|
||||
data class TryUpImgRsp(
|
||||
@ProtoNumber(1) var extFileId: ULong = 0u, // 没有实际作用
|
||||
@ProtoNumber(2) var result: UInt = 0u,
|
||||
@ProtoNumber(3) var faiMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(4) var fileExist: Boolean = false,
|
||||
@ProtoNumber(5) var msgImgInfo: ImgInfo? = null, // 里面只是一堆垃圾
|
||||
@ProtoNumber(6) var upIp: ArrayList<Long>? = null,
|
||||
@ProtoNumber(7) var upPort: ArrayList<Int>? = null,
|
||||
@ProtoNumber(8) var ukey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(9) var fileId: Long = 0,
|
||||
@ProtoNumber(10) var upOffset: ULong = 0u,
|
||||
@ProtoNumber(11) var blockSize: Long = 0,
|
||||
@ProtoNumber(12) var bool_new_big_chan: Boolean = false,
|
||||
@ProtoNumber(26) var rpt_msg_up_ip6: ArrayList<IPv6Info>? = null,
|
||||
@ProtoNumber(27) var client_ip6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(1001) var msg_info4busi: TryUpInfo4Busi? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TryUpInfo4Busi(
|
||||
@ProtoNumber(1) var down_domain: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(2) var thumb_down_url: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(3) var original_down_url: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(4) var big_down_url: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(5) var file_resid: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class IPv6Info(
|
||||
@ProtoNumber(1) var ip6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(2) var port: UInt = 0u,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ImgInfo(
|
||||
@ProtoNumber(1) var file_md5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(2) var file_type: UInt = 0u,
|
||||
@ProtoNumber(3) var file_size: ULong = 0u,
|
||||
@ProtoNumber(4) var file_width: UInt = 0u,
|
||||
@ProtoNumber(5) var file_height: UInt = 0u,
|
||||
)
|
@ -0,0 +1,74 @@
|
||||
package com.tencent.mobileqq.data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MessageForPic extends MessageRecord {
|
||||
public String SpeedInfo;
|
||||
public String actMsgContentValue;
|
||||
public String action;
|
||||
public String bigMsgUrl;
|
||||
public String bigThumbMsgUrl;
|
||||
public int busiType;
|
||||
public int fileSizeFlag;
|
||||
public long groupFileID;
|
||||
public long height;
|
||||
public int imageType;
|
||||
public boolean isInMixedMsg;
|
||||
public boolean isMixed;
|
||||
public boolean isRead;
|
||||
public boolean isShareAppActionMsg;
|
||||
public String localUUID;
|
||||
public int mCurrlength;
|
||||
public int mDownloadLength;
|
||||
public long mPresendTransferedSize;
|
||||
public int mShowLength;
|
||||
public String md5;
|
||||
//@RecordForTest
|
||||
// public msg_ctrl$MsgCtrl msgCtrl;
|
||||
public int msgVia;
|
||||
public int ntChatType;
|
||||
public String ntPeerUid;
|
||||
public String path;
|
||||
//public PicMessageExtraData picExtraData;
|
||||
public int picExtraFlag;
|
||||
public Object picExtraObject;
|
||||
public int previewed;
|
||||
public String rawMsgUrl;
|
||||
/// public ReportInfo reportInfo;
|
||||
//public MsgRecordParams rootMsgRecordParams;
|
||||
public String serverStoreSource;
|
||||
public long shareAppID;
|
||||
public long size;
|
||||
public long subTypeId;
|
||||
public int thumbHeight;
|
||||
public String thumbMsgUrl;
|
||||
public int thumbWidth;
|
||||
//public ThumbWidthHeightDP thumbWidthHeightDP;
|
||||
public int type;
|
||||
public String uuid;
|
||||
public long width;
|
||||
public boolean isDownStatusReady = false;
|
||||
public int subMsgId = 0;
|
||||
public int isReport = 0;
|
||||
public int subVersion = 5;
|
||||
public int preDownState = -1;
|
||||
public int preDownNetworkType = -1;
|
||||
public long DSKey = 0;
|
||||
public int mNotPredownloadReason = 0;
|
||||
public int subThumbWidth = -1;
|
||||
public int subThumbHeight = -1;
|
||||
public int aiofileType = -1;
|
||||
public int subMsgType = -1;
|
||||
public boolean bEnableEnc = false;
|
||||
public int thumbSize = -1;
|
||||
public boolean isBlessPic = false;
|
||||
public boolean sync2Story = false;
|
||||
public boolean isQzonePic = false;
|
||||
public boolean isStoryPhoto = false;
|
||||
public long replyRealSourceMsgId = -1;
|
||||
|
||||
public String toLogString() {
|
||||
return "path:" + this.path + ",uuid:" + this.uuid + ",md5:" + this.md5 + ",size:" + this.size + ",groupFileID:" + this.groupFileID;
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package com.tencent.mobileqq.transfile;
|
||||
|
||||
public class BaseTransProcessor {
|
||||
import com.tencent.mobileqq.utils.httputils.IHttpCommunicatorListener;
|
||||
|
||||
public class BaseTransProcessor implements IHttpCommunicatorListener {
|
||||
public FileMsg file;
|
||||
|
||||
public long getFileStatus() {
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.tencent.mobileqq.transfile;
|
||||
|
||||
public class BaseUploadProcessor extends BaseTransProcessor {
|
||||
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
package com.tencent.mobileqq.transfile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class FileMsg {
|
||||
public static final int STATUS_FILE_EXPIRED = 5002;
|
||||
public static final int STATUS_FILE_TRANSFERING = 5000;
|
||||
@ -107,4 +111,58 @@ public class FileMsg {
|
||||
public static final int UIN_BUDDY = 0;
|
||||
public static final int UIN_DISCUSS = 2;
|
||||
public static final int UIN_TROOP = 1;
|
||||
|
||||
public String domain;
|
||||
public String downDomain;
|
||||
public long endTime;
|
||||
public int errorCode;
|
||||
public String errorMessage;
|
||||
public File file;
|
||||
public long fileID;
|
||||
public String fileKey;
|
||||
public String fileMd5;
|
||||
public String filePath;
|
||||
public long fileSize;
|
||||
public int fileType;
|
||||
public String fileUrl;
|
||||
public String forwardTaskKey;
|
||||
public String friendUin;
|
||||
public int isRead;
|
||||
public boolean isStreamMode;
|
||||
public int lastStatus;
|
||||
public byte[] localFileMd5;
|
||||
public String logTag;
|
||||
public long mSecMsgId;
|
||||
public long mSubMsgId;
|
||||
public String mUin;
|
||||
public String msgImageData;
|
||||
public String msgTime;
|
||||
public String orgiDownUrl;
|
||||
public String peerUin;
|
||||
public int picScale;
|
||||
public long picThumbSize;
|
||||
public BaseTransProcessor processor;
|
||||
public boolean processorDoReportSelf;
|
||||
public int pttSlicePos;
|
||||
public String pttSliceText;
|
||||
public OutputStream revStream;
|
||||
public String selfUin;
|
||||
public InputStream sendStream;
|
||||
public String serverPath;
|
||||
public long startTime;
|
||||
public int status;
|
||||
public long stepUrlCost;
|
||||
public String suffixType;
|
||||
public String thumbDownUrl;
|
||||
public String thumbPath;
|
||||
public String thumbUrl;
|
||||
public String tmpFilePath;
|
||||
public byte[] transferData;
|
||||
public long transferedSize;
|
||||
public String uKey;
|
||||
public int uinType;
|
||||
public long uniseq;
|
||||
public String[] urls;
|
||||
public byte[] userInfo;
|
||||
public String uuidPath;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
package com.tencent.mobileqq.transfile;
|
||||
|
||||
public class GroupPicUploadProcessor {
|
||||
import com.tencent.mobileqq.utils.httputils.IHttpCommunicatorListener;
|
||||
|
||||
public class GroupPicUploadProcessor extends BaseUploadProcessor {
|
||||
}
|
||||
|
@ -208,6 +208,8 @@ public final class PicElement implements IKernelModel {
|
||||
this.isFlashPic = bool;
|
||||
}
|
||||
|
||||
public void setStoreID(int i2) {
|
||||
}
|
||||
public void setMd5HexStr(String str) {
|
||||
this.md5HexStr = str;
|
||||
}
|
||||
|
180
xposed/proguard-rules.pro
vendored
180
xposed/proguard-rules.pro
vendored
@ -18,182 +18,4 @@
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
|
||||
# Never inline methods, but allow shrinking and obfuscation.
|
||||
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.view.ViewCompat$Api* {
|
||||
<methods>;
|
||||
}
|
||||
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.view.WindowInsetsCompat$*Impl* {
|
||||
<methods>;
|
||||
}
|
||||
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.app.NotificationCompat$*$Api*Impl {
|
||||
<methods>;
|
||||
}
|
||||
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.os.UserHandleCompat$Api*Impl {
|
||||
<methods>;
|
||||
}
|
||||
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.widget.EdgeEffectCompat$Api*Impl {
|
||||
<methods>;
|
||||
}
|
||||
|
||||
# Keep metadata about inner emulated classes. This helps with
|
||||
# reflection on older platforms, but can be omitted if the
|
||||
# metadata usage is not present in the app.
|
||||
|
||||
-keepclassmembers class * {
|
||||
** CREATOR;
|
||||
}
|
||||
|
||||
# Keep the special static methods that are required in all enumeration
|
||||
# classes.
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep public class androidx.appcompat.widget.** { *; }
|
||||
-keep public class androidx.appcompat.app.** { *; }
|
||||
-keep public class androidx.appcompat.view.menu.** { *; }
|
||||
|
||||
# Ensure that reflectively-loaded inflater is not obfuscated. This can be
|
||||
# removed when we stop supporting AAPT1 builds.
|
||||
-keepnames class androidx.appcompat.app.AppCompatViewInflater
|
||||
# aapt is not able to read app::actionViewClass and app:actionProviderClass to produce proguard
|
||||
# keep rules. Add a commonly used SearchView to the keep list until b/109831488 is resolved.
|
||||
-keep class androidx.appcompat.widget.SearchView { <init>(...); }
|
||||
|
||||
# CoordinatorLayout resolves the behaviors of its child components with reflection.
|
||||
-keep public class * extends androidx.coordinatorlayout.widget.CoordinatorLayout$Behavior {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>();
|
||||
}
|
||||
|
||||
# Make sure we keep annotations for CoordinatorLayout's DefaultBehavior
|
||||
-keepattributes RuntimeVisible*Annotation*
|
||||
|
||||
-if class androidx.appcompat.app.AppCompatViewInflater
|
||||
-keep class com.google.android.material.theme.MaterialComponentsViewInflater {
|
||||
<init>();
|
||||
}
|
||||
|
||||
# Keep `Companion` object fields of serializable classes.
|
||||
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
||||
-if @kotlinx.serialization.Serializable class **
|
||||
-keepclassmembers class <1> {
|
||||
static <1>$Companion Companion;
|
||||
}
|
||||
|
||||
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
static **$* *;
|
||||
}
|
||||
-keepclassmembers class <2>$<3> {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# Keep `INSTANCE.serializer()` of serializable objects.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
public static ** INSTANCE;
|
||||
}
|
||||
-keepclassmembers class <1> {
|
||||
public static <1> INSTANCE;
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||
|
||||
# Don't print notes about potential mistakes or omissions in the configuration for kotlinx-serialization classes
|
||||
# See also https://github.com/Kotlin/kotlinx.serialization/issues/1900
|
||||
-dontnote kotlinx.serialization.**
|
||||
|
||||
# Serialization core uses `java.lang.ClassValue` for caching inside these specified classes.
|
||||
# If there is no `java.lang.ClassValue` (for example, in Android), then R8/ProGuard will print a warning.
|
||||
# However, since in this case they will not be used, we can disable these warnings
|
||||
-dontwarn kotlinx.serialization.internal.ClassValueReferences
|
||||
|
||||
# Rule to save runtime annotations on serializable class.
|
||||
# If the R8 full mode is used, annotations are removed from classes-files.
|
||||
#
|
||||
# For the annotation serializer, it is necessary to read the `Serializable` annotation inside the serializer<T>() function - if it is present,
|
||||
# then `SealedClassSerializer` is used, if absent, then `PolymorphicSerializer'.
|
||||
#
|
||||
# When using R8 full mode, all interfaces will be serialized using `PolymorphicSerializer`.
|
||||
#
|
||||
# see https://github.com/Kotlin/kotlinx.serialization/issues/2050
|
||||
|
||||
-if @kotlinx.serialization.Serializable class **
|
||||
-keep, allowshrinking, allowoptimization, allowobfuscation, allowaccessmodification class <1>
|
||||
|
||||
# Entry point for retaining MainDispatcherLoader which uses a ServiceLoader.
|
||||
-keep class kotlinx.coroutines.Dispatchers {
|
||||
** getMain();
|
||||
}
|
||||
|
||||
# Entry point for retaining CoroutineExceptionHandlerImpl.handlers which uses a ServiceLoader.
|
||||
-keep class kotlinx.coroutines.CoroutineExceptionHandlerKt {
|
||||
void handleCoroutineException(...);
|
||||
}
|
||||
|
||||
# Entry point for the rest of coroutines machinery
|
||||
-keep class kotlinx.coroutines.BuildersKt {
|
||||
** runBlocking(...);
|
||||
** launch(...);
|
||||
}
|
||||
|
||||
# We are cheating a bit by not having android.jar on R8's library classpath. Ignore those warnings.
|
||||
-ignorewarnings
|
||||
|
||||
-keep class kotlinx.coroutines.android.AndroidDispatcherFactory {*;}
|
||||
-keep class kotlinx.coroutines.android.AndroidExceptionPreHandler {*;}
|
||||
|
||||
# Statically turn off all debugging facilities and assertions
|
||||
-keepclassmembers class io.ktor.** { volatile <fields>; }
|
||||
-keep class io.ktor.** { *; }
|
||||
-keep class kotlinx.coroutines.** { *; }
|
||||
-dontwarn kotlinx.atomicfu.**
|
||||
-dontwarn io.netty.**
|
||||
-dontwarn com.typesafe.**
|
||||
-assumenosideeffects class * implements org.slf4j.Logger {
|
||||
public *** trace(...);
|
||||
public *** debug(...);
|
||||
public *** info(...);
|
||||
public *** warn(...);
|
||||
public *** error(...);
|
||||
}
|
||||
-keep class kotlin.reflect.jvm.internal.** { *; }
|
||||
|
||||
-keep class com.arthenica.ffmpegkit.FFmpegKitConfig {
|
||||
native <methods>;
|
||||
void log(long, int, byte[]);
|
||||
void statistics(long, int, float, float, long , int, double, double);
|
||||
int safOpen(int);
|
||||
int safClose(int);
|
||||
}
|
||||
|
||||
-keep class com.arthenica.ffmpegkit.AbiDetect {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keep class com.arthenica.ffmpegkit.NativeLoader { *; }
|
||||
|
||||
-keep class moe.fuqiuluo.** { *; }
|
||||
-keep class com.tencent.** { *; }
|
||||
-keep class com.qq.** { *; }
|
||||
-keep class com.google.gson.** { *; }
|
||||
-keep class de.** { *; }
|
||||
-keep class mqq.** { *; }
|
||||
-keep class QQService.** { *; }
|
||||
-keep class SummaryCard.** { *; }
|
||||
-keep class tencent.** { *; }
|
||||
|
||||
-keepclassmembers class * {
|
||||
native <methods>;
|
||||
}
|
||||
-keep class io.netty.** { *; }
|
||||
|
||||
-keep class moe.fuqiuluo.** implements com.tencent.qqnt.kernel.nativeinterface.** {
|
||||
*;
|
||||
}
|
||||
#-renamesourcefileattribute SourceFile
|
@ -3,6 +3,7 @@ package moe.fuqiuluo.qqinterface.servlet.msg.maker
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.tencent.mobileqq.app.QQAppInterface
|
||||
import com.tencent.mobileqq.data.MessageForPic
|
||||
import com.tencent.mobileqq.emoticon.QQSysFaceUtil
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
@ -57,37 +58,37 @@ import kotlin.random.nextInt
|
||||
|
||||
internal typealias IMsgElementMaker = suspend (Int, Long, String, JsonObject) -> Result<MsgElement>
|
||||
|
||||
internal object MsgElementMaker {
|
||||
internal object NtMsgElementMaker {
|
||||
private val makerMap = hashMapOf(
|
||||
"text" to MsgElementMaker::createTextElem,
|
||||
"face" to MsgElementMaker::createFaceElem,
|
||||
"pic" to MsgElementMaker::createImageElem,
|
||||
"image" to MsgElementMaker::createImageElem,
|
||||
"voice" to MsgElementMaker::createRecordElem,
|
||||
"record" to MsgElementMaker::createRecordElem,
|
||||
"at" to MsgElementMaker::createAtElem,
|
||||
"video" to MsgElementMaker::createVideoElem,
|
||||
"markdown" to MsgElementMaker::createMarkdownElem,
|
||||
"dice" to MsgElementMaker::createDiceElem,
|
||||
"rps" to MsgElementMaker::createRpsElem,
|
||||
"poke" to MsgElementMaker::createPokeElem,
|
||||
"anonymous" to MsgElementMaker::createAnonymousElem,
|
||||
"share" to MsgElementMaker::createShareElem,
|
||||
"contact" to MsgElementMaker::createContactElem,
|
||||
"location" to MsgElementMaker::createLocationElem,
|
||||
"music" to MsgElementMaker::createMusicElem,
|
||||
"reply" to MsgElementMaker::createReplyElem,
|
||||
"touch" to MsgElementMaker::createTouchElem,
|
||||
"weather" to MsgElementMaker::createWeatherElem,
|
||||
"json" to MsgElementMaker::createJsonElem,
|
||||
"new_dice" to MsgElementMaker::createNewDiceElem,
|
||||
"new_rps" to MsgElementMaker::createNewRpsElem,
|
||||
"basketball" to MsgElementMaker::createBasketballElem,
|
||||
"text" to NtMsgElementMaker::createTextElem,
|
||||
"face" to NtMsgElementMaker::createFaceElem,
|
||||
"pic" to NtMsgElementMaker::createImageElem,
|
||||
"image" to NtMsgElementMaker::createImageElem,
|
||||
"voice" to NtMsgElementMaker::createRecordElem,
|
||||
"record" to NtMsgElementMaker::createRecordElem,
|
||||
"at" to NtMsgElementMaker::createAtElem,
|
||||
"video" to NtMsgElementMaker::createVideoElem,
|
||||
"markdown" to NtMsgElementMaker::createMarkdownElem,
|
||||
"dice" to NtMsgElementMaker::createDiceElem,
|
||||
"rps" to NtMsgElementMaker::createRpsElem,
|
||||
"poke" to NtMsgElementMaker::createPokeElem,
|
||||
"anonymous" to NtMsgElementMaker::createAnonymousElem,
|
||||
"share" to NtMsgElementMaker::createShareElem,
|
||||
"contact" to NtMsgElementMaker::createContactElem,
|
||||
"location" to NtMsgElementMaker::createLocationElem,
|
||||
"music" to NtMsgElementMaker::createMusicElem,
|
||||
"reply" to NtMsgElementMaker::createReplyElem,
|
||||
"touch" to NtMsgElementMaker::createTouchElem,
|
||||
"weather" to NtMsgElementMaker::createWeatherElem,
|
||||
"json" to NtMsgElementMaker::createJsonElem,
|
||||
"new_dice" to NtMsgElementMaker::createNewDiceElem,
|
||||
"new_rps" to NtMsgElementMaker::createNewRpsElem,
|
||||
"basketball" to NtMsgElementMaker::createBasketballElem,
|
||||
//"node" to MessageMaker::createNodeElem,
|
||||
//"multi_msg" to MessageMaker::createLongMsgStruct,
|
||||
"bubble_face" to MsgElementMaker::createBubbleFaceElem,
|
||||
"button" to MsgElementMaker::createInlineKeywordElem,
|
||||
"inline_keyboard" to MsgElementMaker::createInlineKeywordElem
|
||||
"bubble_face" to NtMsgElementMaker::createBubbleFaceElem,
|
||||
"button" to NtMsgElementMaker::createInlineKeywordElem,
|
||||
"inline_keyboard" to NtMsgElementMaker::createInlineKeywordElem
|
||||
)
|
||||
|
||||
operator fun get(type: String): IMsgElementMaker? = makerMap[type]
|
||||
@ -1006,6 +1007,10 @@ internal object MsgElementMaker {
|
||||
pic.picSubType = data["subType"].asIntOrNull ?: 0
|
||||
pic.isFlashPic = isFlash
|
||||
|
||||
//if (PlatformUtils.getQQVersionCode() >= PlatformUtils.QQ_9_0_8_VER && !ShamrockConfig.enableOldBDH()) {
|
||||
// pic.storeID = 1
|
||||
//}
|
||||
|
||||
elem.picElement = pic
|
||||
|
||||
return Result.success(elem)
|
@ -1,5 +1,7 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.transfile
|
||||
|
||||
import com.tencent.mobileqq.data.MessageRecord
|
||||
|
||||
internal enum class ContactType {
|
||||
TROOP,
|
||||
PRIVATE,
|
||||
@ -8,12 +10,20 @@ internal enum class ContactType {
|
||||
internal interface TransTarget {
|
||||
val id: String
|
||||
val type: ContactType
|
||||
|
||||
val mRec: MessageRecord?
|
||||
}
|
||||
|
||||
internal class Troop(override val id: String): TransTarget {
|
||||
internal class Troop(
|
||||
override val id: String,
|
||||
override val mRec: MessageRecord? = null
|
||||
): TransTarget {
|
||||
override val type: ContactType = ContactType.TROOP
|
||||
}
|
||||
|
||||
internal class Private(override val id: String): TransTarget {
|
||||
internal class Private(
|
||||
override val id: String,
|
||||
override val mRec: MessageRecord? = null
|
||||
): TransTarget {
|
||||
override val type: ContactType = ContactType.PRIVATE
|
||||
}
|
||||
|
@ -2,15 +2,18 @@
|
||||
|
||||
package moe.fuqiuluo.qqinterface.servlet.transfile
|
||||
|
||||
import com.tencent.mobileqq.transfile.BaseTransProcessor
|
||||
import com.tencent.mobileqq.transfile.FileMsg
|
||||
import com.tencent.mobileqq.transfile.TransferRequest
|
||||
import com.tencent.mobileqq.transfile.api.ITransFileController
|
||||
import com.tencent.mobileqq.utils.httputils.IHttpCommunicatorListener
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.utils.MD5
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import mqq.app.AppRuntime
|
||||
@ -81,6 +84,7 @@ internal abstract class FileTransfer {
|
||||
}
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch {
|
||||
lateinit var processor: IHttpCommunicatorListener
|
||||
while (
|
||||
//service.findProcessor(
|
||||
// transferRequest.keyForTransfer // uin + uniseq
|
||||
@ -89,8 +93,13 @@ internal abstract class FileTransfer {
|
||||
// 如果上传处理器依旧存在,说明没有上传成功
|
||||
&& service.isWorking.get()
|
||||
) {
|
||||
processor = service.findProcessor(runtime.currentAccountUin, transferRequest.mUniseq)
|
||||
delay(100)
|
||||
}
|
||||
if (processor is BaseTransProcessor && processor.file != null) {
|
||||
val fileMsg = processor.file
|
||||
LogCenter.log("[OldBDH] 资源上传结束(fileId = ${fileMsg.fileID}, fileKey = ${fileMsg.fileKey}, path = ${fileMsg.filePath})")
|
||||
}
|
||||
continuation.resume(true)
|
||||
}
|
||||
// 实现取消上传器
|
||||
|
@ -0,0 +1,224 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.transfile
|
||||
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.hex2ByteArray
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.symbols.decodeProtobuf
|
||||
import protobuf.auto.toByteArray
|
||||
import protobuf.oidb.TrpcOidb
|
||||
import protobuf.oidb.cmd0x11c5.ClientMeta
|
||||
import protobuf.oidb.cmd0x11c5.CodecConfigReq
|
||||
import protobuf.oidb.cmd0x11c5.CommonHead
|
||||
import protobuf.oidb.cmd0x11c5.DownloadExt
|
||||
import protobuf.oidb.cmd0x11c5.DownloadReq
|
||||
import protobuf.oidb.cmd0x11c5.FileInfo
|
||||
import protobuf.oidb.cmd0x11c5.FileType
|
||||
import protobuf.oidb.cmd0x11c5.IndexNode
|
||||
import protobuf.oidb.cmd0x11c5.MultiMediaReqHead
|
||||
import protobuf.oidb.cmd0x11c5.NtV2RichMediaReq
|
||||
import protobuf.oidb.cmd0x11c5.NtV2RichMediaRsp
|
||||
import protobuf.oidb.cmd0x11c5.SceneInfo
|
||||
import protobuf.oidb.cmd0x11c5.UploadInfo
|
||||
import protobuf.oidb.cmd0x11c5.UploadReq
|
||||
import protobuf.oidb.cmd0x11c5.VideoDownloadExt
|
||||
import protobuf.oidb.cmd0x388.Cmd0x388ReqBody
|
||||
import protobuf.oidb.cmd0x388.Cmd0x388RspBody
|
||||
import protobuf.oidb.cmd0x388.TryUpImgReq
|
||||
import java.io.File
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextUInt
|
||||
import kotlin.random.nextULong
|
||||
|
||||
internal object NtV2RichMediaSvc: BaseSvc() {
|
||||
private val requestIdSeq = atomic(2L)
|
||||
|
||||
/**
|
||||
* 获取NT图片的RKEY
|
||||
*/
|
||||
suspend fun getNtPicRKey(
|
||||
fileId: String,
|
||||
md5: String,
|
||||
sha: String,
|
||||
fileSize: ULong,
|
||||
width: UInt,
|
||||
height: UInt,
|
||||
sceneBuilder: suspend SceneInfo.() -> Unit
|
||||
): Result<String> {
|
||||
runCatching {
|
||||
val req = NtV2RichMediaReq(
|
||||
head = MultiMediaReqHead(
|
||||
commonHead = CommonHead(
|
||||
requestId = requestIdSeq.incrementAndGet().toULong(),
|
||||
cmd = 200u
|
||||
),
|
||||
sceneInfo = SceneInfo(
|
||||
requestType = 2u,
|
||||
businessType = 1u,
|
||||
).apply {
|
||||
sceneBuilder()
|
||||
},
|
||||
clientMeta = ClientMeta(2u)
|
||||
),
|
||||
download = DownloadReq(
|
||||
IndexNode(
|
||||
FileInfo(
|
||||
fileSize = fileSize,
|
||||
md5 = md5.lowercase(),
|
||||
sha1 = sha.lowercase(),
|
||||
name = "${md5}.jpg",
|
||||
fileType = FileType(
|
||||
fileType = 1u,
|
||||
picFormat = 1000u,
|
||||
videoFormat = 0u,
|
||||
voiceFormat = 0u
|
||||
),
|
||||
width = width,
|
||||
height = height,
|
||||
time = 0u,
|
||||
original = 1u
|
||||
),
|
||||
fileUuid = fileId,
|
||||
storeId = 1u,
|
||||
uploadTime = 0u,
|
||||
ttl = 0u,
|
||||
subType = 0u,
|
||||
storeAppId = 0u
|
||||
),
|
||||
DownloadExt(
|
||||
video = VideoDownloadExt(
|
||||
busiType = 0u,
|
||||
subBusiType = 0u,
|
||||
msgCodecConfig = CodecConfigReq(
|
||||
platformChipinfo = "",
|
||||
osVer = "",
|
||||
deviceName = ""
|
||||
),
|
||||
flag = 1u
|
||||
)
|
||||
)
|
||||
)
|
||||
).toByteArray()
|
||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_200", 4549, 200, req, true)?.slice(4)
|
||||
buffer?.decodeProtobuf<TrpcOidb>()?.buffer?.decodeProtobuf<NtV2RichMediaRsp>()?.download?.rkeyParam?.let {
|
||||
return Result.success(it)
|
||||
}
|
||||
}.onFailure {
|
||||
return Result.failure(it)
|
||||
}
|
||||
return Result.failure(Exception("unable to get c2c nt pic"))
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求上传Nt图片
|
||||
*/
|
||||
suspend fun requestUploadNtPic(
|
||||
file: File,
|
||||
md5: String,
|
||||
sha: String,
|
||||
name: String,
|
||||
width: UInt,
|
||||
height: UInt,
|
||||
sceneBuilder: suspend SceneInfo.() -> Unit
|
||||
) {
|
||||
val req = NtV2RichMediaReq(
|
||||
head = MultiMediaReqHead(
|
||||
commonHead = CommonHead(
|
||||
requestId = requestIdSeq.incrementAndGet().toULong(),
|
||||
cmd = 100u
|
||||
),
|
||||
sceneInfo = SceneInfo(
|
||||
requestType = 2u,
|
||||
businessType = 1u,
|
||||
).apply {
|
||||
sceneBuilder()
|
||||
},
|
||||
clientMeta = ClientMeta(2u)
|
||||
),
|
||||
upload = UploadReq(
|
||||
listOf(UploadInfo(
|
||||
FileInfo(
|
||||
fileSize = file.length().toULong(),
|
||||
md5 = md5,
|
||||
sha1 = sha,
|
||||
name = name,
|
||||
fileType = FileType(
|
||||
fileType = 1u,
|
||||
picFormat = 1000u,
|
||||
videoFormat = 0u,
|
||||
voiceFormat = 0u
|
||||
),
|
||||
width = width,
|
||||
height = height,
|
||||
time = 0u,
|
||||
original = 1u
|
||||
),
|
||||
subFileType = 0u
|
||||
)),
|
||||
tryFastUploadCompleted = true,
|
||||
srvSendMsg = false,
|
||||
clientRandomId = Random.nextULong(),
|
||||
compatQMsgSceneType = 1u,
|
||||
clientSeq = Random.nextUInt(),
|
||||
noNeedCompatMsg = true
|
||||
)
|
||||
).toByteArray()
|
||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_100", 4549, 100, req, true)?.slice(4)
|
||||
val rsp = buffer?.decodeProtobuf<TrpcOidb>()?.buffer?.decodeProtobuf<NtV2RichMediaRsp>()
|
||||
LogCenter.log("requestUploadPic => rsp: $rsp")
|
||||
}
|
||||
|
||||
suspend fun requestUploadGroupPic(
|
||||
groupId: ULong,
|
||||
md5: String,
|
||||
fileSize: ULong,
|
||||
width: UInt,
|
||||
height: UInt,
|
||||
): Result<TryUpPicData> {
|
||||
return runCatching {
|
||||
val rspBuffer = sendBufferAW("ImgStore.GroupPicUp", true, Cmd0x388ReqBody(
|
||||
netType = 3,
|
||||
subCmd = 1,
|
||||
msgTryUpImg = arrayListOf(
|
||||
TryUpImgReq(
|
||||
groupCode = groupId.toLong(),
|
||||
srcUin = TicketSvc.getLongUin(),
|
||||
fileMd5 = md5.hex2ByteArray(),
|
||||
fileSize = fileSize.toLong(),
|
||||
fileName = "$md5.jpg",
|
||||
srcTerm = 2,
|
||||
platformType = 9,
|
||||
buType = 212,
|
||||
picWidth = width.toInt(),
|
||||
picHeight = height.toInt(),
|
||||
picType = 1000,
|
||||
buildVer = "1.0.0",
|
||||
originalPic = 1,
|
||||
fileIndex = byteArrayOf(),
|
||||
srvUpload = 0
|
||||
)
|
||||
),
|
||||
).toByteArray())!!
|
||||
val rsp = rspBuffer.decodeProtobuf<Cmd0x388RspBody>()
|
||||
.msgTryUpImgRsp!!.first()
|
||||
TryUpPicData(
|
||||
uKey = rsp.ukey,
|
||||
exist = rsp.fileExist,
|
||||
fileId = rsp.fileId.toULong(),
|
||||
upIp = rsp.upIp,
|
||||
upPort = rsp.upPort
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class TryUpPicData(
|
||||
val uKey: ByteArray,
|
||||
val exist: Boolean,
|
||||
val fileId: ULong,
|
||||
var upIp: ArrayList<Long>? = null,
|
||||
var upPort: ArrayList<Int>? = null,
|
||||
)
|
||||
}
|
@ -10,6 +10,7 @@ import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.transfile.NtV2RichMediaSvc.getNtPicRKey
|
||||
import moe.fuqiuluo.shamrock.helper.ContactHelper
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
@ -53,8 +54,6 @@ private const val MULTIMEDIA_DOMAIN = "multimedia.nt.qq.com.cn"
|
||||
private const val C2C_PIC = "c2cpicdw.qpic.cn"
|
||||
|
||||
internal object RichProtoSvc: BaseSvc() {
|
||||
private val requestId = atomic(2L)
|
||||
|
||||
suspend fun getGuildFileDownUrl(peerId: String, channelId: String, fileId: String, bizId: Int): String {
|
||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0xfc2_0", 4034, 0, Oidb0xfc2ReqBody(
|
||||
msgCmd = 1200,
|
||||
@ -279,81 +278,6 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
return "https://$domain/qmeetpic/0/0-0-${md5.uppercase()}/0?term=2"
|
||||
}
|
||||
|
||||
suspend fun getNtPicRKey(
|
||||
fileId: String,
|
||||
md5: String,
|
||||
sha: String,
|
||||
fileSize: ULong,
|
||||
width: UInt,
|
||||
height: UInt,
|
||||
sceneBuilder: suspend SceneInfo.() -> Unit
|
||||
): Result<String> {
|
||||
runCatching {
|
||||
val req = run {
|
||||
NtV2RichMediaReq(
|
||||
head = MultiMediaReqHead(
|
||||
commonHead = CommonHead(
|
||||
requestId = requestId.incrementAndGet().toULong(),
|
||||
cmd = 200u
|
||||
),
|
||||
sceneInfo = SceneInfo(
|
||||
requestType = 2u,
|
||||
businessType = 1u,
|
||||
).apply {
|
||||
sceneBuilder()
|
||||
},
|
||||
clientMeta = ClientMeta(2u)
|
||||
),
|
||||
download = DownloadReq(
|
||||
IndexNode(
|
||||
FileInfo(
|
||||
fileSize = fileSize,
|
||||
md5 = md5.lowercase(),
|
||||
sha1 = sha.lowercase(),
|
||||
name = "${md5}.jpg",
|
||||
fileType = FileType(
|
||||
fileType = 1u,
|
||||
picFormat = 1000u,
|
||||
videoFormat = 0u,
|
||||
voiceFormat = 0u
|
||||
),
|
||||
width = width,
|
||||
height = height,
|
||||
time = 0u,
|
||||
original = 1u
|
||||
),
|
||||
fileUuid = fileId,
|
||||
storeId = 1u,
|
||||
uploadTime = 0u,
|
||||
ttl = 0u,
|
||||
subType = 0u,
|
||||
storeAppId = 0u
|
||||
),
|
||||
DownloadExt(
|
||||
video = VideoDownloadExt(
|
||||
busiType = 0u,
|
||||
subBusiType = 0u,
|
||||
msgCodecConfig = CodecConfigReq(
|
||||
platformChipinfo = "",
|
||||
osVer = "",
|
||||
deviceName = ""
|
||||
),
|
||||
flag = 1u
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}.toByteArray()
|
||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_200", 4549, 200, req, true)?.slice(4)
|
||||
buffer?.decodeProtobuf<TrpcOidb>()?.buffer?.decodeProtobuf<NtV2RichMediaRsp>()?.download?.rkeyParam?.let {
|
||||
return Result.success(it)
|
||||
}
|
||||
}.onFailure {
|
||||
return Result.failure(it)
|
||||
}
|
||||
return Result.failure(Exception("unable to get c2c nt pic"))
|
||||
}
|
||||
|
||||
suspend fun getC2CVideoDownUrl(
|
||||
peerId: String,
|
||||
md5: ByteArray,
|
||||
|
@ -1,6 +1,8 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.transfile
|
||||
|
||||
import com.tencent.mobileqq.data.MessageForPic
|
||||
import com.tencent.mobileqq.data.MessageForShortVideo
|
||||
import com.tencent.mobileqq.data.MessageRecord
|
||||
import com.tencent.mobileqq.transfile.FileMsg
|
||||
import com.tencent.mobileqq.transfile.TransferRequest
|
||||
import moe.fuqiuluo.shamrock.utils.MD5
|
||||
@ -11,16 +13,15 @@ import moe.fuqiuluo.shamrock.helper.TransfileHelper
|
||||
internal object Transfer: FileTransfer() {
|
||||
private val ROUTE = mapOf<ContactType, Map<ResourceType, suspend TransTarget.(Resource) -> Boolean>>(
|
||||
ContactType.TROOP to mapOf(
|
||||
Picture to { uploadGroupPic(id, (it as PictureResource).src) },
|
||||
Picture to { uploadGroupPic(id, (it as PictureResource).src, mRec) },
|
||||
Voice to { uploadGroupVoice(id, (it as VoiceResource).src) },
|
||||
Video to { uploadGroupVideo(id, (it as VideoResource).src, it.thumb) },
|
||||
|
||||
),
|
||||
ContactType.PRIVATE to mapOf(
|
||||
Picture to { uploadC2CPic(id, (it as PictureResource).src) },
|
||||
Picture to { uploadC2CPic(id, (it as PictureResource).src, mRec) },
|
||||
Voice to { uploadC2CVoice(id, (it as VoiceResource).src) },
|
||||
Video to { uploadC2CVideo(id, (it as VideoResource).src, it.thumb) },
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
@ -83,6 +84,7 @@ internal object Transfer: FileTransfer() {
|
||||
suspend fun uploadC2CPic(
|
||||
peerId: String,
|
||||
file: File,
|
||||
record: MessageRecord? = null,
|
||||
wait: Boolean = true
|
||||
): Boolean {
|
||||
return transC2CResource(peerId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_CAMERA, wait) {
|
||||
@ -93,22 +95,24 @@ internal object Transfer: FileTransfer() {
|
||||
it.mExtraObj = picUpExtraInfo
|
||||
it.mIsPresend = true
|
||||
it.delayShowProgressTimeInMs = 2000
|
||||
it.mRec = record
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun uploadGroupPic(
|
||||
groupId: String,
|
||||
file: File,
|
||||
record: MessageRecord? = null,
|
||||
wait: Boolean = true
|
||||
): Boolean {
|
||||
return transTroopResource(groupId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_CAMERA, wait) {
|
||||
val picUpExtraInfo = TransferRequest.PicUpExtraInfo()
|
||||
//picUpExtraInfo.mIsRaw = !TransfileHelper.isGifFile(file)
|
||||
picUpExtraInfo.mIsRaw = false
|
||||
picUpExtraInfo.mUinType = FileMsg.UIN_TROOP
|
||||
it.mPicSendSource = 8
|
||||
it.delayShowProgressTimeInMs = 2000
|
||||
it.mExtraObj = picUpExtraInfo
|
||||
it.mRec = record
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.maker.MessageElementMaker
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.maker.MsgElementMaker
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.maker.NtMsgElementMaker
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageMapping
|
||||
import moe.fuqiuluo.shamrock.remote.structures.SendMsgResult
|
||||
@ -29,6 +29,7 @@ import moe.fuqiuluo.shamrock.tools.jsonArray
|
||||
import protobuf.message.Elem
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.math.abs
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
internal object MessageHelper {
|
||||
suspend fun sendMessageWithoutMsgId(
|
||||
@ -66,12 +67,15 @@ internal object MessageHelper {
|
||||
suspend fun resendMsg(contact: Contact, msgId: Long, retryCnt: Int, msgHashId: Int): Result<SendMsgResult> {
|
||||
if (retryCnt < 0) return Result.failure(SendMsgException("消息发送超时次数过多"))
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
val result = withTimeoutOrNull(15000) {
|
||||
if (suspendCancellableCoroutine {
|
||||
service.resendMsg(contact, msgId) { result, _ ->
|
||||
it.resume(result)
|
||||
}
|
||||
} != 0) {
|
||||
val result = withTimeoutOrNull(15.seconds) {
|
||||
val resendRet = suspendCancellableCoroutine {
|
||||
service.resendMsg(contact, msgId) { result, _ ->
|
||||
it.resume(result)
|
||||
}
|
||||
}
|
||||
if (resendRet != 0 &&
|
||||
resendRet != 4 // 使用OldBDH 100%触发
|
||||
) {
|
||||
resendMsg(contact, msgId, retryCnt - 1, msgHashId)
|
||||
} else {
|
||||
Result.success(SendMsgResult(msgHashId, msgId, System.currentTimeMillis()))
|
||||
@ -294,7 +298,7 @@ internal object MessageHelper {
|
||||
var hasActionMsg = false
|
||||
messageList.forEach {
|
||||
val msg = it.jsonObject
|
||||
val maker = MsgElementMaker[msg["type"].asString]
|
||||
val maker = NtMsgElementMaker[msg["type"].asString]
|
||||
if (maker != null) {
|
||||
try {
|
||||
val data = msg["data"].asJsonObjectOrNull ?: EmptyJsonObject
|
||||
|
@ -15,13 +15,13 @@ internal object SendGroupMessage: IActionHandler() {
|
||||
return if (session.isString("message")) {
|
||||
val autoEscape = session.getBooleanOrDefault("auto_escape", false)
|
||||
val message = session.getString("message")
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, autoEscape, echo = session.echo, retryCnt = retryCnt ?: 3, recallDuration = recallDuration)
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, autoEscape, echo = session.echo, retryCnt = retryCnt ?: 5, recallDuration = recallDuration)
|
||||
} else if (session.isObject("message")) {
|
||||
val message = session.getObject("message")
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), listOf( message ).jsonArray, session.echo, retryCnt = retryCnt ?: 3, recallDuration = recallDuration)
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), listOf( message ).jsonArray, session.echo, retryCnt = retryCnt ?: 5, recallDuration = recallDuration)
|
||||
} else {
|
||||
val message = session.getArray("message")
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, session.echo, retryCnt = retryCnt ?: 3, recallDuration = recallDuration)
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, session.echo, retryCnt = retryCnt ?: 5, recallDuration = recallDuration)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,13 +55,13 @@ internal object SendMessage: IActionHandler() {
|
||||
return if (session.isString("message")) {
|
||||
val autoEscape = session.getBooleanOrDefault("auto_escape", false)
|
||||
val message = session.getString("message")
|
||||
invoke(chatType, peerId, message, autoEscape, echo = session.echo, fromId = fromId, retryCnt = retryCnt ?: 3, recallDuration = recallDuration)
|
||||
invoke(chatType, peerId, message, autoEscape, echo = session.echo, fromId = fromId, retryCnt = retryCnt ?: 5, recallDuration = recallDuration)
|
||||
} else if (session.isArray("message")) {
|
||||
val message = session.getArray("message")
|
||||
invoke(chatType, peerId, message, session.echo, fromId = fromId, retryCnt ?: 3, recallDuration = recallDuration)
|
||||
invoke(chatType, peerId, message, session.echo, fromId = fromId, retryCnt ?: 5, recallDuration = recallDuration)
|
||||
} else {
|
||||
val message = session.getObject("message")
|
||||
invoke(chatType, peerId, listOf( message ).jsonArray, session.echo, fromId = fromId, retryCnt ?: 3, recallDuration = recallDuration)
|
||||
invoke(chatType, peerId, listOf( message ).jsonArray, session.echo, fromId = fromId, retryCnt ?: 5, recallDuration = recallDuration)
|
||||
}
|
||||
} catch (e: ParamsException) {
|
||||
return noParam(e.message!!, session.echo)
|
||||
|
@ -1,10 +1,12 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
import protobuf.auto.toByteArray
|
||||
import protobuf.message.*
|
||||
@ -21,8 +23,13 @@ internal object SendMsgByResid : IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val resid = session.getString("resid")
|
||||
val peerId = session.getString("peer")
|
||||
val msgType = session.getStringOrNull("message_type") ?: "group"
|
||||
return invoke(peerId, resid, msgType, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(peerId: String, resId: String, type: String, echo: JsonElement = EmptyJsonString): String {
|
||||
val req = PbSendMsgReq(
|
||||
routingHead = when (session.getStringOrNull("message_type")) {
|
||||
routingHead = when (type) {
|
||||
"group" ->RoutingHead(grp = Grp(peerId.toUInt()))
|
||||
"private" ->RoutingHead( c2c = C2C(peerId.toUInt()))
|
||||
else ->RoutingHead( grp = Grp(peerId.toUInt()))
|
||||
@ -34,7 +41,7 @@ internal object SendMsgByResid : IActionHandler() {
|
||||
Elem(
|
||||
generalFlags = GeneralFlags(
|
||||
longTextFlag = 1u,
|
||||
longTextResid = resid.toByteArray()
|
||||
longTextResid = resId.toByteArray()
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -45,6 +52,6 @@ internal object SendMsgByResid : IActionHandler() {
|
||||
msgVia = 0u
|
||||
)
|
||||
BaseSvc.sendBufferAW("MessageSvc.PbSendMsg", true, req.toByteArray())
|
||||
return ok("ok", session.echo)
|
||||
return ok("ok", echo)
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ internal object SendPrivateMessage : IActionHandler() {
|
||||
autoEscape = autoEscape,
|
||||
echo = session.echo,
|
||||
fromId = groupId?.toString() ?: userId.toString(),
|
||||
retryCnt = retryCnt ?: 3,
|
||||
retryCnt = retryCnt ?: 5,
|
||||
recallDuration = recallDuration
|
||||
)
|
||||
} else {
|
||||
@ -34,7 +34,7 @@ internal object SendPrivateMessage : IActionHandler() {
|
||||
message = if (session.isArray("message")) session.getArray("message") else listOf(session.getObject("message")).jsonArray,
|
||||
echo = session.echo,
|
||||
fromId = groupId?.toString() ?: userId.toString(),
|
||||
retryCnt = retryCnt ?: 3,
|
||||
retryCnt = retryCnt ?: 5,
|
||||
recallDuration = recallDuration
|
||||
)
|
||||
}
|
||||
|
@ -117,6 +117,8 @@ internal class XposedEntry: IXposedHookLoadPackage {
|
||||
}
|
||||
|
||||
private fun execStartupInit(ctx: Context) {
|
||||
log("Shamrock: Executing startup init: $ctx")
|
||||
|
||||
if (sec_static_stage_inited) return
|
||||
|
||||
val classLoader = ctx.classLoader.also { requireNotNull(it) }
|
||||
|
Loading…
x
Reference in New Issue
Block a user