diff --git a/Auth/FakeBrowser.cs b/Auth/FakeBrowser.cs new file mode 100644 index 0000000..2105cc8 --- /dev/null +++ b/Auth/FakeBrowser.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Playwright; + +namespace BiliApi.Auth +{ + internal class FakeBrowser + { + IPlaywright pw; + IBrowser browser; + IBrowserContext context; + + public FakeBrowser() + { + } + + public async Task InitAsync() + { + if (pw == null) + pw = await Playwright.CreateAsync(); + if (browser == null) + browser = await pw.Chromium.LaunchAsync(new BrowserTypeLaunchOptions + { + Headless = true + }); + if (context == null) + context = await browser.NewContextAsync(); + } + + public async Task> GetContextCookies(string url) + { + return await context.CookiesAsync(url); + } + + public async Task GetContextCookies() + { + var cookies = await context.CookiesAsync(); + CookieCollection result = new CookieCollection(); + foreach(BrowserContextCookiesResult cc in cookies) + { + System.Net.Cookie ccc = new System.Net.Cookie(); + ccc.Domain = cc.Domain; + ccc.Name = cc.Name; + ccc.Path = cc.Path; + ccc.Value = cc.Value; + ccc.HttpOnly = cc.HttpOnly; + result.Add(ccc); + } + return result; + } + + public async Task AddContextCookies(CookieCollection cookies) + { + List cookieList = new List(); + foreach(System.Net.Cookie c in cookies) + { + Microsoft.Playwright.Cookie cc = new Microsoft.Playwright.Cookie(); + cc.Value = c.Value; + cc.Name = c.Name; + cc.Path = c.Path; + cc.Domain = c.Domain; + cc.HttpOnly = c.HttpOnly; + cookieList.Add(cc); + } + await context.AddCookiesAsync(cookieList); + } + + public async Task AddContextCookies(List cookies) + { + await context.AddCookiesAsync(cookies); + } + + public async Task GetPageAsync(string url) + { + var page = await context.NewPageAsync(); + await page.GotoAsync(url, new PageGotoOptions + { + WaitUntil = WaitUntilState.NetworkIdle + }); + return await page.ContentAsync(); + } + } +} diff --git a/Auth/QRLogin.cs b/Auth/QRLogin.cs index 8138e68..5d3768f 100644 --- a/Auth/QRLogin.cs +++ b/Auth/QRLogin.cs @@ -7,6 +7,7 @@ using BiliApi.Exceptions; using System.Threading; using System.Drawing; +using Microsoft.Playwright; namespace BiliApi.Auth { @@ -17,11 +18,13 @@ public class QRLogin : IAuthBase { const string URL_GETKEY = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate"; const string URL_STATUS = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key="; - + FakeBrowser fb = new FakeBrowser(); public CookieCollection Cookies { get; private set; } public LoginQRCode QRToken { private set; get; } public bool LoggedIn { get; private set; } + public bool UseFakeBrowser { get; private set; } + public struct LoginQRCode { public string ScanUrl, OAuthKey; @@ -50,7 +53,7 @@ public enum QRState public string Serilize() { JArray jb = new JArray(); - foreach (Cookie c in Cookies) + foreach (System.Net.Cookie c in Cookies) { JObject j = new JObject(); j.Add("k", c.Name); @@ -62,10 +65,11 @@ public string Serilize() return jb.ToString(); } - public QRLogin() + public QRLogin(bool fake_browser = true) { QRToken = GetNewQRItem(); LoggedIn = false; + UseFakeBrowser = fake_browser; } public QRLogin(LoginQRCode code) @@ -80,7 +84,7 @@ public QRLogin(string serilizedJson) Cookies = new CookieCollection(); foreach (JObject jb in ja) { - Cookies.Add(new Cookie( + Cookies.Add(new System.Net.Cookie( jb.Value("k"), jb.Value("v"), jb.Value("p"), jb.Value("d") )); } @@ -168,7 +172,17 @@ public QRState GetQRState(LoginQRCode qr) return QRState.Expired; case 0: { - Cookies = res.Cookies; + if (UseFakeBrowser) + { + fb.InitAsync().Wait(); + fb.AddContextCookies(res.Cookies).Wait(); + fb.GetPageAsync("https://bilibili.com").Wait(); + Cookies = fb.GetContextCookies().Result; + } + else + { + Cookies = res.Cookies; + } LoggedIn = IsOnline(); if (!LoggedIn) throw new AuthenticateFailedException(jb); return QRState.LoggedIn; diff --git a/BiliApi.csproj b/BiliApi.csproj index dc79f68..88e752b 100644 --- a/BiliApi.csproj +++ b/BiliApi.csproj @@ -9,8 +9,9 @@ - - + + + diff --git a/BiliPrivMessage/PrivMessage.cs b/BiliPrivMessage/PrivMessage.cs index 09815fa..21969c8 100644 --- a/BiliPrivMessage/PrivMessage.cs +++ b/BiliPrivMessage/PrivMessage.cs @@ -6,7 +6,8 @@ namespace BiliApi.BiliPrivMessage { public class PrivMessage : IComparable { - public int recieiver_id, timestamp, msgtype; + public long recieiver_id, timestamp; + public int msgtype; public long msg_seqno; public long msg_key; public BiliUser talker; @@ -15,9 +16,9 @@ public class PrivMessage : IComparable public PrivMessage(JToken json,BiliSession sess) { - recieiver_id = json.Value("receiver_id"); + recieiver_id = json.Value("receiver_id"); timestamp = json.Value("timestamp"); - talker = BiliUser.getUser(json.Value("sender_uid"),sess); + talker = BiliUser.getUser(json.Value("sender_uid"),sess); msgtype = json.Value("msg_type"); msg_seqno = json.Value("msg_seqno"); msg_key = json.Value("msg_key"); diff --git a/BiliPrivMessage/PrivMessageSession.cs b/BiliPrivMessage/PrivMessageSession.cs index 69f7d7c..a9fc5db 100644 --- a/BiliPrivMessage/PrivMessageSession.cs +++ b/BiliPrivMessage/PrivMessageSession.cs @@ -10,7 +10,7 @@ namespace BiliApi.BiliPrivMessage { - public class PrivMessageSession + public class PrivMessageSession : IEquatable { public bool loaded = false; public long talker_id; @@ -40,7 +40,7 @@ public PrivMessageSession(long targetuid, BiliSession sess) public void init(JToken json) { - talker_id = json.Value("talker_id"); + talker_id = json.Value("talker_id"); sessiontype = json.Value("session_type"); session_ts = json.Value("session_ts"); unread_cnt = json.Value("unread_count"); @@ -211,12 +211,20 @@ public bool sendMessage(JObject job) public bool SendImage(Bitmap bmap) { //上传图片 - MemoryStream ms = new MemoryStream(); - bmap.Save(ms, ImageFormat.Png); + using (MemoryStream ms = new MemoryStream()) + { + bmap.Save(ms, ImageFormat.Png); + return SendImage(ms.ToArray()); + } + } + + public bool SendImage(byte[] bmap) + { + //上传图片 var upload = sess.PostFile( "https://api.vc.bilibili.com/api/v1/drawImage/upload", "https://message.bilibili.com", - ms.ToArray(), + bmap, "file_up", "image/png", "picturen.png", @@ -237,7 +245,7 @@ public bool SendImage(Bitmap bmap) payload.Add("height", jb["data"]["image_height"]); payload.Add("imageType", "png"); payload.Add("original", "1"); - payload.Add("size", ms.ToArray().Length / 1024); + payload.Add("size", bmap.Length / 1024); return sendMessage(payload); } @@ -276,5 +284,10 @@ public override int GetHashCode() { return talker_id.GetHashCode(); } + + public bool Equals(PrivMessageSession other) + { + return talker_id.Equals(other.talker_id); + } } } diff --git a/BiliPrivMessage/PrivMsgReceiverLite.cs b/BiliPrivMessage/PrivMsgReceiverLite.cs new file mode 100644 index 0000000..725a560 --- /dev/null +++ b/BiliPrivMessage/PrivMsgReceiverLite.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using BiliApi.Exceptions; + +namespace BiliApi.BiliPrivMessage +{ + public class PrivMsgReceiverLite + { + BiliSession sess; + public DateTime LastUpdate = new DateTime(1999, 12, 12); + + public PrivMsgReceiverLite(BiliSession session) + { + sess = session; + } + + /// + /// 获取(自上次更新以来)新的私信会话 + /// + /// 新会话列表 + /// API出错 + public List GetNewSessions() + { + string rtv = sess._get_with_cookies("https://api.vc.bilibili.com/session_svr/v1/session_svr/new_sessions?begin_ts=" + + TimestampHandler.GetTimeStamp16(LastUpdate) + "&build=0&mobi_app=web"); + sess._get_with_cookies("https://api.vc.bilibili.com/session_svr/v1/session_svr/ack_sessions?begin_ts=" + + TimestampHandler.GetTimeStamp16(LastUpdate) + "&build=0&mobi_app=web"); + LastUpdate = DateTime.Now; + JObject raw_json = (JObject)JsonConvert.DeserializeObject(rtv); + if (raw_json.Value("code") != 0) + {//发生错误 + throw new ApiRemoteException(raw_json); + } + List rtvlist = new List(); + foreach (JToken jobj in raw_json["data"]["session_list"]) + { + var psess = new PrivMessageSession(jobj, sess); + if(psess.lastmessage.talker.uid == sess.getCurrentUserId()) + { + continue; + } + rtvlist.Add(psess); + } + return rtvlist; + } + } +} diff --git a/BiliPrivMessage/PrivSessionManager.cs b/BiliPrivMessage/PrivSessionManager.cs index 00a31b0..fd7178c 100644 --- a/BiliPrivMessage/PrivSessionManager.cs +++ b/BiliPrivMessage/PrivSessionManager.cs @@ -66,10 +66,11 @@ public void smartRefresh() public void updateSessions() { - sess._get_with_cookies("https://api.vc.bilibili.com/session_svr/v1/session_svr/new_sessions?begin_ts=" + last_refresh + "&build=0&mobi_app=web"); - string rtv = sess._get_with_cookies("https://api.vc.bilibili.com/session_svr/v1/session_svr/ack_sessions?begin_ts=" + last_refresh + "&build=0&mobi_app=web"); - lastjson = rtv; + string rtv = sess._get_with_cookies("https://api.vc.bilibili.com/session_svr/v1/session_svr/new_sessions?begin_ts=" + last_refresh + "&build=0&mobi_app=web"); JObject raw_json = (JObject)JsonConvert.DeserializeObject(rtv); + rtv = sess._get_with_cookies("https://api.vc.bilibili.com/session_svr/v1/session_svr/ack_sessions?begin_ts=" + last_refresh + "&build=0&mobi_app=web"); + lastjson = rtv; + //JObject raw_json = (JObject)JsonConvert.DeserializeObject(rtv); if (raw_json.Value("code") != 0) {//发生错误 throw new ApiRemoteException(raw_json); diff --git a/BiliUser.cs b/BiliUser.cs index 3044226..246973e 100644 --- a/BiliUser.cs +++ b/BiliUser.cs @@ -259,7 +259,7 @@ public List getMedals() return metals; } - public static List getMedals(BiliSession sess, long uid) + public static List getMedals(BiliSession sess, long uid, bool _ = false) { List metals = new List(); JObject jb = JObject.Parse(sess.getBiliUserMedal(uid)); diff --git a/TimestampHandler.cs b/TimestampHandler.cs index 9a8f64f..bc6e39c 100644 --- a/TimestampHandler.cs +++ b/TimestampHandler.cs @@ -32,7 +32,7 @@ public static int GetTimeStamp(DateTime dateTime) public static long GetTimeStamp16(DateTime dateTime) { #pragma warning disable CS0618 // '“TimeZone”已过时:“System.TimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo instead.” - return (long)(dateTime - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))).TotalMilliseconds; + return (long)(dateTime - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))).TotalMilliseconds * 1000; #pragma warning restore CS0618 // '“TimeZone”已过时:“System.TimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo instead.” } }