@@ -85,6 +85,10 @@
|
|||||||
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
</assemblyBinding>
|
</assemblyBinding>
|
||||||
</runtime>
|
</runtime>
|
||||||
<startup>
|
<startup>
|
||||||
|
|||||||
+73
-1
@@ -5,6 +5,7 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BarrageGrab.Modles;
|
using BarrageGrab.Modles;
|
||||||
|
using BarrageGrab.Modles.ProtoEntity;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Org.BouncyCastle.Asn1.Cmp;
|
using Org.BouncyCastle.Asn1.Cmp;
|
||||||
using Org.BouncyCastle.Asn1.Crmf;
|
using Org.BouncyCastle.Asn1.Crmf;
|
||||||
@@ -53,7 +54,78 @@ namespace BarrageGrab
|
|||||||
{
|
{
|
||||||
Logger.LogError($"礼物信息从服务器请求失败: {ex.Message}");
|
Logger.LogError($"礼物信息从服务器请求失败: {ex.Message}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取房间信息,通过原生接口
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="webRoomid">web直播间号</param>
|
||||||
|
/// <param name="user">账号凭据</param>
|
||||||
|
/// <param name="proxy">查询代理</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<RoomInfo> GetRoomInfoForApi(string webRoomid, string cookie)
|
||||||
|
{
|
||||||
|
string url = "https://live.douyin.com/webcast/room/web/enter/";
|
||||||
|
|
||||||
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
|
||||||
|
var uri = new UriBuilder(url);
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
dict.Set("aid", "6383");
|
||||||
|
dict.Set("live_id", "1");
|
||||||
|
dict.Set("app_name", "douyin_web");
|
||||||
|
dict.Set("device_platform", "web");
|
||||||
|
dict.Set("language", "zh-CN");
|
||||||
|
dict.Set("cookie_enabled", "true");
|
||||||
|
dict.Set("enter_from", "page_refresh");
|
||||||
|
dict.Set("web_rid", webRoomid);
|
||||||
|
//dict.Set("room_id_str", roomid);
|
||||||
|
dict.Set("enter_source", "");
|
||||||
|
dict.Set("is_need_double_stream", "false");
|
||||||
|
dict.Set("insert_task_id", "");
|
||||||
|
dict.Set("live_reason", "");
|
||||||
|
dict.Set("browser_language", "zh-CN");
|
||||||
|
dict.Set("browser_platform", "Win32");
|
||||||
|
dict.Set("browser_name", "Edge");
|
||||||
|
dict.Foreach(f => uri.AddQueryParam(f.Key, f.Value));
|
||||||
|
|
||||||
|
url = uri.Uri.ToString();
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
request.Headers.Add("Accept", "application/json, text/plain, */*");
|
||||||
|
request.Headers.Add("Cache-Control", "no-cache");
|
||||||
|
request.Headers.Add("Referer", $"https://live.douyin.com/{webRoomid}");
|
||||||
|
request.Headers.Add("Host", "live.douyin.com");
|
||||||
|
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0");
|
||||||
|
request.Headers.Add("Cookie", cookie);
|
||||||
|
|
||||||
|
var rsp = await client.SendAsync(request);
|
||||||
|
if (rsp == null || rsp.StatusCode != System.Net.HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buff = rsp.Content.ReadAsByteArrayAsync();
|
||||||
|
var result = Encoding.UTF8.GetString(buff.Result);
|
||||||
|
RoomInfo dto;
|
||||||
|
var res = RoomInfo.TryParseRoomEnterResponse(result, out dto);
|
||||||
|
int code = res.Item1;
|
||||||
|
string msg = res.Item2;
|
||||||
|
if (code == 0)
|
||||||
|
{
|
||||||
|
dto.LiveUrl = $"https://live.douyin.com/{webRoomid}";
|
||||||
|
dto.WebRoomId = webRoomid;
|
||||||
|
AppRuntime.RoomCaches.AddRoomInfoCache(dto);
|
||||||
|
Logger.LogInfo($"{dto.Owner.Nickname ?? dto.WebRoomId ?? dto.RoomId} 的直播间信息已添加到缓存");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+108
-18
@@ -9,6 +9,10 @@ using System.Threading.Tasks;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using IWshRuntimeLibrary;
|
using IWshRuntimeLibrary;
|
||||||
using File = System.IO.File;
|
using File = System.IO.File;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
|
|
||||||
namespace BarrageGrab
|
namespace BarrageGrab
|
||||||
{
|
{
|
||||||
@@ -20,36 +24,122 @@ namespace BarrageGrab
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetExePath()
|
public static string GetExePath()
|
||||||
{
|
{
|
||||||
|
string appName = "直播伴侣";
|
||||||
|
appName = Path.GetFileNameWithoutExtension(appName);
|
||||||
string exePath = "";
|
string exePath = "";
|
||||||
//获取exe所在目录
|
|
||||||
//1.先在开始菜单找
|
//从卸载列表中查找
|
||||||
var shortcutPath = @"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\直播伴侣.lnk";
|
try
|
||||||
if (File.Exists(shortcutPath))
|
|
||||||
{
|
{
|
||||||
//获取快捷方式的目标路径
|
// 打开注册表中的卸载信息节点
|
||||||
exePath = GetInkTargetPath(shortcutPath);
|
RegistryKey uninstallNode = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
|
||||||
if (!File.Exists(exePath))
|
|
||||||
|
if (uninstallNode != null)
|
||||||
{
|
{
|
||||||
exePath = "";
|
// 遍历所有的子键(每个子键代表一个已安装的程序的卸载信息)
|
||||||
Logger.LogWarn($"直播伴侣.lnk 所指向的exe文件位置 {exePath} 无效");
|
foreach (string subKeyName in uninstallNode.GetSubKeyNames())
|
||||||
|
{
|
||||||
|
RegistryKey subKey = uninstallNode.OpenSubKey(subKeyName);
|
||||||
|
var displayName = subKey?.GetValue("DisplayName")?.ToString() ?? "";
|
||||||
|
|
||||||
|
if (!displayName.Contains(appName)) continue;
|
||||||
|
string uninstallString = subKey?.GetValue("UninstallString")?.ToString();
|
||||||
|
if (uninstallString.IsNullOrWhiteSpace()) continue;
|
||||||
|
|
||||||
|
//"D:\Program Files (x86)\webcast_mate\Uninstall 直播伴侣.exe" /allusers
|
||||||
|
//正则取出""中间的内容
|
||||||
|
var match = Regex.Match(uninstallString, "\"(.+?)\"");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
string uninstallPath = match.Groups[1].Value;
|
||||||
|
string dir = Path.GetDirectoryName(uninstallPath);
|
||||||
|
string exe = Path.Combine(dir, $"{appName}.exe");
|
||||||
|
if (File.Exists(exe))
|
||||||
|
{
|
||||||
|
exePath = exe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogInfo("未找到直播伴侣的桌面快捷方式");
|
// 发生异常时,可能是注册表访问出错,记录错误信息
|
||||||
|
Logger.LogError(ex, $"Error checking for Live Companion installation path: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
//再从配置文件读取
|
//从 C:\ProgramData\Microsoft\Windows\Start Menu\Programs 中查找
|
||||||
if (exePath.IsNullOrWhiteSpace())
|
string startMenuPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu), "Programs");
|
||||||
|
var findFiles = Directory.GetFiles(startMenuPath, $"{appName}.lnk", SearchOption.AllDirectories);
|
||||||
|
if (findFiles.Length > 0)
|
||||||
{
|
{
|
||||||
exePath = AppSetting.Current.LiveCompanPath;
|
exePath = GetShortcutTarget(findFiles[0]);
|
||||||
if(!exePath.IsNullOrWhiteSpace() && !File.Exists(exePath))
|
}
|
||||||
|
|
||||||
|
var fileName = Path.GetFileName(exePath);
|
||||||
|
|
||||||
|
//判断是否是 版本选择器
|
||||||
|
if (fileName.Contains("Launcher"))
|
||||||
|
{
|
||||||
|
var dir = Path.GetDirectoryName(exePath);
|
||||||
|
//读取目录下 launcher_config.json
|
||||||
|
var launcherConfigPath = Path.Combine(dir, "launcher_config.json");
|
||||||
|
if (!File.Exists(launcherConfigPath))
|
||||||
{
|
{
|
||||||
Logger.LogWarn($"所配置的 {exePath} 不存在");
|
throw new Exception("未找到直播伴侣版本选择器的 launcher_config.json 文件");
|
||||||
exePath = "";
|
}
|
||||||
|
var json = File.ReadAllText(launcherConfigPath, Encoding.UTF8);
|
||||||
|
var jobj = JsonConvert.DeserializeObject<dynamic>(json);
|
||||||
|
string curPath = jobj.cur_path;
|
||||||
|
exePath = Path.Combine(dir, curPath, "直播伴侣.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有找到相关信息,则返回空字符串
|
||||||
|
return exePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 .lnk 文件的目标路径
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="shortcutPath">快捷方式文件路径</param>
|
||||||
|
/// <returns>目标路径</returns>
|
||||||
|
private static string GetShortcutTarget(string shortcutPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(shortcutPath))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("快捷方式路径不能为空", nameof(shortcutPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
var processStartInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "powershell",
|
||||||
|
Arguments = $"-command \"$WshShell = New-Object -ComObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut('{shortcutPath}'); $Shortcut.TargetPath\"",
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var process = Process.Start(processStartInfo))
|
||||||
|
{
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("无法启动 PowerShell 进程");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var reader = process.StandardOutput)
|
||||||
|
{
|
||||||
|
string result = reader.ReadToEnd();
|
||||||
|
process.WaitForExit();
|
||||||
|
return result.Trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return exePath;
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"powershell 获取快捷方式目标路径失败,错误信息:{ex.Message}", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -53,6 +53,15 @@ namespace BarrageGrab.Modles.JsonEntity
|
|||||||
抖音好友 = 112
|
抖音好友 = 112
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 观众的进入方式
|
||||||
|
/// </summary>
|
||||||
|
public enum EnterType
|
||||||
|
{
|
||||||
|
正常进入 = 0,
|
||||||
|
通过分享进入 = 6,
|
||||||
|
//...其他暂时未知
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据包装器
|
/// 数据包装器
|
||||||
@@ -121,6 +130,11 @@ namespace BarrageGrab.Modles.JsonEntity
|
|||||||
/// web直播间ID
|
/// web直播间ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string WebRoomId { get; set; }
|
public string WebRoomId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户使用的 Appid ,已知 1128,8663,2329 等
|
||||||
|
/// </summary>
|
||||||
|
public string Appid { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -180,6 +194,16 @@ namespace BarrageGrab.Modles.JsonEntity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public long Id { get; set; }
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是直播间管理员
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAdmin { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是主播自己
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAnchor { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ShortId
|
/// ShortId
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -365,6 +389,11 @@ namespace BarrageGrab.Modles.JsonEntity
|
|||||||
/// 当前直播间人数
|
/// 当前直播间人数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long CurrentCount { get; set; }
|
public long CurrentCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 直播间进入方式,目前已知 0 正常进入,6 通过分享进入
|
||||||
|
/// </summary>
|
||||||
|
public long EnterTipType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -476,6 +476,12 @@ namespace BarrageGrab.Modles.ProtoEntity
|
|||||||
[global::ProtoBuf.ProtoMember(19)]
|
[global::ProtoBuf.ProtoMember(19)]
|
||||||
public PublicAreaCommon publicAreaCommon { get; set; }
|
public PublicAreaCommon publicAreaCommon { get; set; }
|
||||||
|
|
||||||
|
[global::ProtoBuf.ProtoMember(20)]
|
||||||
|
public long userEnterTipType { get; set; }
|
||||||
|
|
||||||
|
[global::ProtoBuf.ProtoMember(21)]
|
||||||
|
public long anchorEnterTipType { get; set; }
|
||||||
|
|
||||||
[global::ProtoBuf.ProtoContract()]
|
[global::ProtoBuf.ProtoContract()]
|
||||||
public partial class EffectConfig : global::ProtoBuf.IExtensible
|
public partial class EffectConfig : global::ProtoBuf.IExtensible
|
||||||
{
|
{
|
||||||
@@ -638,6 +644,8 @@ namespace BarrageGrab.Modles.ProtoEntity
|
|||||||
[global::ProtoBuf.ProtoMember(18)]
|
[global::ProtoBuf.ProtoMember(18)]
|
||||||
public long processAtSeiTimeMs { get; set; }
|
public long processAtSeiTimeMs { get; set; }
|
||||||
|
|
||||||
|
[global::ProtoBuf.ProtoMember(24)]
|
||||||
|
public long appId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[global::ProtoBuf.ProtoContract()]
|
[global::ProtoBuf.ProtoContract()]
|
||||||
|
|||||||
@@ -87,6 +87,29 @@ namespace BarrageGrab.Modles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Ttwid { get; set; }
|
public string Ttwid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是匿名直播间
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAnonymous { get; set; }
|
||||||
|
|
||||||
|
public void SetData(JObject room)
|
||||||
|
{
|
||||||
|
this.RoomId = room["id_str"]?.ToString() ?? "";
|
||||||
|
this.AdminUserIds = room["admin_user_ids_str"]?.Values<string>().ToList() ?? new List<string>();
|
||||||
|
this.IsLive = room["status"]?.Value<int>() == 2;
|
||||||
|
this.IsAnonymous = room["live_room_mode"]?.Value<int>() == 1;
|
||||||
|
this.Title = room["title"]?.ToString() ?? "";
|
||||||
|
this.UserCount = long.Parse(room["room_view_stats"]?["display_value"]?.Value<string>() ?? "0");
|
||||||
|
this.TotalUserCount = room["room_view_stats"]?["total_user_str"]?.Value<string>() ?? "0";
|
||||||
|
this.LikeCount = room["like_count"]?.Value<long>() ?? 0;
|
||||||
|
//this.QrcodeUrl = rootData["qrcode_url"]?.ToString() ?? "";
|
||||||
|
this.AuthInfo = room["room_auth"]?.ToObject<RoomInfo.RoomAuth>();
|
||||||
|
this.Cover = room["cover"]?["url_list"]?.Values<string>().FirstOrDefault() ?? "";//下播情况下没有cover字段
|
||||||
|
|
||||||
|
this.AuthInfo = room["room_auth"]?.ToObject<RoomInfo.RoomAuth>();
|
||||||
|
this.Cover = room["cover"]?["url_list"]?.Values<string>().FirstOrDefault() ?? "";//下播情况下没有cover字段
|
||||||
|
}
|
||||||
|
|
||||||
public class RoomAnchor
|
public class RoomAnchor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -641,5 +664,58 @@ namespace BarrageGrab.Modles
|
|||||||
|
|
||||||
return Tuple.Create(0, "succ");
|
return Tuple.Create(0, "succ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 EnterRoom Response 转为房间信息对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
/// <param name="info"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Tuple<int, string> TryParseRoomEnterResponse(string response, out RoomInfo info)
|
||||||
|
{
|
||||||
|
info = null;
|
||||||
|
JObject res;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res = JsonConvert.DeserializeObject<JObject>(response);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return Tuple.Create(4, "不是合法的json格式");
|
||||||
|
}
|
||||||
|
if (res == null)
|
||||||
|
{
|
||||||
|
return Tuple.Create(1, "响应内容为空");
|
||||||
|
}
|
||||||
|
if (res["status_code"]?.Value<int>() != 0)
|
||||||
|
{
|
||||||
|
return Tuple.Create(2, (res["status_msg"]?.ToString() ?? "响应状态失败"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var roomInfos = res["data"]?["data"]?.Values<JToken>().ToArray();
|
||||||
|
if (roomInfos == null || roomInfos.Length == 0) return Tuple.Create(3, "房间信息列表为空");
|
||||||
|
var rootData = res["data"];
|
||||||
|
var room = roomInfos[0]?.ToObject<JObject>();
|
||||||
|
var roomOwner = rootData?["user"] ?? room?["owner"];
|
||||||
|
|
||||||
|
var dto = new RoomInfo();
|
||||||
|
dto.SetData(room);
|
||||||
|
dto.QrcodeUrl = rootData["qrcode_url"]?.ToString() ?? "";
|
||||||
|
if (roomOwner != null)
|
||||||
|
{
|
||||||
|
dto.Owner = new RoomInfo.RoomAnchor()
|
||||||
|
{
|
||||||
|
UserId = roomOwner["id_str"].ToString(),
|
||||||
|
Nickname = roomOwner["nickname"].ToString(),
|
||||||
|
SecUid = roomOwner["sec_uid"].ToString(),
|
||||||
|
HeadUrl = roomOwner["avatar_thumb"]["url_list"].Values<string>()?.FirstOrDefault() ?? "",
|
||||||
|
FollowStatus = roomOwner["follow_info"]["follow_status"].Value<int>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
info = dto;
|
||||||
|
return Tuple.Create(0, "succ");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,5 +319,44 @@ namespace BarrageGrab
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取Uri查询参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uri"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public static IDictionary<string, string> GetQueryParams(this Uri uri)
|
||||||
|
{
|
||||||
|
if (uri == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryParams = uri.Query.TrimStart('?');
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(queryParams))
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryParams
|
||||||
|
.Split('&')
|
||||||
|
.Select(param => param.Split('='))
|
||||||
|
.ToDictionary(
|
||||||
|
keyValuePair => Uri.UnescapeDataString(keyValuePair[0]),
|
||||||
|
keyValuePair => Uri.UnescapeDataString(keyValuePair.Length > 1 ? keyValuePair[1] : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取Uri查询参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uri"></param>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetQueryParam(this Uri uri, string key)
|
||||||
|
{
|
||||||
|
return uri.GetQueryParams().Where(w => w.Key == key).Select(s => s.Value).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,6 @@ using System.Runtime.InteropServices;
|
|||||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||||
//通过使用 "*",如下所示:
|
//通过使用 "*",如下所示:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("2.7.6.0")]
|
[assembly: AssemblyVersion("2.7.7")]
|
||||||
[assembly: AssemblyFileVersion("2.7.6.0")]
|
[assembly: AssemblyFileVersion("2.7.7")]
|
||||||
[assembly: NeutralResourcesLanguage("zh-CN")]
|
[assembly: NeutralResourcesLanguage("zh-CN")]
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using BrotliSharpLib;
|
using BrotliSharpLib;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Security.Policy;
|
||||||
|
using NLog.LayoutRenderers;
|
||||||
|
|
||||||
namespace BarrageGrab.Proxy
|
namespace BarrageGrab.Proxy
|
||||||
{
|
{
|
||||||
@@ -31,6 +34,7 @@ namespace BarrageGrab.Proxy
|
|||||||
ProxyServer proxyServer = null;
|
ProxyServer proxyServer = null;
|
||||||
ExplicitProxyEndPoint explicitEndPoint = null;
|
ExplicitProxyEndPoint explicitEndPoint = null;
|
||||||
ExternalProxy upStreamProxy = null;
|
ExternalProxy upStreamProxy = null;
|
||||||
|
List<string> rinfoRequestings = new List<string>();
|
||||||
|
|
||||||
const string SCRIPT_HOST = "lf-cdn-tos.bytescm.com";
|
const string SCRIPT_HOST = "lf-cdn-tos.bytescm.com";
|
||||||
const string LIVE_HOST = "live.douyin.com";
|
const string LIVE_HOST = "live.douyin.com";
|
||||||
@@ -39,6 +43,7 @@ namespace BarrageGrab.Proxy
|
|||||||
const string BARRAGE_POOL_PATH = "/webcast/im/fetch";
|
const string BARRAGE_POOL_PATH = "/webcast/im/fetch";
|
||||||
const string LIVE_SCRIPT_PATH = "/obj/static/webcast/douyin_live";
|
const string LIVE_SCRIPT_PATH = "/obj/static/webcast/douyin_live";
|
||||||
const string WEBCAST_AMEMV_HOST = "webcast.amemv.com";
|
const string WEBCAST_AMEMV_HOST = "webcast.amemv.com";
|
||||||
|
private readonly Regex webcastBarrageReg = new Regex(@"webcast\d+-ws-web-\w+\.(douyin|amemv)\.com");
|
||||||
|
|
||||||
public override string HttpUpstreamProxy { get { return proxyServer?.UpStreamHttpProxy?.ToString() ?? ""; } }
|
public override string HttpUpstreamProxy { get { return proxyServer?.UpStreamHttpProxy?.ToString() ?? ""; } }
|
||||||
|
|
||||||
@@ -97,6 +102,7 @@ namespace BarrageGrab.Proxy
|
|||||||
proxyServer.CertificateManager.TrustRootCertificate(true);
|
proxyServer.CertificateManager.TrustRootCertificate(true);
|
||||||
|
|
||||||
proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback;
|
proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback;
|
||||||
|
//proxyServer.BeforeRequest += ProxyServer_BeforeRequest;
|
||||||
proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
|
proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
|
||||||
//proxyServer.AfterResponse += ProxyServer_AfterResponse;
|
//proxyServer.AfterResponse += ProxyServer_AfterResponse;
|
||||||
|
|
||||||
@@ -189,7 +195,7 @@ namespace BarrageGrab.Proxy
|
|||||||
|
|
||||||
private bool CheckBrowser(string processName)
|
private bool CheckBrowser(string processName)
|
||||||
{
|
{
|
||||||
return AppSetting.Current.ProcessFilter.Contains(processName) && processName!="直播伴侣" && processName!= "douyin";
|
return AppSetting.Current.ProcessFilter.Contains(processName) && processName != "直播伴侣" && processName != "douyin";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
|
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
|
||||||
@@ -266,20 +272,55 @@ namespace BarrageGrab.Proxy
|
|||||||
var processid = e.HttpClient.ProcessId.Value;
|
var processid = e.HttpClient.ProcessId.Value;
|
||||||
var processName = base.GetProcessName(processid);
|
var processName = base.GetProcessName(processid);
|
||||||
var contentType = e.HttpClient.Response.ContentType ?? "";
|
var contentType = e.HttpClient.Response.ContentType ?? "";
|
||||||
|
var isLiveCompan = processName == "直播伴侣";
|
||||||
|
|
||||||
//ws 方式
|
//ws 方式
|
||||||
if (
|
if (
|
||||||
e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket &&
|
e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket &&
|
||||||
hostname.StartsWith("webcast")
|
webcastBarrageReg.IsMatch(uri)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
e.DataReceived += WebSocket_DataReceived;
|
e.DataReceived += WebSocket_DataReceived;
|
||||||
|
var urix = new Uri(uri);
|
||||||
|
var roomid = urix.GetQueryParam("room_id");
|
||||||
|
Logger.LogInfo($"订阅到新的弹幕流地址,roomid:{roomid}");
|
||||||
}
|
}
|
||||||
|
|
||||||
//轮询方式(当抖音ws连接断开后,客户端也会降级使用轮询模式获取弹幕)
|
//轮询方式(当抖音ws连接断开后,客户端也会降级使用轮询模式获取弹幕)
|
||||||
if (uri.Contains(BARRAGE_POOL_PATH) && contentType.Contains("application/protobuffer"))
|
if (uri.Contains(BARRAGE_POOL_PATH) && contentType.Contains("application/protobuffer"))
|
||||||
{
|
{
|
||||||
var payload = await e.GetResponseBody();
|
var payload = await e.GetResponseBody();
|
||||||
|
|
||||||
|
var referrer = e.HttpClient.Request.Headers.GetFirstHeader("Referer")?.Value;
|
||||||
|
//https://live.douyin.com/22404217360
|
||||||
|
|
||||||
|
//检查webroomid映射
|
||||||
|
if (!referrer.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
var webroomid = Regex.Match(referrer, @"(?<=live\.douyin\.com\/)\d+").Value;
|
||||||
|
var urix = new Uri(uri);
|
||||||
|
var roomid = urix.GetQueryParam("room_id");
|
||||||
|
var cookie = e.HttpClient.Request.Headers.GetFirstHeader("Cookie")?.Value;
|
||||||
|
|
||||||
|
var roomInfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(roomid);
|
||||||
|
if (roomInfo == null && cookie != null && !rinfoRequestings.Contains(webroomid))
|
||||||
|
{
|
||||||
|
lock (rinfoRequestings) rinfoRequestings.Add(webroomid);
|
||||||
|
//查询后会自动缓存
|
||||||
|
DyServer.GetRoomInfoForApi(webroomid, cookie).ContinueWith(t =>
|
||||||
|
{
|
||||||
|
var rinfo = t.Result;
|
||||||
|
//限制只尝试一次
|
||||||
|
if (rinfo != null)
|
||||||
|
{
|
||||||
|
lock (rinfoRequestings) rinfoRequestings.Remove(webroomid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
AppRuntime.RoomCaches.SetRoomCache(roomid, webroomid);
|
||||||
|
}
|
||||||
|
|
||||||
base.FireOnFetchResponse(new HttpResponseEventArgs()
|
base.FireOnFetchResponse(new HttpResponseEventArgs()
|
||||||
{
|
{
|
||||||
HttpClient = e.HttpClient,
|
HttpClient = e.HttpClient,
|
||||||
@@ -358,7 +399,7 @@ namespace BarrageGrab.Proxy
|
|||||||
|
|
||||||
if (code == 0)
|
if (code == 0)
|
||||||
{
|
{
|
||||||
Logger.LogInfo($"直播页{webrid}房间信息已采集到缓存");
|
Logger.LogInfo($"直播页{webrid} [{roominfo.Owner.Nickname}]的直播间,房间信息已采集到缓存");
|
||||||
roominfo.WebRoomId = webrid;
|
roominfo.WebRoomId = webrid;
|
||||||
roominfo.LiveUrl = url;
|
roominfo.LiveUrl = url;
|
||||||
AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
|
AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
|
||||||
@@ -565,6 +606,16 @@ namespace BarrageGrab.Proxy
|
|||||||
string hostname = e.HttpClient.Request.RequestUri.Host;
|
string hostname = e.HttpClient.Request.RequestUri.Host;
|
||||||
|
|
||||||
e.DecryptSsl = CheckHost(hostname);
|
e.DecryptSsl = CheckHost(hostname);
|
||||||
|
|
||||||
|
|
||||||
|
//ws 方式
|
||||||
|
//if (
|
||||||
|
// e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket &&
|
||||||
|
// webcastBarrageReg.IsMatch(url)
|
||||||
|
// )
|
||||||
|
//{
|
||||||
|
// e.HttpClient.Request.RequestUri = new Uri("wss:////localhost:8828");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
//检测域名白名单
|
//检测域名白名单
|
||||||
@@ -597,7 +648,7 @@ namespace BarrageGrab.Proxy
|
|||||||
var processid = args.HttpClient.ProcessId.Value;
|
var processid = args.HttpClient.ProcessId.Value;
|
||||||
|
|
||||||
List<byte> messageData = new List<byte>();
|
List<byte> messageData = new List<byte>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (var frame in args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count))
|
foreach (var frame in args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count))
|
||||||
|
|||||||
+111
-130
@@ -17,6 +17,9 @@ using BarrageGrab.Modles.JsonEntity;
|
|||||||
using BarrageGrab.Modles.ProtoEntity;
|
using BarrageGrab.Modles.ProtoEntity;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Dynamic;
|
||||||
|
using static BarrageGrab.Modles.ProtoEntity.Image;
|
||||||
|
using static BarrageGrab.Modles.WebCastGift;
|
||||||
|
|
||||||
namespace BarrageGrab
|
namespace BarrageGrab
|
||||||
{
|
{
|
||||||
@@ -36,8 +39,7 @@ namespace BarrageGrab
|
|||||||
Timer dieout = new Timer(10000);//离线客户端清理计时器
|
Timer dieout = new Timer(10000);//离线客户端清理计时器
|
||||||
Timer giftCountTimer = new Timer(10000);//礼物缓存清理计时器
|
Timer giftCountTimer = new Timer(10000);//礼物缓存清理计时器
|
||||||
WssBarrageGrab grab = new WssBarrageGrab();//弹幕解析器核心
|
WssBarrageGrab grab = new WssBarrageGrab();//弹幕解析器核心
|
||||||
AppSetting Appsetting = AppSetting.Current;//全局配置文件实例
|
AppSetting Appsetting = AppSetting.Current;//全局配置文件实例
|
||||||
WebCastGiftPack giftData = null; //礼物数据
|
|
||||||
static int printCount = 0; //控制台输出计数,用于判断清理控制台
|
static int printCount = 0; //控制台输出计数,用于判断清理控制台
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -91,39 +93,6 @@ namespace BarrageGrab
|
|||||||
this.socketServer = socket;
|
this.socketServer = socket;
|
||||||
//dieout.Start();
|
//dieout.Start();
|
||||||
giftCountTimer.Start();
|
giftCountTimer.Start();
|
||||||
|
|
||||||
InitGiftData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化礼物数据
|
|
||||||
private void InitGiftData()
|
|
||||||
{
|
|
||||||
var path = Path.Combine(AppContext.BaseDirectory, "LocalData", "gift.json");
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
var jsonData = File.ReadAllText(path);
|
|
||||||
this.giftData = JsonConvert.DeserializeObject<WebCastGiftPack>(jsonData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
//从服务器获取礼物数据
|
|
||||||
DyServer.GetGifts().ContinueWith(t =>
|
|
||||||
{
|
|
||||||
if (t.IsFaulted) return;
|
|
||||||
if (t.Result == null) return;
|
|
||||||
|
|
||||||
this.giftData = t.Result;
|
|
||||||
Logger.LogInfo("礼物数据下载成功");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//覆写本地数据
|
|
||||||
File.WriteAllText(path, t.Result.ToJson(true));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogWarn("缓存礼物数据到本地失败,"+ex.Message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//礼物缓存清理计时器回调
|
//礼物缓存清理计时器回调
|
||||||
@@ -197,13 +166,68 @@ namespace BarrageGrab
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//检查属性定义
|
||||||
|
private bool HasProperty(dynamic obj, string propertyName)
|
||||||
|
{
|
||||||
|
if (obj is ExpandoObject)
|
||||||
|
{
|
||||||
|
return ((IDictionary<string, object>)obj).ContainsKey(propertyName);
|
||||||
|
}
|
||||||
|
return obj.GetType().GetProperty(propertyName) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T CreateMsg<T>(dynamic msg) where T : Msg, new()
|
||||||
|
{
|
||||||
|
var roomid = msg.Common.roomId.ToString();
|
||||||
|
RoomInfo roomInfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(roomid);
|
||||||
|
|
||||||
|
//判断 Common 属性是否存在
|
||||||
|
var hasUser = HasProperty(msg, nameof(msg.User));
|
||||||
|
|
||||||
|
var enty = new T()
|
||||||
|
{
|
||||||
|
MsgId = msg.Common?.msgId,
|
||||||
|
RoomId = roomid,
|
||||||
|
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(roomid),
|
||||||
|
Appid = msg.Common.appId.ToString(),
|
||||||
|
User = hasUser ? GetUser(msg.User) : null,
|
||||||
|
};
|
||||||
|
|
||||||
|
//判断是否是直播间管理员
|
||||||
|
if (enty.User != null && roomInfo != null && roomInfo.AdminUserIds.Any())
|
||||||
|
{
|
||||||
|
enty.User.IsAdmin = roomInfo.AdminUserIds.Contains(enty.User.Id.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断是否是主播
|
||||||
|
if (enty.User != null && roomInfo != null && roomInfo.Owner != null)
|
||||||
|
{
|
||||||
|
enty.User.IsAnchor = enty.User.Id.ToString() == roomInfo.Owner.UserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return enty;
|
||||||
|
}
|
||||||
|
|
||||||
//打印消息
|
//打印消息
|
||||||
private void PrintMsg(Msg msg, PackMsgType barType)
|
private void PrintMsg(Msg msg, PackMsgType barType)
|
||||||
{
|
{
|
||||||
var rinfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString());
|
var rinfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString());
|
||||||
var roomName = (rinfo?.Owner?.Nickname ?? ((msg.WebRoomId.IsNullOrWhiteSpace() ? msg.RoomId.ToString() : msg.WebRoomId)));
|
var roomName = (rinfo?.Owner?.Nickname ?? ((msg.WebRoomId.IsNullOrWhiteSpace() ? msg.RoomId.ToString() : msg.WebRoomId)));
|
||||||
|
var isAdmin = msg.User != null && msg.User.IsAdmin;
|
||||||
|
var isAnchor = msg.User != null && msg.User.IsAnchor;
|
||||||
|
|
||||||
var text = $"{DateTime.Now.ToString("HH:mm:ss")} [{roomName}] [{barType}]";
|
var text = $"{DateTime.Now.ToString("HH:mm:ss")} [{roomName}] [{barType}]";
|
||||||
|
|
||||||
|
if (isAdmin)
|
||||||
|
{
|
||||||
|
text+= " [管理员]";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isAnchor)
|
||||||
|
{
|
||||||
|
text += " [主播]";
|
||||||
|
}
|
||||||
|
|
||||||
if (msg.User != null)
|
if (msg.User != null)
|
||||||
{
|
{
|
||||||
text += $" [{msg.User?.GenderToString()}] ";
|
text += $" [{msg.User?.GenderToString()}] ";
|
||||||
@@ -260,9 +284,9 @@ namespace BarrageGrab
|
|||||||
//附加房间信息
|
//附加房间信息
|
||||||
private void AttachRoomInfo(Msg msg)
|
private void AttachRoomInfo(Msg msg)
|
||||||
{
|
{
|
||||||
if(msg==null) return;
|
if (msg == null) return;
|
||||||
var roomInfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString());
|
var roomInfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString());
|
||||||
if (roomInfo != null)
|
if (roomInfo != null && roomInfo.Owner!=null)
|
||||||
{
|
{
|
||||||
msg.Onwer = new RoomAnchorInfo()
|
msg.Onwer = new RoomAnchorInfo()
|
||||||
{
|
{
|
||||||
@@ -281,15 +305,10 @@ namespace BarrageGrab
|
|||||||
{
|
{
|
||||||
var msg = e.Message;
|
var msg = e.Message;
|
||||||
if (!CheckRoomId(msg.Common.roomId)) return;
|
if (!CheckRoomId(msg.Common.roomId)) return;
|
||||||
var enty = new FansclubMsg()
|
var enty = CreateMsg<FansclubMsg>(msg);
|
||||||
{
|
|
||||||
MsgId = msg.Common.msgId,
|
enty.Content = msg.Content;
|
||||||
Content = msg.Content,
|
enty.Type = msg.Type;
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
Type = msg.Type,
|
|
||||||
User = GetUser(msg.User)
|
|
||||||
};
|
|
||||||
enty.Level = enty.User.FansClub.Level;
|
enty.Level = enty.User.FansClub.Level;
|
||||||
|
|
||||||
var msgType = PackMsgType.粉丝团消息;
|
var msgType = PackMsgType.粉丝团消息;
|
||||||
@@ -304,18 +323,13 @@ namespace BarrageGrab
|
|||||||
{
|
{
|
||||||
var msg = e.Message;
|
var msg = e.Message;
|
||||||
if (!CheckRoomId(msg.Common.roomId)) return;
|
if (!CheckRoomId(msg.Common.roomId)) return;
|
||||||
var enty = new UserSeqMsg()
|
|
||||||
{
|
var enty = CreateMsg<UserSeqMsg>(msg);
|
||||||
MsgId = msg.Common.msgId,
|
enty.OnlineUserCount = msg.Total;
|
||||||
OnlineUserCount = msg.Total,
|
enty.TotalUserCount = msg.totalUser;
|
||||||
TotalUserCount = msg.totalUser,
|
enty.TotalUserCountStr = msg.totalPvForAnchor;
|
||||||
TotalUserCountStr = msg.totalPvForAnchor,
|
enty.OnlineUserCountStr = msg.onlineUserForAnchor;
|
||||||
OnlineUserCountStr = msg.onlineUserForAnchor,
|
enty.Content = $"当前直播间人数 {msg.onlineUserForAnchor},累计直播间人数 {msg.totalPvForAnchor}";
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
Content = $"当前直播间人数 {msg.onlineUserForAnchor},累计直播间人数 {msg.totalPvForAnchor}",
|
|
||||||
User = null
|
|
||||||
};
|
|
||||||
|
|
||||||
var msgType = PackMsgType.直播间统计;
|
var msgType = PackMsgType.直播间统计;
|
||||||
AttachRoomInfo(enty);
|
AttachRoomInfo(enty);
|
||||||
@@ -337,21 +351,21 @@ namespace BarrageGrab
|
|||||||
int lastCount = 0;
|
int lastCount = 0;
|
||||||
|
|
||||||
//纠正赋值礼物数据,比如是否连击,弹幕回送会不准确
|
//纠正赋值礼物数据,比如是否连击,弹幕回送会不准确
|
||||||
var findForData = giftData?.gifts?.FirstOrDefault(f => f.id == msg.giftId);
|
//var findForData = giftData?.gifts?.FirstOrDefault(f => f.id == msg.giftId);
|
||||||
if (findForData != null)
|
//if (findForData != null)
|
||||||
{
|
//{
|
||||||
var ogift = msg.Gift;
|
// var ogift = msg.Gift;
|
||||||
ogift.Name = findForData.name;
|
// ogift.Name = findForData.name;
|
||||||
ogift.Combo = findForData.combo;
|
// ogift.Combo = findForData.combo;
|
||||||
ogift.diamondCount = findForData.diamond_count;
|
// ogift.diamondCount = findForData.diamond_count;
|
||||||
ogift.Name = findForData.name;
|
// ogift.Name = findForData.name;
|
||||||
}
|
//}
|
||||||
|
|
||||||
//判断礼物重复
|
//判断礼物重复
|
||||||
if (msg.repeatEnd == 1 && giftCountCache.ContainsKey(key))
|
if (msg.repeatEnd == 1 && giftCountCache.ContainsKey(key))
|
||||||
{
|
{
|
||||||
//清除缓存中的key
|
//清除缓存中的key
|
||||||
if (msg.groupId > 0 )
|
if (msg.groupId > 0)
|
||||||
{
|
{
|
||||||
Tuple<int, DateTime> _;
|
Tuple<int, DateTime> _;
|
||||||
giftCountCache.TryRemove(key, out _);
|
giftCountCache.TryRemove(key, out _);
|
||||||
@@ -385,23 +399,17 @@ namespace BarrageGrab
|
|||||||
|
|
||||||
var count = currCount - lastCount;
|
var count = currCount - lastCount;
|
||||||
|
|
||||||
var enty = new GiftMsg()
|
var enty = CreateMsg<GiftMsg>(msg);
|
||||||
{
|
enty.Content = $"{msg.User.Nickname} 送出 {msg.Gift.Name}{(msg.Gift.Combo ? "(可连击)" : "")} x {msg.repeatCount}个,增量{count}个";
|
||||||
MsgId = msg.Common.msgId,
|
enty.DiamondCount = msg.Gift.diamondCount;
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
enty.RepeatCount = msg.repeatCount;
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
enty.GiftCount = count;
|
||||||
Content = $"{msg.User.Nickname} 送出 {msg.Gift.Name}{(msg.Gift.Combo ? "(可连击)" : "")} x {msg.repeatCount}个,增量{count}个",
|
enty.GroupId = msg.groupId;
|
||||||
DiamondCount = msg.Gift.diamondCount,
|
enty.GiftId = msg.giftId;
|
||||||
RepeatCount = msg.repeatCount,
|
enty.GiftName = msg.Gift.Name;
|
||||||
GiftCount = count,
|
enty.Combo = msg.Gift.Combo;
|
||||||
GroupId = msg.groupId,
|
enty.ImgUrl = msg.Gift.Image?.urlLists?.FirstOrDefault() ?? "";
|
||||||
GiftId = msg.giftId,
|
enty.ToUser = GetUser(msg.toUser);
|
||||||
GiftName = msg.Gift.Name,
|
|
||||||
Combo = msg.Gift.Combo,
|
|
||||||
ImgUrl = msg.Gift.Image?.urlLists?.FirstOrDefault() ?? "",
|
|
||||||
User = GetUser(msg.User),
|
|
||||||
ToUser = GetUser(msg.toUser)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (enty.ToUser != null)
|
if (enty.ToUser != null)
|
||||||
{
|
{
|
||||||
@@ -422,14 +430,8 @@ namespace BarrageGrab
|
|||||||
var msg = e.Message;
|
var msg = e.Message;
|
||||||
if (!CheckRoomId(msg.Common.roomId)) return;
|
if (!CheckRoomId(msg.Common.roomId)) return;
|
||||||
if (msg.Action != 1) return;
|
if (msg.Action != 1) return;
|
||||||
var enty = new Msg()
|
var enty = CreateMsg<Msg>(msg);
|
||||||
{
|
enty.Content = $"{msg.User.Nickname} 关注了主播";
|
||||||
MsgId = msg.Common.msgId,
|
|
||||||
Content = $"{msg.User.Nickname} 关注了主播",
|
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
User = GetUser(msg.User)
|
|
||||||
};
|
|
||||||
|
|
||||||
var msgType = PackMsgType.关注消息;
|
var msgType = PackMsgType.关注消息;
|
||||||
AttachRoomInfo(enty);
|
AttachRoomInfo(enty);
|
||||||
@@ -452,15 +454,9 @@ namespace BarrageGrab
|
|||||||
type = (ShareType)int.Parse(msg.shareTarget);
|
type = (ShareType)int.Parse(msg.shareTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
var enty = new ShareMessage()
|
var enty = CreateMsg<ShareMessage>(msg);
|
||||||
{
|
enty.Content = $"{msg.User.Nickname} 分享了直播间到{type}";
|
||||||
MsgId = msg.Common.msgId,
|
enty.ShareType = type;
|
||||||
Content = $"{msg.User.Nickname} 分享了直播间到{type}",
|
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
ShareType = type,
|
|
||||||
User = GetUser(msg.User)
|
|
||||||
};
|
|
||||||
|
|
||||||
var msgType = PackMsgType.直播间分享;
|
var msgType = PackMsgType.直播间分享;
|
||||||
AttachRoomInfo(enty);
|
AttachRoomInfo(enty);
|
||||||
@@ -479,15 +475,11 @@ namespace BarrageGrab
|
|||||||
var msg = e.Message;
|
var msg = e.Message;
|
||||||
if (!CheckRoomId(msg.Common.roomId)) return;
|
if (!CheckRoomId(msg.Common.roomId)) return;
|
||||||
|
|
||||||
var enty = new Modles.JsonEntity.MemberMessage()
|
var enterType = e.Message.userEnterTipType;
|
||||||
{
|
var enty = CreateMsg<Modles.JsonEntity.MemberMessage>(msg);
|
||||||
MsgId = msg.Common.msgId,
|
enty.Content = $"{msg.User.Nickname} ${(enterType == 6 ? " 通过分享" : "")}来了 直播间人数:{msg.memberCount}";
|
||||||
Content = $"{msg.User.Nickname} 来了 直播间人数:{msg.memberCount}",
|
enty.CurrentCount = msg.memberCount;
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
enty.EnterTipType = enterType;
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
CurrentCount = msg.memberCount,
|
|
||||||
User = GetUser(msg.User)
|
|
||||||
};
|
|
||||||
|
|
||||||
var msgType = PackMsgType.进直播间;
|
var msgType = PackMsgType.进直播间;
|
||||||
AttachRoomInfo(enty);
|
AttachRoomInfo(enty);
|
||||||
@@ -504,16 +496,10 @@ namespace BarrageGrab
|
|||||||
var msg = e.Message;
|
var msg = e.Message;
|
||||||
if (!CheckRoomId(msg.Common.roomId)) return;
|
if (!CheckRoomId(msg.Common.roomId)) return;
|
||||||
|
|
||||||
var enty = new LikeMsg()
|
var enty = CreateMsg<LikeMsg>(msg);
|
||||||
{
|
enty.Total = msg.Total;
|
||||||
MsgId = msg.Common.msgId,
|
enty.Count = msg.Count;
|
||||||
Count = msg.Count,
|
enty.Content = $"{msg.User.Nickname} 为主播点了{msg.Count}个赞,总点赞{msg.Total}";
|
||||||
Content = $"{msg.User.Nickname} 为主播点了{msg.Count}个赞,总点赞{msg.Total}",
|
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
Total = msg.Total,
|
|
||||||
User = GetUser(msg.User)
|
|
||||||
};
|
|
||||||
|
|
||||||
var msgType = PackMsgType.点赞消息;
|
var msgType = PackMsgType.点赞消息;
|
||||||
AttachRoomInfo(enty);
|
AttachRoomInfo(enty);
|
||||||
@@ -529,14 +515,8 @@ namespace BarrageGrab
|
|||||||
var msg = e.Message;
|
var msg = e.Message;
|
||||||
if (!CheckRoomId(msg.Common.roomId)) return;
|
if (!CheckRoomId(msg.Common.roomId)) return;
|
||||||
|
|
||||||
var enty = new Msg()
|
var enty = CreateMsg<Msg>(msg);
|
||||||
{
|
enty.Content = msg.Content;
|
||||||
MsgId = msg.Common.msgId,
|
|
||||||
Content = msg.Content,
|
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
|
||||||
User = GetUser(msg.User),
|
|
||||||
};
|
|
||||||
|
|
||||||
var msgType = PackMsgType.弹幕消息;
|
var msgType = PackMsgType.弹幕消息;
|
||||||
AttachRoomInfo(enty);
|
AttachRoomInfo(enty);
|
||||||
@@ -562,7 +542,8 @@ namespace BarrageGrab
|
|||||||
Content = "直播已结束",
|
Content = "直播已结束",
|
||||||
RoomId = msg.Common.roomId.ToString(),
|
RoomId = msg.Common.roomId.ToString(),
|
||||||
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
|
||||||
User = null
|
User = null,
|
||||||
|
Appid = e.Message.Common.appId.ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
var msgType = PackMsgType.下播;
|
var msgType = PackMsgType.下播;
|
||||||
|
|||||||
@@ -64,6 +64,9 @@
|
|||||||
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Acornima, Version=1.1.0.0, Culture=neutral, PublicKeyToken=496b38436bb9edeb, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Acornima.1.1.0\lib\net462\Acornima.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="BouncyCastle.Crypto, Version=1.8.8.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
|
<Reference Include="BouncyCastle.Crypto, Version=1.8.8.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Portable.BouncyCastle.1.8.8\lib\net40\BouncyCastle.Crypto.dll</HintPath>
|
<HintPath>..\packages\Portable.BouncyCastle.1.8.8\lib\net40\BouncyCastle.Crypto.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -86,9 +89,8 @@
|
|||||||
<Reference Include="HtmlAgilityPack, Version=1.11.51.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
<Reference Include="HtmlAgilityPack, Version=1.11.51.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\HtmlAgilityPack.1.11.51\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
<HintPath>..\packages\HtmlAgilityPack.1.11.51\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Jint, Version=3.0.1.0, Culture=neutral, PublicKeyToken=2e92ba9c8d81157f, processorArchitecture=MSIL">
|
<Reference Include="Jint, Version=4.1.0.0, Culture=neutral, PublicKeyToken=2e92ba9c8d81157f, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Jint.3.0.1\lib\net462\Jint.dll</HintPath>
|
<HintPath>..\packages\Jint.4.1.0\lib\net462\Jint.dll</HintPath>
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
|
||||||
@@ -169,8 +171,8 @@
|
|||||||
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
|
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll</HintPath>
|
<HintPath>..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll</HintPath>
|
||||||
@@ -259,10 +261,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
<None Include="LocalData\gift.json">
|
|
||||||
<CustomToolNamespace>WssBarrageService.Resource.LocalData</CustomToolNamespace>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="nlog.config">
|
<None Include="nlog.config">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="Acornima" version="1.1.0" targetFramework="net462" />
|
||||||
<package id="BouncyCastle.Cryptography" version="2.0.0" targetFramework="net48" />
|
<package id="BouncyCastle.Cryptography" version="2.0.0" targetFramework="net48" />
|
||||||
<package id="BrotliSharpLib" version="0.3.3" targetFramework="net48" />
|
<package id="BrotliSharpLib" version="0.3.3" targetFramework="net48" />
|
||||||
<package id="Costura.Fody" version="5.7.0" targetFramework="net462" developmentDependency="true" />
|
<package id="Costura.Fody" version="5.7.0" targetFramework="net462" developmentDependency="true" />
|
||||||
@@ -7,7 +8,7 @@
|
|||||||
<package id="Fleck" version="1.2.0" targetFramework="net48" />
|
<package id="Fleck" version="1.2.0" targetFramework="net48" />
|
||||||
<package id="Fody" version="6.8.2" targetFramework="net462" developmentDependency="true" />
|
<package id="Fody" version="6.8.2" targetFramework="net462" developmentDependency="true" />
|
||||||
<package id="HtmlAgilityPack" version="1.11.51" targetFramework="net48" />
|
<package id="HtmlAgilityPack" version="1.11.51" targetFramework="net48" />
|
||||||
<package id="Jint" version="3.0.1" targetFramework="net462" />
|
<package id="Jint" version="4.1.0" targetFramework="net462" />
|
||||||
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net462" />
|
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net462" />
|
||||||
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net462" />
|
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net48" />
|
<package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net48" />
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net462" />
|
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net462" />
|
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="System.Runtime" version="4.3.0" targetFramework="net462" />
|
<package id="System.Runtime" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" />
|
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
|
||||||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net462" />
|
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net462" />
|
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net462" />
|
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net462" />
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ message MemberMessage{
|
|||||||
Image backgroundImageV2 = 17;
|
Image backgroundImageV2 = 17;
|
||||||
Text anchorDisplayText = 18;
|
Text anchorDisplayText = 18;
|
||||||
PublicAreaCommon publicAreaCommon = 19;
|
PublicAreaCommon publicAreaCommon = 19;
|
||||||
|
string userEnterTipType = 20;
|
||||||
|
string anchorEnterTipType = 21;
|
||||||
|
|
||||||
message EffectConfig{
|
message EffectConfig{
|
||||||
int64 type = 1;
|
int64 type = 1;
|
||||||
@@ -197,6 +199,7 @@ message Common{
|
|||||||
Room room = 16;
|
Room room = 16;
|
||||||
int64 anchorFoldTypeV2 = 17;
|
int64 anchorFoldTypeV2 = 17;
|
||||||
int64 processAtSeiTimeMs = 18;
|
int64 processAtSeiTimeMs = 18;
|
||||||
|
int64 appId = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Text{
|
message Text{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<p style="text-align:center;font-size:3rem">📺 抖音弹幕监听器</p>
|
<p style="text-align:center;font-size:3rem"></p>
|
||||||
|
|
||||||
|
|
||||||
|
# 📺 抖音弹幕监听器
|
||||||
|
|
||||||
<p style="text-align:center">- 小白不圆 -</p>
|
<p style="text-align:center">- 小白不圆 -</p>
|
||||||
|
|
||||||
@@ -8,15 +8,29 @@
|
|||||||
|
|
||||||
+ Github(受网络影响,更新很可能不及时)大佬请移步 [Gitee](https://gitee.com/haodong108/dy-barrage-grab) ,参与Issues讨论,QQ技术讨论群:<br>
|
+ Github(受网络影响,更新很可能不及时)大佬请移步 [Gitee](https://gitee.com/haodong108/dy-barrage-grab) ,参与Issues讨论,QQ技术讨论群:<br>
|
||||||
+ 群1: 819927029
|
+ 群1: 819927029
|
||||||
+ 群2: 789875441 (新建)
|
+ 群2: 789875441
|
||||||
+ 注: (进群前请先⭐**Star**,并填入答案,用于排除行外人员,特殊原因请私聊我),之前因满员踢掉的群员可申请群2。
|
+ 注: (进群前请先⭐**Star**,并填入答案,用于排除行外人员,特殊原因请私聊我),之前因满员踢掉的群员可申请群2。
|
||||||
+ 发行版下载地址在[这里](https://gitee.com/haodong108/dy-barrage-grab/releases),别下成源码包了!!,**决定下载使用前请先仔细阅读文档**,不要进群提问已经介绍到的问题
|
+ 发行版下载地址在[这里](https://gitee.com/haodong108/dy-barrage-grab/releases),别下成源码包了!!,**决定下载使用前请先仔细阅读文档**,不要进群提问已经介绍到的问题
|
||||||
+ 💭 需要抖音日常操作协议化,包括**多直播间超长稳定连接**、**自动私信**(支持群组,单发,支持多账号切换),**私信监听、自动关注、粉丝群、作品点赞评论及监听、直播间发弹幕、获取直播间榜单、直播间更多消息事件、作品评论(支持图片)、发布作品** 等等功能的可以找我(Q1083092844)提供一些技术支持 (注:主要面向个人直播自动化,不面向恶意j流、水jun等,不支持匿名直播间,想搞他人直播间匿名采集的勿扰,加群也不会有人支持)
|
+ 💭 需要抖音日常操作协议化,包括**多直播间超长稳定连接**、**自动私信**(支持群组,单发,支持多账号切换),**私信监听、自动关注、粉丝群、作品点赞评论及监听、直播间发弹幕、获取直播间榜单、直播间更多消息事件、作品评论(支持图片)、发布作品** 等功能的可以找我(Q1083092844)提供一些技术支持 (注:主要面向个人直播自动化,不面向恶意j流、水jun等,不支持匿名直播间,想搞他人直播间匿名采集的勿扰,加群也不会有人支持)
|
||||||
+ 支持接单、定制等,dy相关优先,其他方面也可以找我帮忙转发定制
|
+ 支持接单、定制等,dy相关优先,其他方面也可以找我帮忙转发定制
|
||||||
+ 如果好用,请<a href="#user-content-支持一下">捐赠</a>个仨瓜俩枣,白某谢过各位老板
|
+ 如果好用,请<a href="#user-content-支持一下">捐赠</a>个仨瓜俩枣,白某谢过各位老板
|
||||||
|
|
||||||
## ⛳近期更新
|
## ⛳近期更新
|
||||||
|
|
||||||
|
2025-02-11 v2.7.7
|
||||||
|
|
||||||
|
1. 添加 `Appid` 字段(疑似用户看直播的APP标识) 和 `EnterTipType` 字段(用于获知用户进入直播间的方式,已知0为普通进入,6为通过分享进入)
|
||||||
|
|
||||||
|
2. User字段新增 `IsAdmin` 和 `IsAnchor` 字段,用于区分是否为管理员或者主播的消息
|
||||||
|
|
||||||
|
3. web在中途监听弹幕,且直播间弹幕链接已降级为轮询的情况下,解决 `webroomid` 以及房间信息丢失问题
|
||||||
|
|
||||||
|
4. 修复直播伴侣更新后,无法定位到exe位置的问题
|
||||||
|
|
||||||
|
5. 优化部分其他已知问题
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2024-09-28 v2.7.6(beta)
|
2024-09-28 v2.7.6(beta)
|
||||||
|
|
||||||
1. **[重要更新]** 支持免系统代理监听直播伴侣,需要在配置文件关闭`useproxy`选项以及打开`liveCompanHookSwitch`选项,配置后监听web直播间可参考<a href="#user-content-实践指南">实践指南</a>新部分
|
1. **[重要更新]** 支持免系统代理监听直播伴侣,需要在配置文件关闭`useproxy`选项以及打开`liveCompanHookSwitch`选项,配置后监听web直播间可参考<a href="#user-content-实践指南">实践指南</a>新部分
|
||||||
@@ -67,7 +81,7 @@
|
|||||||
|
|
||||||
## 🖼️控制台截图
|
## 🖼️控制台截图
|
||||||
|
|
||||||
[](https://imgse.com/i/z9YYPU)
|
[](https://imgse.com/i/z9YYPU)
|
||||||
|
|
||||||
## 😎介绍及配置
|
## 😎介绍及配置
|
||||||
|
|
||||||
@@ -210,19 +224,19 @@
|
|||||||
|
|
||||||
1. 前往扩展商店 搜索 `switchyomega` 安装
|
1. 前往扩展商店 搜索 `switchyomega` 安装
|
||||||
|
|
||||||
[<img src="https://s21.ax1x.com/2024/09/28/pA1SSSg.png" alt="pA1SSSg.png" style="zoom: 50%;" />](https://imgse.com/i/pA1SSSg)
|
[<img src="./imgs/proxy1.png" style="zoom: 50%;" />](https://imgse.com/i/pA1SSSg)
|
||||||
|
|
||||||
2. 添加弹幕代理
|
2. 添加弹幕代理
|
||||||
|
|
||||||
[<img src="https://s21.ax1x.com/2024/09/28/pA1SCOs.png" alt="pA1SCOs.png" style="zoom:50%;" />](https://imgse.com/i/pA1SCOs)
|
[<img src="./imgs/proxy2.png" alt="pA1SCOs.png" style="zoom:50%;" />](https://imgse.com/i/pA1SCOs)
|
||||||
|
|
||||||
3. 配置代理地址,并保存,不要配置为ws服务端口地址,程序默认代理端口是**8827**
|
3. 配置代理地址,并保存,不要配置为ws服务端口地址,程序默认代理端口是**8827**
|
||||||
|
|
||||||
[<img src="https://s21.ax1x.com/2024/09/28/pA1SLjJ.png" alt="pA1SLjJ.png" style="zoom:50%;" />](https://imgse.com/i/pA1SLjJ)
|
[<img src="./imgs/proxy3.png" style="zoom:50%;" />](https://imgse.com/i/pA1SLjJ)
|
||||||
|
|
||||||
4. 进入直播页,应用代理,完成!
|
4. 进入直播页,应用代理,完成!
|
||||||
|
|
||||||
[<img src="https://s21.ax1x.com/2024/09/28/pA1SXu9.png" alt="pA1SXu9.png" style="zoom:50%;" />](https://imgse.com/i/pA1SXu9)
|
[<img src="./imgs/proxy4.png" style="zoom:50%;" />](https://imgse.com/i/pA1SXu9)
|
||||||
|
|
||||||
5. Chrome 用户请自行百度搜索扩展安装方法
|
5. Chrome 用户请自行百度搜索扩展安装方法
|
||||||
|
|
||||||
@@ -257,7 +271,7 @@
|
|||||||
<a id="user-content-支持一下" class="anchor"></a>
|
<a id="user-content-支持一下" class="anchor"></a>
|
||||||
|
|
||||||
## 🍻支持一下?
|
## 🍻支持一下?
|
||||||
开源不易,老板
|
开源不易
|
||||||
<p>
|
<p>
|
||||||
<img src="./imgs/微信.png" alt="微信支付" style="zoom:70%;border-radius: 5px;" />
|
<img src="./imgs/微信.png" alt="微信支付" style="zoom:70%;border-radius: 5px;" />
|
||||||
</p>
|
</p>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 414 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
Reference in New Issue
Block a user