426 lines
20 KiB
C#
426 lines
20 KiB
C#
using Api.Framework.Cps;
|
||
using Api.Framework.Utils;
|
||
using CsharpHttpHelper;
|
||
using CsharpHttpHelper.Enum;
|
||
using Newtonsoft.Json.Linq;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Web;
|
||
|
||
namespace Api.Framework.Tools
|
||
{
|
||
/// <summary>
|
||
/// 抖音解析助手
|
||
/// </summary>
|
||
public class DYHelper
|
||
{
|
||
/// <summary>
|
||
/// 获取抖音链接中的商品ID(有问题,用api中的GetDyGoodsID)
|
||
/// </summary>
|
||
/// <param name="mess">包含抖音链接的文本</param>
|
||
/// <returns></returns>
|
||
public static string GetDyGoodsID(string mess, out string promotion_id, out string title)
|
||
{
|
||
title = string.Empty;
|
||
promotion_id = string.Empty;
|
||
|
||
if (string.IsNullOrWhiteSpace(mess) ||
|
||
Regex.IsMatch(mess, @"\[图片=(.+?)\]") ||
|
||
Regex.IsMatch(mess, @"\[视频=(.+?)\]") ||
|
||
Regex.IsMatch(mess, @"\[卡片=(.+?)\]") ||
|
||
Regex.IsMatch(mess, @"\[公告=(.+?)\]") ||
|
||
Regex.IsMatch(mess, @"\[语音=(.+?)\]")
|
||
)
|
||
return string.Empty;
|
||
|
||
bool flag = false;
|
||
if (mess.Contains("goods_id")) flag = true;
|
||
//获取链接的正则表达式
|
||
var _url = HttpExtend.RegexMatchUrl(mess);
|
||
|
||
#region 之前的拿不到promotion_id,就先不处理 这种连接: https://haohuo.jinritemai.com/views/product/item2?id=3479881104721353508
|
||
//if (!flag && _url.Success)//有链接的情况
|
||
//{
|
||
// mess = _url.Groups["链接"].Value;
|
||
// if (Regex.IsMatch(mess, "http[s]?://haohuo."))
|
||
// {
|
||
// if (mess == null || !mess.Contains("?id=")) return string.Empty;
|
||
// else flag = true;
|
||
// }
|
||
// else
|
||
// flag = true;
|
||
//}
|
||
#region 新的
|
||
if (!flag && !string.IsNullOrWhiteSpace(_url))//有链接的情况
|
||
{
|
||
mess = _url;
|
||
if (Regex.IsMatch(mess, "http[s]?://haohuo."))
|
||
{
|
||
if (mess == null || !mess.Contains("?id=")) return string.Empty;
|
||
else flag = true;
|
||
}
|
||
else if (Regex.IsMatch(mess, "http[s]?://www.iesdouyin.", RegexOptions.IgnoreCase))
|
||
{
|
||
if (mess == null || mess.ToLower().Contains("object_id="))
|
||
{
|
||
var reg = Regex.Match(mess, @"object_id=(?:\d+?)_(?<promotion_id>\d+?)_(?<goodid>\d+?)_(?:\d+?)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||
if (reg.Success)
|
||
{
|
||
//https://www.iesdouyin.com/?schema_type=20&object_id=1460607342872671_3508329772335892947_3508329411592229101_0
|
||
promotion_id = reg.Groups["promotion_id"].ToString();
|
||
return reg.Groups["goodid"].ToString();
|
||
}
|
||
}
|
||
else flag = true;
|
||
}
|
||
else if (Regex.IsMatch(mess, "http[s]?://v.douyin.com", RegexOptions.IgnoreCase))//链接: https://v.douyin.com/LbN2pka/
|
||
{
|
||
HttpHelper http = new HttpHelper();
|
||
HttpItem item = new HttpItem()
|
||
{
|
||
URL = mess,
|
||
Method = "GET",
|
||
Timeout = 100000,
|
||
ReadWriteTimeout = 30000,
|
||
IsToLower = false,
|
||
Cookie = "",
|
||
UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0",
|
||
Accept = "text/html, application/xhtml+xml, */*",
|
||
ContentType = "application/x-www-form-urlencoded",
|
||
Referer = "",
|
||
Allowautoredirect = false,
|
||
AutoRedirectCookie = false,
|
||
Postdata = "",
|
||
};
|
||
HttpResult result = http.GetHtml(item);
|
||
|
||
mess = result.Html;
|
||
flag = true;
|
||
}
|
||
else
|
||
flag = true;
|
||
}
|
||
#endregion
|
||
|
||
#endregion
|
||
if (flag)
|
||
{
|
||
var regUrl = Regex.Match(mess, @"(yukhj.com|m.tb.cn|m.yeeoq.top|m.uqlsi|m.rijni|m.gkqmj|m.mulwt|uland\\.taobao\\.com|sjtm.me|aa5d.com|d11a.com|f61[a-z].com|92db.com|yqt.so|e22a.com|f61b.com|detail.m.tmall.hk|k.83jie.com|ewqcxz.com|items.alitrip.com|tmqd.me|detail.tmall.hk|url.cn|taobao.com|mashort.cn|tmall.com|tb.cn|detail.yao.95095.com|laiwang.com|dwz.cn|juhuasuan.com|detail.m.tmall.com|zmnxbc.com|s.click.taobao|detail.liangxinyao.com|m.tb.cn)", RegexOptions.IgnoreCase);
|
||
if (!regUrl.Success)
|
||
{
|
||
var messTmp = HttpHelper.URLDecode(HttpHelper.URLDecode(mess)).Replace("&", "&");
|
||
var reg = Regex.Match(messTmp, @"origin_id=\d+_(?<promotion_id>\d+)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"alkey=\d+?_\d+?_\d+?_(?<promotion_id>\d+)_\d+?", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||
if (reg.Success)
|
||
promotion_id = reg.Groups["promotion_id"].ToString();
|
||
|
||
reg = Regex.Match(messTmp, @"\?id=(?<商品id>\d{4,})", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"product_id=(?<商品id>\d+)", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"""product_id\\\"":\\\""(?<商品id>\d+)\\\""", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"""product_id"":(?<商品id>\d+)", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"""product_id"":""(?<商品id>\d+)""", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"product_id"":""(?<商品id>\d+)""", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
//reg = Regex.Match(messTmp, @"&id=(?<商品id>\d{4,})", RegexOptions.IgnoreCase);
|
||
reg = Regex.Match(messTmp, @"\\\\\\""gid\\\\\\"":(?<商品id>\d{4,}),", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"origin_id=\d+?_\d+?_(?<商品id>\d+)", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"""search_result_id\\+?"":\\+?""(?<商品id>\d+)", RegexOptions.IgnoreCase);
|
||
if (!reg.Success)
|
||
reg = Regex.Match(messTmp, @"""pre_product_id\\+?"":\\+?""(?<商品id>\d+)", RegexOptions.IgnoreCase);
|
||
if (reg.Success)
|
||
return reg.Groups["商品id"].ToString();
|
||
|
||
reg = Regex.Match(messTmp, @"object_id=(?:\d+)_(?<推广id>\d+)_(?<商品id>\d+)_(?:\d+)", RegexOptions.IgnoreCase);
|
||
if (reg.Success)
|
||
{
|
||
promotion_id = reg.Groups["推广id"].ToString();
|
||
return reg.Groups["商品id"].ToString();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//var regs1 = Regex.Matches(mess, "[^A-Za-z0-9]?([A-Za-z0-9]{11})[^A-Za-z0-9]?");
|
||
var reg = Regex.Match(mess, "([︽#]{2}[A-Za-z0-9]{11,14}[︽#]{2})");
|
||
if (reg.Success)
|
||
{
|
||
return DouyinApi.AnalysisCmdToGoodsUrl(reg.Groups[1].Value, out promotion_id, out title);
|
||
}
|
||
}
|
||
return string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 抖音短连接
|
||
/// </summary>
|
||
/// <param name="url"></param>
|
||
/// <returns></returns>
|
||
public static string ShortDyUrl(string url)
|
||
{
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
try
|
||
{
|
||
//{"code":0,"message":"success","now":1640269188,"data":"https://v.douyin.com/8Ntmkfp/"}
|
||
var shortUrl = "https://lf.snssdk.com/shorten/?belong=aweme&target=" + HttpHelper.URLEncode(url);
|
||
HttpHelper http = new HttpHelper();
|
||
var html = http.GetHtml(shortUrl).Html;
|
||
if (!string.IsNullOrWhiteSpace(html))
|
||
{
|
||
var jObj = JObject.Parse(html);
|
||
if (jObj["code"] != null && ((int)jObj["code"] == 0 || jObj["message"]?.ToString() == "success"))
|
||
{
|
||
var data = jObj["data"]?.ToString();
|
||
if (data.ToLower().Contains("douyin"))
|
||
return data;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{ }
|
||
Thread.Sleep(200);
|
||
}
|
||
return url;
|
||
}
|
||
|
||
|
||
|
||
|
||
#region 口令算法
|
||
|
||
private static string Md5(string str)
|
||
{
|
||
MD5 md5 = MD5.Create();
|
||
var bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
|
||
// 第五步:把二进制转化为大写的十六进制
|
||
StringBuilder result = new StringBuilder();
|
||
for (int i = 0; i < bytes.Length; i++)
|
||
{
|
||
result.Append(bytes[i].ToString("x2"));
|
||
}
|
||
return result.ToString();
|
||
}
|
||
private static long GetTimeStamp(bool Seconds = true)
|
||
{
|
||
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||
if (Seconds) return Convert.ToInt64(ts.TotalSeconds);
|
||
else return Convert.ToInt64(ts.TotalMilliseconds);
|
||
}
|
||
private static string hex_string(long num)
|
||
{
|
||
var tmp_string = num.ToString("x2");
|
||
if (tmp_string.Length < 2)
|
||
tmp_string = '0' + tmp_string;
|
||
return tmp_string;
|
||
}
|
||
private static int reverse(long num)
|
||
{
|
||
var tmp_string = hex_string(num);
|
||
return Convert.ToInt32(tmp_string.Substring(1) + tmp_string.Substring(0, 1), 16);
|
||
}
|
||
private static int RIT(long num)
|
||
{
|
||
var result = "";
|
||
var tmp_string = Convert.ToString(num, 2); ;// bin(num)[2];
|
||
while (tmp_string.Length < 8)
|
||
{
|
||
tmp_string = "0" + tmp_string;
|
||
}
|
||
for (int i = 0; i < 8; i++)
|
||
{
|
||
result = result + tmp_string[7 - i];
|
||
}
|
||
return Convert.ToInt32(result, 2);
|
||
}
|
||
private static Dictionary<string, string> CreateXg(string url, string data = "", string cookies = "")
|
||
{
|
||
var gorgon = string.Empty;
|
||
gorgon += Md5(url);
|
||
if (!string.IsNullOrEmpty(data))
|
||
gorgon += Md5(data);
|
||
else
|
||
gorgon += "00000000000000000000000000000000";
|
||
|
||
if (!string.IsNullOrEmpty(cookies))
|
||
gorgon += Md5(cookies);
|
||
else
|
||
gorgon += "00000000000000000000000000000000";
|
||
|
||
gorgon += "00000000000000000000000000000000";
|
||
|
||
return calc_xg(gorgon);
|
||
|
||
}
|
||
|
||
private static Dictionary<string, string> calc_xg(string data)
|
||
{
|
||
var ts = 1646128554;// GetTimeStamp();
|
||
var ts_x = 1646128554000;// GetTimeStamp(true);
|
||
var len = 0x14;
|
||
var key = new long[] { 0xDF, 0x77, 0xB9, 0x40, 0xb9, 0x9b, 0x84, 0x83, 0xd1, 0xb9, 0xcb, 0xd1, 0xf7, 0xc2, 0xb9, 0x85, 0xc3, 0xd0,
|
||
0xfb, 0xc3};
|
||
var param_list = new List<long>();
|
||
long H = 0;
|
||
// for i in range(0, 12, 4):
|
||
for (int i = 0; i < 12; i = i + 4)
|
||
{
|
||
var temp = data.Substring(8 * i, 8);// data[8 * i: 8 * (i + 1)];
|
||
for (int j = 0; j < 4; j++)
|
||
{
|
||
// int(temp[j * 2:(j + 1) * 2], 16)
|
||
var V = temp.Substring(j * 2, 2);
|
||
H = Convert.ToInt32(temp.Substring(j * 2, 2), 16);
|
||
param_list.Add(H);
|
||
}
|
||
}
|
||
//param_list.extend([0x0, 0x6, 0xB, 0x1C])
|
||
param_list.Add(0x0);
|
||
param_list.Add(0x6);
|
||
param_list.Add(0xB);
|
||
param_list.Add(0x1C);
|
||
H = Convert.ToInt32(ts.ToString("x2"), 16);
|
||
param_list.Add((H & 0xFF000000) >> 24);
|
||
param_list.Add((H & 0x00FF0000) >> 16);
|
||
param_list.Add((H & 0x0000FF00) >> 8);
|
||
param_list.Add((H & 0x000000FF) >> 0);
|
||
var eor_result_list = new List<long>();
|
||
for (int i = 0; i < 20; i++)
|
||
{
|
||
//eor_result_list.append(A ^ B)
|
||
eor_result_list.Add(param_list[i] ^ key[i]);
|
||
}
|
||
|
||
for (int i = 0; i < 20; i++)
|
||
{
|
||
var C = reverse(eor_result_list[i]);
|
||
var D = eor_result_list[(i + 1) % len];
|
||
var E = C ^ D;
|
||
var F = RIT(E);
|
||
H = (F ^ 0xFFFFFFFF ^ len) & 0xFF;
|
||
eor_result_list[i] = H;
|
||
}
|
||
|
||
var result = "";
|
||
foreach (var param in eor_result_list)
|
||
{
|
||
result += hex_string(param);
|
||
}
|
||
|
||
var xgorgon = "0408b0d30000" + result;
|
||
Dictionary<string, string> XgDatas = new Dictionary<string, string>();
|
||
XgDatas["X-Gorgon"] = xgorgon;
|
||
XgDatas["X-Khronos"] = ts.ToString();
|
||
XgDatas["X-SS-REQ-TICKET"] = ts_x.ToString();
|
||
return XgDatas;
|
||
}
|
||
private static Dictionary<string, string> _device_info;
|
||
private static Dictionary<string, string> device_info
|
||
{
|
||
get
|
||
{
|
||
if (_device_info == null)
|
||
{
|
||
_device_info = new Dictionary<string, string>();
|
||
|
||
_device_info["device_id"] = "655729250010781";
|
||
_device_info["install_id"] = "2590869714905182";
|
||
_device_info["device_id_str"] = "655729250010781";
|
||
_device_info["install_id_str"] = "2590869714905182";
|
||
_device_info["new_user"] = "1";
|
||
_device_info["device_token"] = "AAA45JXIIXBRRAL6BCSHWP2ZFWET2NU65PHNP6EREEYPF2WJ6NMY2TKTAZXV666654U44IRIACWWQKGDEJWZQS7JMB7KTT5MOQ6WEFSOPMATGN6FG2EYRZTG4YQ5A";
|
||
|
||
}
|
||
return _device_info;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连接转口令
|
||
/// </summary>
|
||
/// <param name="url"></param>
|
||
/// <returns></returns>
|
||
public static string CreateKouling(string url)
|
||
{
|
||
//https://haohuo.jinritemai.com/views/product/item2?id=3504966563675637147&origin_type=2002170010&origin_id=1460607342872671_3507916645882543574&alkey=1128_1460607342872671_0_3507916645882543574_011&sec_author_id=MS4wLjABAAAAEnpGkVpQS-WLtu18Me9lZ-9A284xvNbstU-HGyQK3vn2Pi-WtDWPRAXLCnSRvDsF&buyin_track=COgIEN-Q0K6ijcwCGgQIABAAIgkyB05ldmpGQ2Mom4uIjNCQidIwMAE&c_biz_combo=2
|
||
|
||
|
||
var uri = new Uri(url);
|
||
|
||
var collection = HttpUtility.ParseQueryString(uri.Query);//默认采用UTF-8编码,当然也可以传入特定编码进行解析
|
||
//var collection= HttpUtility.ParseQueryString(uri.Query,Encoding.ASCII);
|
||
|
||
var id = collection["id"];
|
||
var promotion_id = collection["origin_id"]?.Split('_')[1];
|
||
var sec_author_id = collection["sec_author_id"];
|
||
var buyin_track = collection["buyin_track"];
|
||
|
||
return CreateKouling(id, promotion_id, sec_author_id, buyin_track);
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="product_id">商品ID</param>
|
||
/// <param name="promotion_id">推广地址ID</param>
|
||
/// <param name="sec_author_id">推广人信息</param>
|
||
private static string CreateKouling(string product_id, string promotion_id, string sec_author_id, string buyin_track)
|
||
{
|
||
try
|
||
{
|
||
var ts = GetTimeStamp();
|
||
//var sslocal = $"sslocal%3A%2F%2Fec_goods_detail%2F%3Fsec_author_id%3D%26promotion_id%3D{promotion_id}%26product_id%3D{product_id}%26commodity_id%3D%26commodity_type%3D%26promotion_source%3D%26enter_method%3Dclick_video_tag%26meta_params%3D%7B%22is_star_atlas%22%3Afalse%2C%22is_ad_traffic%22%3Afalse%2C%22entrance_info%22%3A%22%22%7D%26source_page%3Dtoken%26ecom_share_track_params%3D%7B%22is_ec_shopping%22%3A%221%22%7D%26request_additions%3D%7B%22sec_author_id%22%3A%22{}%22%7D";
|
||
var sslocal = "sslocal://ec_goods_detail/?sec_author_id=&promotion_id=" + promotion_id + "&product_id=" + product_id + "&commodity_id=&commodity_type=&promotion_source=&enter_method=click_video_tag&meta_params={\"is_star_atlas\":false,\"is_ad_traffic\":false,\"entrance_info\":\"\"}&source_page=token&ecom_share_track_params={\"is_ec_shopping\":\"1\"}&request_additions={\"sec_author_id\":\"" + sec_author_id + "\",\"buyin_track\":\"" + buyin_track + "\"}";
|
||
sslocal = CsharpHttpHelper.HttpHelper.URLEncode(sslocal, Encoding.UTF8);
|
||
var otherData = $"&schema_type=20&object_id={product_id}©_type=auto&iid={device_info["install_id"]}&device_id={device_info["device_id"]}&ac=wifi&channel=douyin_juyouliang_and4&aid=1128&app_name=aweme&version_code=190200&version_name=19.2.0&device_platform=android&os=android&ssmix=a&device_type=Pixel+3&device_brand=google&language=zh&os_api=29&os_version=10&manifest_version_code=190201&resolution=1080*2028&dpi=440&update_version_code=19209900&_rticket=1646117336178&package=com.ss.android.ugc.aweme&cpu_support64=true&host_abi=armeabi-v7a&is_guest_mode=0&app_type=normal&minor_status=0&appTheme=light&need_personal_recommend=1&is_android_pad=0&ts={ts}&cdid=a090acdf-53e8-47a7-85ca-7d4f8d3d3b7c";
|
||
|
||
var param = $"schema={sslocal}{otherData}";
|
||
var url = $"https://api5-normal-c-lq.amemv.com/aweme/v2/platform/share/command/gen/?{param}";
|
||
var Headers = CreateXg(param);
|
||
var http = new CsharpHttpHelper.HttpHelper();
|
||
var item = new CsharpHttpHelper.HttpItem()
|
||
{
|
||
URL = url,
|
||
Method = "post",
|
||
ContentType = "application/json",
|
||
Postdata = "{'body': 'null'}",
|
||
Timeout = 5000,
|
||
UserAgent = "com.ss.android.ugc.aweme/190201 (Linux; U; Android 10; zh_CN_#Hans; Pixel 3; Build/QQ3A.200805.001; Cronet/TTNetVersion:28eaf52b 2021-12-28 QuicVersion:68cae75d 2021-08-12)"
|
||
};
|
||
foreach (var v in Headers)
|
||
{
|
||
item.Header[v.Key] = v.Value;
|
||
}
|
||
//3:/ -
|
||
var html = http.GetHtml(item).Html;
|
||
var json = JObject.Parse(html);
|
||
if (json["command_v2"] != null)
|
||
return json["command_v2"].ToString();
|
||
else throw new Exception(html);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
EventClient.OnEvent("", $"抖音口令转换失败:{ex.Message}");
|
||
}
|
||
return String.Empty;
|
||
}
|
||
#endregion
|
||
|
||
|
||
|
||
}
|
||
}
|