mirror of
https://github.com/yaobiao131/downkyicore.git
synced 2025-08-10 00:52:31 +00:00
fix: 修复番剧无法解析高清晰度问题
This commit is contained in:
@@ -13,6 +13,7 @@ public class BangumiEpisode : BaseModel
|
||||
// badge_type
|
||||
[JsonProperty("bvid")] public string Bvid { get; set; }
|
||||
[JsonProperty("cid")] public long Cid { get; set; }
|
||||
[JsonProperty("ep_id")] public long EpisodeId { get; set; }
|
||||
[JsonProperty("cover")] public string Cover { get; set; }
|
||||
[JsonProperty("dimension")] public Dimension Dimension { get; set; }
|
||||
[JsonProperty("duration")] public long Duration { get; set; }
|
||||
|
||||
19
DownKyi.Core/BiliApi/VideoStream/Models/PlayView.cs
Normal file
19
DownKyi.Core/BiliApi/VideoStream/Models/PlayView.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DownKyi.Core.BiliApi.VideoStream.Models;
|
||||
|
||||
public class PlayViewOrigin
|
||||
{
|
||||
[JsonProperty("data")] public PlayView? Data { get; set; }
|
||||
}
|
||||
|
||||
public class PlayView
|
||||
{
|
||||
[JsonProperty("video_info")] public PlayUrl VideoInfo { get; set; } = new();
|
||||
[JsonProperty("plugins")] public List<PlayViewPlugin> Plugins { get; set; } = new();
|
||||
}
|
||||
|
||||
public class PlayViewPlugin
|
||||
{
|
||||
[JsonProperty("name")] public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using DownKyi.Core.BiliApi.Login;
|
||||
using DownKyi.Core.BiliApi.Models.Json;
|
||||
using DownKyi.Core.BiliApi.Sign;
|
||||
using DownKyi.Core.BiliApi.VideoStream.Models;
|
||||
using DownKyi.Core.Logging;
|
||||
using DownKyi.Core.Storage;
|
||||
using Newtonsoft.Json;
|
||||
using Console = DownKyi.Core.Utils.Debugging.Console;
|
||||
|
||||
@@ -116,7 +118,7 @@ public static class VideoStream
|
||||
/// <param name="cid"></param>
|
||||
/// <param name="quality"></param>
|
||||
/// <returns></returns>
|
||||
public static PlayUrl GetVideoPlayUrl(long avid, string bvid, long cid, int quality = 125)
|
||||
public static PlayUrl? GetVideoPlayUrl(long avid, string bvid, long cid, int quality = 125)
|
||||
{
|
||||
var parameters = new Dictionary<string, object?>
|
||||
{
|
||||
@@ -153,7 +155,7 @@ public static class VideoStream
|
||||
/// <param name="bvid"></param>
|
||||
/// <param name="p"></param>
|
||||
/// <returns></returns>
|
||||
public static PlayUrl GetVideoPlayUrlWebPage(long avid, string bvid, long cid, int p)
|
||||
public static PlayUrl? GetVideoPlayUrlWebPage(long avid, string bvid, long cid, int p)
|
||||
{
|
||||
var url = "https://www.bilibili.com/video";
|
||||
if (bvid == string.Empty)
|
||||
@@ -174,32 +176,86 @@ public static class VideoStream
|
||||
return playUrl;
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// 获取番剧的视频流
|
||||
// /// </summary>
|
||||
// /// <param name="avid"></param>
|
||||
// /// <param name="bvid"></param>
|
||||
// /// <param name="cid"></param>
|
||||
// /// <param name="quality"></param>
|
||||
// /// <returns></returns>
|
||||
// public static PlayUrl GetBangumiPlayUrl(long avid, string bvid, long cid, int quality = 125)
|
||||
// {
|
||||
// var baseUrl = $"https://api.bilibili.com/pgc/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048";
|
||||
// string url;
|
||||
// if (bvid != null)
|
||||
// {
|
||||
// url = $"{baseUrl}&bvid={bvid}";
|
||||
// }
|
||||
// else if (avid > -1)
|
||||
// {
|
||||
// url = $"{baseUrl}&aid={avid}";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// return GetPlayUrl(url);
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// 获取番剧的视频流
|
||||
/// </summary>
|
||||
/// <param name="avid"></param>
|
||||
/// <param name="bvid"></param>
|
||||
/// <param name="cid"></param>
|
||||
/// <param name="episodeId"></param>
|
||||
/// <param name="quality"></param>
|
||||
/// <returns></returns>
|
||||
public static PlayUrl GetBangumiPlayUrl(long avid, string bvid, long cid, int quality = 125)
|
||||
public static PlayUrl? GetBangumiPlayUrl(long episodeId, int quality = 125)
|
||||
{
|
||||
var baseUrl = $"https://api.bilibili.com/pgc/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048";
|
||||
string url;
|
||||
if (bvid != null)
|
||||
string? csrfToken = null;
|
||||
if (File.Exists(StorageManager.GetLogin()))
|
||||
{
|
||||
url = $"{baseUrl}&bvid={bvid}";
|
||||
}
|
||||
else if (avid > -1)
|
||||
{
|
||||
url = $"{baseUrl}&aid={avid}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
csrfToken = LoginHelper.GetLoginInfoCookies().First(cookie => cookie.Name == "bili_jct").Value;
|
||||
}
|
||||
|
||||
return GetPlayUrl(url);
|
||||
var url = "https://api.bilibili.com/ogv/player/playview";
|
||||
if (csrfToken != null) url += $"?csrf={csrfToken}";
|
||||
var parameters = new Dictionary<string, object?>
|
||||
{
|
||||
{ "scene", "normal" },
|
||||
{
|
||||
"video_index", new Dictionary<string, object?>
|
||||
{
|
||||
{ "bvid", null },
|
||||
{ "cid", null },
|
||||
{ "ogv_season_id", null },
|
||||
{ "ogv_episode_id", episodeId },
|
||||
}
|
||||
},
|
||||
{
|
||||
"video_param", new Dictionary<string, object>
|
||||
{
|
||||
{ "qn", quality }
|
||||
}
|
||||
},
|
||||
{
|
||||
"player_param", new Dictionary<string, object>
|
||||
{
|
||||
{ "fnver", 0 },
|
||||
{ "fnval", 4048 },
|
||||
{ "drm_tech_type", 2 },
|
||||
}
|
||||
},
|
||||
{
|
||||
"exp_info", new Dictionary<string, object>
|
||||
{
|
||||
{ "ogv_half_pay", true }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return GetPlayUrlBangumi(url, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -241,7 +297,7 @@ public static class VideoStream
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
private static PlayUrl GetPlayUrl(string url)
|
||||
private static PlayUrl? GetPlayUrl(string url)
|
||||
{
|
||||
const string referer = "https://www.bilibili.com";
|
||||
var response = WebClient.RequestWeb(url, referer);
|
||||
@@ -320,4 +376,26 @@ public static class VideoStream
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static PlayUrl? GetPlayUrlBangumi(string url, Dictionary<string, object?> parameters)
|
||||
{
|
||||
const string referer = "https://www.bilibili.com";
|
||||
var response = WebClient.RequestWeb(url, referer, "POST", parameters, json: true);
|
||||
var playViewOrigin = JsonConvert.DeserializeObject<PlayViewOrigin>(response);
|
||||
var playViewOriginData = playViewOrigin?.Data;
|
||||
if (playViewOriginData == null)
|
||||
{
|
||||
Console.PrintLine("GetPlayUrlBangumi()返回数据为空");
|
||||
LogManager.Error("GetPlayUrlBangumi()", new Exception("返回数据为空"));
|
||||
return null;
|
||||
}
|
||||
|
||||
var notLoginPlugin = playViewOriginData.Plugins.Find(plugin => plugin.Name == "NoLoginDrmLimitPanel");
|
||||
if (notLoginPlugin != null)
|
||||
{
|
||||
throw new Exception("当前视频需要登录才能观看,请先登录B站账号。");
|
||||
}
|
||||
|
||||
return playViewOriginData.VideoInfo;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace DownKyi.Core.BiliApi;
|
||||
|
||||
internal static class WebClient
|
||||
{
|
||||
private static readonly HttpClient _httpClient;
|
||||
private static readonly HttpClient HttpClient;
|
||||
private static string? _bvuid3 = string.Empty;
|
||||
private static string? _bvuid4 = string.Empty;
|
||||
|
||||
@@ -49,9 +49,9 @@ internal static class WebClient
|
||||
break;
|
||||
}
|
||||
|
||||
_httpClient = new HttpClient(socketsHandler);
|
||||
_httpClient.DefaultRequestHeaders.Add("User-Agent", SettingsManager.GetInstance().GetUserAgent());
|
||||
_httpClient.DefaultRequestHeaders.Add("accept-language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7");
|
||||
HttpClient = new HttpClient(socketsHandler);
|
||||
HttpClient.DefaultRequestHeaders.Add("User-Agent", SettingsManager.GetInstance().GetUserAgent());
|
||||
HttpClient.DefaultRequestHeaders.Add("accept-language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7");
|
||||
}
|
||||
|
||||
internal class SpiOrigin
|
||||
@@ -76,7 +76,7 @@ internal static class WebClient
|
||||
_bvuid4 = spi?.Data?.Bvuid4;
|
||||
}
|
||||
|
||||
public static string RequestWeb(string url, string? referer = null, string method = "GET", Dictionary<string, string>? parameters = null, int retry = 3)
|
||||
public static string RequestWeb(string url, string? referer = null, string method = "GET", Dictionary<string, object?>? parameters = null, int retry = 3, bool json = false)
|
||||
{
|
||||
if (retry <= 0)
|
||||
{
|
||||
@@ -121,7 +121,14 @@ internal static class WebClient
|
||||
|
||||
if (method == "POST" && parameters != null)
|
||||
{
|
||||
request.Content = new FormUrlEncodedContent(parameters);
|
||||
if (json)
|
||||
{
|
||||
request.Content = new StringContent(JsonSerializer.Serialize(parameters), System.Text.Encoding.UTF8, "application/json");
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Content = new FormUrlEncodedContent(parameters.Select(item => new KeyValuePair<string, string>(item.Key, item.Value?.ToString() ?? "")));
|
||||
}
|
||||
}
|
||||
else if (parameters != null)
|
||||
{
|
||||
@@ -130,7 +137,7 @@ internal static class WebClient
|
||||
request.RequestUri = new Uri(url);
|
||||
}
|
||||
|
||||
var response = _httpClient.Send(request);
|
||||
var response = HttpClient.Send(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using var reader = new StreamReader(response.Content.ReadAsStream());
|
||||
@@ -151,21 +158,21 @@ internal static class WebClient
|
||||
}
|
||||
|
||||
public static void DownloadFile(string url, string destFile, string? referer = null)
|
||||
{
|
||||
{
|
||||
using var fs = File.Create(destFile);
|
||||
using var stream = RequestStream(url, referer);
|
||||
stream?.CopyTo(fs);
|
||||
stream.CopyTo(fs);
|
||||
}
|
||||
|
||||
public static Stream? RequestStream(string url, string? referer = null,
|
||||
string method = "GET")
|
||||
public static Stream RequestStream(string url, string? referer = null, string method = "GET")
|
||||
{
|
||||
var request = new HttpRequestMessage(new HttpMethod(method), url);
|
||||
|
||||
|
||||
if (referer != null)
|
||||
{
|
||||
request.Headers.Referrer = new Uri(referer);
|
||||
}
|
||||
|
||||
if (!url.Contains("getLogin"))
|
||||
{
|
||||
request.Headers.Add("origin", "https://m.bilibili.com");
|
||||
@@ -175,8 +182,8 @@ internal static class WebClient
|
||||
request.Headers.Add("cookie", cookies);
|
||||
}
|
||||
}
|
||||
|
||||
var response = _httpClient.Send(request);
|
||||
|
||||
var response = HttpClient.Send(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return response.Content.ReadAsStream();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public class BangumiInfoService : IInfoService
|
||||
Avid = episode.Aid,
|
||||
Bvid = episode.Bvid,
|
||||
Cid = episode.Cid,
|
||||
EpisodeId = -1,
|
||||
EpisodeId = episode.EpisodeId,
|
||||
FirstFrame = episode.Cover,
|
||||
Order = order,
|
||||
Name = name,
|
||||
@@ -199,7 +199,7 @@ public class BangumiInfoService : IInfoService
|
||||
Avid = episode.Aid,
|
||||
Bvid = episode.Bvid,
|
||||
Cid = episode.Cid,
|
||||
EpisodeId = -1,
|
||||
EpisodeId = episode.EpisodeId,
|
||||
FirstFrame = episode.Cover,
|
||||
Order = order,
|
||||
Name = name,
|
||||
@@ -255,7 +255,7 @@ public class BangumiInfoService : IInfoService
|
||||
/// <param name="page"></param>
|
||||
public void GetVideoStream(VideoPage page)
|
||||
{
|
||||
var playUrl = VideoStream.GetBangumiPlayUrl(page.Avid, page.Bvid, page.Cid);
|
||||
var playUrl = VideoStream.GetBangumiPlayUrl(page.EpisodeId);
|
||||
Dispatcher.UIThread.Invoke(() => Utils.VideoPageInfo(playUrl, page));
|
||||
}
|
||||
|
||||
|
||||
@@ -418,8 +418,7 @@ public abstract class DownloadService
|
||||
};
|
||||
break;
|
||||
case PlayStreamType.Bangumi:
|
||||
downloading.PlayUrl ??= VideoStream.GetBangumiPlayUrl(downloading.DownloadBase.Avid,
|
||||
downloading.DownloadBase.Bvid, downloading.DownloadBase.Cid);
|
||||
downloading.PlayUrl ??= VideoStream.GetBangumiPlayUrl(downloading.DownloadBase.EpisodeId);
|
||||
break;
|
||||
case PlayStreamType.Cheese:
|
||||
downloading.PlayUrl ??= VideoStream.GetCheesePlayUrl(downloading.DownloadBase.Avid,
|
||||
|
||||
@@ -84,7 +84,7 @@ public class ViewBiliHelperViewModel : ViewModelBase
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Run(() => { Bvid = BvId.Av2Bv((ulong)avid); });
|
||||
await Task.Run(() => { Bvid = BvId.Av2Bv(avid); });
|
||||
}
|
||||
|
||||
// 输入bvid事件
|
||||
|
||||
@@ -190,7 +190,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
|
||||
|
||||
private DelegateCommand? _inputSearchCommand;
|
||||
|
||||
|
||||
|
||||
public DelegateCommand InputSearchCommand => _inputSearchCommand ??= new DelegateCommand(ExecuteInputSearchCommand);
|
||||
|
||||
@@ -260,6 +260,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
{
|
||||
Console.PrintLine("InputCommand()发生异常: {0}", e);
|
||||
LogManager.Error(Tag, e);
|
||||
EventAggregator.GetEvent<MessageEvent>().Publish(e.Message);
|
||||
|
||||
LoadingVisibility = false;
|
||||
ContentVisibility = false;
|
||||
@@ -334,13 +335,14 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedSection = VideoSections.FirstOrDefault(x => x.IsSelected);
|
||||
if (selectedSection?.VideoPages == null)
|
||||
if (selectedSection?.VideoPages == null)
|
||||
{
|
||||
IsSelectAll = false;
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var selectedPages = selectedSection.VideoPages
|
||||
.Where(x => x.IsSelected).ToList();
|
||||
foreach (var page in selectedPages)
|
||||
@@ -348,7 +350,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
grid.SelectedItems.Add(page);
|
||||
}
|
||||
|
||||
IsSelectAll = selectedSection.VideoPages.Count > 0 &&
|
||||
IsSelectAll = selectedSection.VideoPages.Count > 0 &&
|
||||
selectedPages.Count == selectedSection.VideoPages.Count;
|
||||
}
|
||||
|
||||
@@ -369,7 +371,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
}
|
||||
|
||||
var section = VideoSections.FirstOrDefault(item => item.IsSelected);
|
||||
|
||||
|
||||
if (section == null)
|
||||
{
|
||||
return;
|
||||
@@ -410,7 +412,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
|
||||
// 解析视频流事件
|
||||
private DelegateCommand<object>? _parseCommand;
|
||||
|
||||
|
||||
public DelegateCommand<object> ParseCommand => _parseCommand ??= new DelegateCommand<object>(ExecuteParseCommand, CanExecuteParseCommand);
|
||||
|
||||
/// <summary>
|
||||
@@ -439,6 +441,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
{
|
||||
Console.PrintLine("ParseCommand()发生异常: {0}", e);
|
||||
LogManager.Error(Tag, e);
|
||||
EventAggregator.GetEvent<MessageEvent>().Publish(e.Message);
|
||||
|
||||
LoadingVisibility = false;
|
||||
}
|
||||
@@ -558,6 +561,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
{
|
||||
Console.PrintLine("ParseCommand()发生异常: {0}", e);
|
||||
LogManager.Error(Tag, e);
|
||||
EventAggregator.GetEvent<MessageEvent>().Publish(e.Message);
|
||||
|
||||
LoadingVisibility = false;
|
||||
}
|
||||
@@ -609,8 +613,7 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
VideoSections.Clear();
|
||||
CaCheVideoSections.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新页面的统一方法
|
||||
@@ -624,8 +627,8 @@ public class ViewVideoDetailViewModel : ViewModelBase
|
||||
if (_infoService == null || refresh)
|
||||
{
|
||||
// 视频
|
||||
if (ParseEntrance.IsAvUrl(input) || ParseEntrance.IsBvUrl(input)
|
||||
|| ParseEntrance.IsAvId(input) || ParseEntrance.IsBvId(input))
|
||||
if (ParseEntrance.IsAvUrl(input) || ParseEntrance.IsBvUrl(input)
|
||||
|| ParseEntrance.IsAvId(input) || ParseEntrance.IsBvId(input))
|
||||
{
|
||||
_infoService = new VideoInfoService(input);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user