Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ packages
.DS_Store
Aweme
Makefile.local
.vscode/
4 changes: 4 additions & 0 deletions AwemeHeaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ typedef NS_ENUM(NSUInteger, DYEdgeMode) {
- (void)buttonTouchUp:(id)sender;
@end

@interface HTSLiveRoomStatsMessage : NSObject
- (NSInteger)displayValue;
@end

@interface AWEFeedVideoButton : UIButton
@end

Expand Down
209 changes: 209 additions & 0 deletions DYYY.xm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import <float.h>
#import <math.h>
#import <objc/runtime.h>
#import <substrate.h>

#import "AwemeHeaders.h"
#import "CityManager.h"
Expand Down Expand Up @@ -362,6 +363,202 @@ static BOOL DYYYShouldHandleSpeedFeatures(void) {

%end

// 直播间真实人数

static NSString *(*orig_displayShort)(id, SEL);
static NSString *my_displayShort(id self, SEL _cmd) {
if (!DYYYGetBool(@"DYYYEnableLiveRealCount")) return orig_displayShort(self, _cmd);
if ([self respondsToSelector:@selector(displayValue)]) {
NSInteger count = (NSInteger)[self performSelector:@selector(displayValue)];
if (count > 0) return [NSString stringWithFormat:@"%ld", (long)count];
}
return orig_displayShort(self, _cmd);
}

static NSString *(*orig_displayMiddle)(id, SEL);
static NSString *my_displayMiddle(id self, SEL _cmd) {
if (!DYYYGetBool(@"DYYYEnableLiveRealCount")) return orig_displayMiddle(self, _cmd);
if ([self respondsToSelector:@selector(displayValue)]) {
NSInteger count = (NSInteger)[self performSelector:@selector(displayValue)];
if (count > 0) return [NSString stringWithFormat:@"%ld", (long)count];
}
return orig_displayMiddle(self, _cmd);
}

static NSString *(*orig_displayLong)(id, SEL);
static NSString *my_displayLong(id self, SEL _cmd) {
if (!DYYYGetBool(@"DYYYEnableLiveRealCount")) return orig_displayLong(self, _cmd);
if ([self respondsToSelector:@selector(displayValue)]) {
NSInteger count = (NSInteger)[self performSelector:@selector(displayValue)];
if (count > 0) return [NSString stringWithFormat:@"%ld在线观众", (long)count];
}
return orig_displayLong(self, _cmd);
}

// 评论具体时间
%hook AWEDateTimeFormatter

+ (id)formattedDateForTimestamp:(double)timestamp {
if (!DYYYGetBool(@"DYYYCommentExactTime")) return %orig(timestamp);
return [NSString stringWithFormat:@"%.0f ", timestamp];
}

%end

%hook AWERLVirtualLabel

- (void)setText:(NSString *)text {
if (!DYYYGetBool(@"DYYYCommentExactTime") || !text || text.length == 0) {
%orig(text);
return;
}

if ([text isEqualToString:@"回复"]) {
%orig(@"");
return;
}

NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\d{10,13})([\\s\\S]*)" options:0 error:&error];

NSTextCheckingResult *match = [regex firstMatchInString:text options:0 range:NSMakeRange(0, text.length)];

if (match) {
NSString *rawTs = [text substringWithRange:[match rangeAtIndex:1]];
NSString *suffix = [text substringWithRange:[match rangeAtIndex:2]];

long long ts = [rawTs longLongValue];

if (ts > 100000000000) {
ts = ts / 1000;
}

NSDate *date = [NSDate dateWithTimeIntervalSince1970:ts];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *formattedDate = [formatter stringFromDate:date];

NSString *newText = [NSString stringWithFormat:@"%@%@", formattedDate, suffix];
%orig(newText);
} else {
%orig(text);
}
}

%end

%group DYYYCommentExactTimeGroup
%hook AWECommentSwiftBizUI_CommentInteractionBaseLabel

- (void)setText:(NSString *)text {
%orig(text); // 先让系统把文本赋上去

if (!DYYYGetBool(@"DYYYCommentExactTime")) {
return;
}

UILabel *label = (UILabel *)self;
if (!text || text.length == 0) return;

// --- 1. 拦截翻译文本,将其绝对定位在屏幕右侧 100 像素 ---
if ([text isEqualToString:@"翻译"] || [text isEqualToString:@"隐藏翻译"]) {
CGRect currentFrame = label.frame;
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
// 重新计算 X 坐标:屏幕宽度 - 100 - 标签自身宽度
currentFrame.origin.x = screenWidth - 100.0 - currentFrame.size.width;
label.frame = currentFrame;
return;
}

// --- 2. 拦截时间文本,如果不够宽则扩充宽度 ---
UIFont *font = label.font;
if (font) {
CGFloat expectedWidth = ceilf([text sizeWithAttributes:@{NSFontAttributeName: font}].width);
CGRect currentFrame = label.frame;

// 如果当前宽度不够,并且不是尚未初始化的状态(>0),则强行修改并重新赋值
if (currentFrame.size.width < expectedWidth && currentFrame.size.width > 0) {
currentFrame.size.width = expectedWidth;
label.frame = currentFrame;
label.clipsToBounds = NO;
}
}
}

- (void)setFrame:(CGRect)frame {
if (!DYYYGetBool(@"DYYYCommentExactTime") || ![self respondsToSelector:@selector(text)]) {
%orig(frame);
return;
}

UILabel *label = (UILabel *)self;
NSString *text = label.text;

if (text && text.length > 0) {
// --- 1. 拦截翻译文本,将其绝对定位在屏幕右侧 100 像素 ---
if ([text isEqualToString:@"翻译"] || [text isEqualToString:@"隐藏翻译"]) {
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
frame.origin.x = screenWidth - 100.0 - frame.size.width;
}
// --- 2. 拦截时间文本,如果不够宽则扩充宽度 ---
else if ([self respondsToSelector:@selector(font)]) {
UIFont *font = label.font;
if (font) {
CGFloat expectedWidth = ceilf([text sizeWithAttributes:@{NSFontAttributeName: font}].width);
if (frame.size.width < expectedWidth && frame.size.width > 0) {
frame.size.width = expectedWidth;
label.clipsToBounds = NO;
}
}
}
}

%orig(frame);
}

%end
%end

// 前面的AWEDateTimeFormatter会导致图文视频展开时间文本变成时间戳,这里处理下
%hook YYLabel

// 1. Hook 富文本赋值方法 (核心)
- (void)setAttributedText:(NSAttributedString *)attributedText {
if (!DYYYGetBool(@"DYYYCommentExactTime") || !attributedText || attributedText.length == 0) {
%orig(attributedText);
return;
}

NSString *plainText = [attributedText string];

NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\d{10,13})" options:0 error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:plainText options:0 range:NSMakeRange(0, plainText.length)];

if (match) {
NSString *rawTs = [plainText substringWithRange:[match rangeAtIndex:1]];
long long ts = [rawTs longLongValue];

if (ts > 100000000000) {
ts = ts / 1000;
}

NSDate *date = [NSDate dateWithTimeIntervalSince1970:ts];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *formattedDate = [formatter stringFromDate:date];

NSMutableAttributedString *newAttrStr = [attributedText mutableCopy];
[newAttrStr replaceCharactersInRange:[match rangeAtIndex:1] withString:formattedDate];

%orig(newAttrStr);
} else {
%orig(attributedText);
}
}

%end

// 禁用自动进入直播间
%hook AWELiveGuideElement

Expand Down Expand Up @@ -8508,6 +8705,18 @@ static void findTargetViewInView(UIView *view) {
}

%ctor {
Class interactionBaseLabelClass = objc_getClass("AWECommentSwiftBizUI.CommentInteractionBaseLabel");
if (interactionBaseLabelClass) {
%init(DYYYCommentExactTimeGroup, AWECommentSwiftBizUI_CommentInteractionBaseLabel = interactionBaseLabelClass);
}

Class statsMessageClass = objc_getClass("HTSLiveRoomStatsMessage");
if (statsMessageClass) {
MSHookMessageEx(statsMessageClass, @selector(displayShort), (IMP)&my_displayShort, (IMP *)&orig_displayShort);
MSHookMessageEx(statsMessageClass, @selector(displayMiddle), (IMP)&my_displayMiddle, (IMP *)&orig_displayMiddle);
MSHookMessageEx(statsMessageClass, @selector(displayLong), (IMP)&my_displayLong, (IMP *)&orig_displayLong);
}

Class imMenuComponentClass = objc_getClass("AWEIMCustomMenuComponent");
if (imMenuComponentClass) {
SEL legacySelector = NSSelectorFromString(@"msg_showMenuForBubbleFrameInScreen:tapLocationInScreen:menuItemList:moreEmoticon:onCell:extra:");
Expand Down
13 changes: 13 additions & 0 deletions DYYYSettings.xm
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,19 @@ void showDYYYSettingsVC(UIViewController *rootVC, BOOL hasAgreed) {
@"detail" : @"自动",
@"cellType" : @26,
@"imageName" : @"ic_video_outlined_20"},
@{@"identifier" : @"DYYYEnableLiveRealCount",
@"title" : @"直播真实人数",
@"subTitle" : @"直播显示具体的在线人数",
@"detail" : @"",
@"cellType" : @37,
@"imageName" : @"ic_video_outlined_20"},

@{@"identifier" : @"DYYYCommentExactTime",
@"title" : @"评论具体时间",
@"subTitle" : @"开启后评论区将显示具体的发布时间而非相对时间",
@"detail" : @"",
@"cellType" : @37,
@"imageName" : @"ic_clock_outlined_20"},
@{@"identifier" : @"DYYYEnableVideoHighestQuality",
@"title" : @"提高视频画质",
@"detail" : @"",
Expand Down
Loading