支持杜比全景声、杜比视界

croire 3 years ago
parent c664ecd9f6
commit 0a37220fe9

@ -6,6 +6,8 @@ namespace DownKyi.Core.BiliApi.BiliUtils
{ {
private static readonly List<Quality> resolutions = new List<Quality> private static readonly List<Quality> resolutions = new List<Quality>
{ {
new Quality { Name = "超高清 8K", Id = 127 },
new Quality { Name = "杜比视界", Id = 126 },
new Quality { Name = "HDR 真彩", Id = 125 }, new Quality { Name = "HDR 真彩", Id = 125 },
new Quality { Name = "4K 超清", Id = 120 }, new Quality { Name = "4K 超清", Id = 120 },
new Quality { Name = "1080P 60帧", Id = 116 }, new Quality { Name = "1080P 60帧", Id = 116 },
@ -22,6 +24,7 @@ namespace DownKyi.Core.BiliApi.BiliUtils
new Quality { Name = "64K", Id = 30216 }, new Quality { Name = "64K", Id = 30216 },
new Quality { Name = "132K", Id = 30232 }, new Quality { Name = "132K", Id = 30232 },
new Quality { Name = "192K", Id = 30280 }, new Quality { Name = "192K", Id = 30280 },
new Quality { Name = "Dolby Atmos", Id = 30250 },
}; };
/// <summary> /// <summary>

@ -16,5 +16,7 @@ namespace DownKyi.Core.BiliApi.VideoStream.Models
public List<PlayUrlDashVideo> Video { get; set; } public List<PlayUrlDashVideo> Video { get; set; }
[JsonProperty("audio")] [JsonProperty("audio")]
public List<PlayUrlDashVideo> Audio { get; set; } public List<PlayUrlDashVideo> Audio { get; set; }
[JsonProperty("dolby")]
public PlayUrlDashDolby Dolby { get; set; }
} }
} }

@ -0,0 +1,13 @@
using DownKyi.Core.BiliApi.Models;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace DownKyi.Core.BiliApi.VideoStream.Models
{
public class PlayUrlDashDolby : BaseModel
{
// type
[JsonProperty("audio")]
public List<PlayUrlDashVideo> Audio { get; set; }
}
}

@ -8,9 +8,9 @@ namespace DownKyi.Core.BiliApi.VideoStream.Models
{ {
[JsonProperty("id")] [JsonProperty("id")]
public int Id { get; set; } public int Id { get; set; }
[JsonProperty("baseUrl")] [JsonProperty("base_url")]
public string BaseUrl { get; set; } public string BaseUrl { get; set; }
[JsonProperty("backupUrl")] [JsonProperty("backup_url")]
public List<string> BackupUrl { get; set; } public List<string> BackupUrl { get; set; }
// bandwidth // bandwidth
[JsonProperty("mimeType")] [JsonProperty("mimeType")]

@ -93,7 +93,7 @@ namespace DownKyi.Core.BiliApi.VideoStream
/// <returns></returns> /// <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)
{ {
string baseUrl = $"https://api.bilibili.com/x/player/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=80"; string baseUrl = $"https://api.bilibili.com/x/player/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048";
string url; string url;
if (bvid != null) { url = $"{baseUrl}&bvid={bvid}"; } if (bvid != null) { url = $"{baseUrl}&bvid={bvid}"; }
else if (avid > -1) { url = $"{baseUrl}&aid={avid}"; } else if (avid > -1) { url = $"{baseUrl}&aid={avid}"; }
@ -112,7 +112,7 @@ namespace DownKyi.Core.BiliApi.VideoStream
/// <returns></returns> /// <returns></returns>
public static PlayUrl GetBangumiPlayUrl(long avid, string bvid, long cid, int quality = 125) public static PlayUrl GetBangumiPlayUrl(long avid, string bvid, long cid, int quality = 125)
{ {
string baseUrl = $"https://api.bilibili.com/pgc/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=80"; string baseUrl = $"https://api.bilibili.com/pgc/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048";
string url; string url;
if (bvid != null) { url = $"{baseUrl}&bvid={bvid}"; } if (bvid != null) { url = $"{baseUrl}&bvid={bvid}"; }
else if (avid > -1) { url = $"{baseUrl}&aid={avid}"; } else if (avid > -1) { url = $"{baseUrl}&aid={avid}"; }
@ -131,7 +131,7 @@ namespace DownKyi.Core.BiliApi.VideoStream
/// <returns></returns> /// <returns></returns>
public static PlayUrl GetCheesePlayUrl(long avid, string bvid, long cid, long episodeId, int quality = 125) public static PlayUrl GetCheesePlayUrl(long avid, string bvid, long cid, long episodeId, int quality = 125)
{ {
string baseUrl = $"https://api.bilibili.com/pugv/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=80"; string baseUrl = $"https://api.bilibili.com/pugv/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048";
string url; string url;
if (bvid != null) { url = $"{baseUrl}&bvid={bvid}"; } if (bvid != null) { url = $"{baseUrl}&bvid={bvid}"; }
else if (avid > -1) { url = $"{baseUrl}&aid={avid}"; } else if (avid > -1) { url = $"{baseUrl}&aid={avid}"; }

@ -49,7 +49,13 @@ namespace DownKyi.Core.BiliApi
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method; request.Method = method;
request.Timeout = 30 * 1000; request.Timeout = 30 * 1000;
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36";
// MacOS Safari
string safari = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15";
// Windows 10 Chrome
string chrome = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36";
request.UserAgent = chrome;
//request.ContentType = "application/json,text/html,application/xhtml+xml,application/xml;charset=UTF-8"; //request.ContentType = "application/json,text/html,application/xhtml+xml,application/xml;charset=UTF-8";
request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"; request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7";
request.Headers["accept-encoding"] = "gzip, deflate, br"; request.Headers["accept-encoding"] = "gzip, deflate, br";

@ -211,6 +211,7 @@
<Compile Include="BiliApi\VideoStream\Models\PlayerV2.cs" /> <Compile Include="BiliApi\VideoStream\Models\PlayerV2.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrl.cs" /> <Compile Include="BiliApi\VideoStream\Models\PlayUrl.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDash.cs" /> <Compile Include="BiliApi\VideoStream\Models\PlayUrlDash.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDashDolby.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDashVideo.cs" /> <Compile Include="BiliApi\VideoStream\Models\PlayUrlDashVideo.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDurl.cs" /> <Compile Include="BiliApi\VideoStream\Models\PlayUrlDurl.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlSupportFormat.cs" /> <Compile Include="BiliApi\VideoStream\Models\PlayUrlSupportFormat.cs" />

@ -1,15 +1,31 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace DownKyi.Core.Utils namespace DownKyi.Core.Utils
{ {
public static class ListHelper public static class ListHelper
{ {
/// <summary>
/// 判断ObservableCollection中是否存在不存在则添加
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="item"></param>
public static void AddUnique<T>(ObservableCollection<T> list, T item)
{
if (!list.Contains(item))
{
list.Add(item);
}
}
/// <summary> /// <summary>
/// 判断List中是否存在不存在则添加 /// 判断List中是否存在不存在则添加
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="list"></param> /// <param name="list"></param>
/// <param name="item"></param>
public static void AddUnique<T>(List<T> list, T item) public static void AddUnique<T>(List<T> list, T item)
{ {
if (!list.Exists(t => t.Equals(item))) if (!list.Exists(t => t.Equals(item)))

@ -119,6 +119,15 @@ namespace DownKyi.Services.Download
} }
}; };
} }
// 将所有视频设置为选中
foreach (VideoSection section in videoSections)
{
foreach (var item in section.VideoPages)
{
item.IsSelected = true;
}
}
} }
/// <summary> /// <summary>
@ -200,6 +209,9 @@ namespace DownKyi.Services.Download
{ {
foreach (VideoPage page in section.VideoPages) foreach (VideoPage page in section.VideoPages)
{ {
// 只下载选中项,跳过未选中项
if (!page.IsSelected) { continue; }
// 没有解析的也跳过 // 没有解析的也跳过
if (page.PlayUrl == null) { continue; } if (page.PlayUrl == null) { continue; }
@ -282,7 +294,7 @@ namespace DownKyi.Services.Download
.SetVideoZone(videoInfoView.VideoZone.Split('>')[0]) .SetVideoZone(videoInfoView.VideoZone.Split('>')[0])
.SetAudioQuality(page.AudioQualityFormat) .SetAudioQuality(page.AudioQualityFormat)
.SetVideoQuality(page.VideoQuality == null ? "" : page.VideoQuality.QualityFormat) .SetVideoQuality(page.VideoQuality == null ? "" : page.VideoQuality.QualityFormat)
.SetVideoCodec(page.VideoQuality == null ? "" : page.VideoQuality.SelectedVideoCodec.Contains("AVC") ? "AVC" : page.VideoQuality.SelectedVideoCodec.Contains("HEVC") ? "HEVC" : ""); .SetVideoCodec(page.VideoQuality == null ? "" : page.VideoQuality.SelectedVideoCodec.Contains("AVC") ? "AVC" : page.VideoQuality.SelectedVideoCodec.Contains("HEVC") ? "HEVC" : page.VideoQuality.SelectedVideoCodec.Contains("Dolby") ? "Dolby Vision" : "");
string filePath = Path.Combine(directory, fileName.RelativePath()); string filePath = Path.Combine(directory, fileName.RelativePath());
// 视频类别 // 视频类别

@ -71,6 +71,17 @@ namespace DownKyi.Services.Download
} }
} }
// 避免Dolby==null及其它未知情况直接使用异常捕获
try
{
// Dolby Atmos
if (downloading.AudioCodec.Id == 30250)
{
downloadAudio = downloading.PlayUrl.Dash.Dolby.Audio[0];
}
}
catch (Exception) { }
return DownloadVideo(downloading, downloadAudio); return DownloadVideo(downloading, downloadAudio);
} }
@ -892,7 +903,7 @@ namespace DownKyi.Services.Download
$"Cookie: {LoginHelper.GetLoginInfoCookiesString()}", $"Cookie: {LoginHelper.GetLoginInfoCookiesString()}",
$"Origin: https://www.bilibili.com", $"Origin: https://www.bilibili.com",
$"Referer: https://www.bilibili.com", $"Referer: https://www.bilibili.com",
$"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 91.0.4472.77 Safari / 537.36" $"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"
}; };
AriaConfig config = new AriaConfig() AriaConfig config = new AriaConfig()

@ -5,6 +5,7 @@ using DownKyi.Core.Settings.Models;
using DownKyi.Core.Utils; using DownKyi.Core.Utils;
using DownKyi.ViewModels.PageViewModels; using DownKyi.ViewModels.PageViewModels;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
namespace DownKyi.Services namespace DownKyi.Services
@ -94,13 +95,13 @@ namespace DownKyi.Services
/// <param name="playUrl"></param> /// <param name="playUrl"></param>
/// <param name="defaultAudioQuality"></param> /// <param name="defaultAudioQuality"></param>
/// <returns></returns> /// <returns></returns>
private static List<string> GetAudioQualityFormatList(PlayUrl playUrl, int defaultAudioQuality) private static ObservableCollection<string> GetAudioQualityFormatList(PlayUrl playUrl, int defaultAudioQuality)
{ {
List<string> audioQualityFormatList = new List<string>(); List<string> audioQualityFormatList = new List<string>();
if (playUrl.Dash.Audio == null) if (playUrl.Dash.Audio == null)
{ {
return audioQualityFormatList; return new ObservableCollection<string>();
} }
foreach (PlayUrlDashVideo audio in playUrl.Dash.Audio) foreach (PlayUrlDashVideo audio in playUrl.Dash.Audio)
@ -118,7 +119,7 @@ namespace DownKyi.Services
audioQualityFormatList.Sort(new StringLogicalComparer<string>()); audioQualityFormatList.Sort(new StringLogicalComparer<string>());
audioQualityFormatList.Reverse(); audioQualityFormatList.Reverse();
return audioQualityFormatList; return new ObservableCollection<string>(audioQualityFormatList);
} }
/// <summary> /// <summary>
@ -221,7 +222,7 @@ namespace DownKyi.Services
/// <returns></returns> /// <returns></returns>
internal static string GetVideoCodecName(string origin) internal static string GetVideoCodecName(string origin)
{ {
return origin.Contains("avc") ? "H.264/AVC" : origin.Contains("hev") ? "H.265/HEVC" : origin.Contains("dvh") ? "dolby" : ""; return origin.Contains("avc") ? "H.264/AVC" : origin.Contains("hev") ? "H.265/HEVC" : origin.Contains("dvh") || origin.Contains("hvc") ? "Dolby Vision" : "";
} }
} }

@ -1,6 +1,10 @@
using DownKyi.Core.BiliApi.VideoStream.Models; using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.VideoStream.Models;
using DownKyi.Core.Utils;
using Prism.Commands;
using Prism.Mvvm; using Prism.Mvvm;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace DownKyi.ViewModels.PageViewModels namespace DownKyi.ViewModels.PageViewModels
{ {
@ -43,8 +47,8 @@ namespace DownKyi.ViewModels.PageViewModels
set => SetProperty(ref duration, value); set => SetProperty(ref duration, value);
} }
private List<string> audioQualityFormatList; private ObservableCollection<string> audioQualityFormatList;
public List<string> AudioQualityFormatList public ObservableCollection<string> AudioQualityFormatList
{ {
get => audioQualityFormatList; get => audioQualityFormatList;
set => SetProperty(ref audioQualityFormatList, value); set => SetProperty(ref audioQualityFormatList, value);
@ -71,5 +75,37 @@ namespace DownKyi.ViewModels.PageViewModels
set => SetProperty(ref videoQuality, value); set => SetProperty(ref videoQuality, value);
} }
#region
// 视频画质选择事件
private DelegateCommand videoQualitySelectedCommand;
public DelegateCommand VideoQualitySelectedCommand => videoQualitySelectedCommand ?? (videoQualitySelectedCommand = new DelegateCommand(ExecuteVideoQualitySelectedCommand));
/// <summary>
/// 视频画质选择事件
/// </summary>
private void ExecuteVideoQualitySelectedCommand()
{
// 杜比视界
string dolby = Constant.GetAudioQualities()[3].Name;
if (VideoQuality.Quality == 126)
{
ListHelper.AddUnique(AudioQualityFormatList, dolby);
AudioQualityFormat = dolby;
}
else
{
if (AudioQualityFormatList.Contains(dolby))
{
AudioQualityFormatList.Remove(dolby);
AudioQualityFormat = AudioQualityFormatList[0];
}
}
}
#endregion
} }
} }

@ -125,6 +125,7 @@ namespace DownKyi.ViewModels.Settings
// 优先下载音质 // 优先下载音质
AudioQualityList = Constant.GetAudioQualities(); AudioQualityList = Constant.GetAudioQualities();
AudioQualityList.RemoveAt(3);
// 文件命名格式 // 文件命名格式
SelectedFileName = new ObservableCollection<DisplayFileNamePart>(); SelectedFileName = new ObservableCollection<DisplayFileNamePart>();

@ -619,14 +619,14 @@
DisplayMemberBinding="{Binding Order}" DisplayMemberBinding="{Binding Order}"
Header="{DynamicResource Order}" /> Header="{DynamicResource Order}" />
<GridViewColumn <GridViewColumn
Width="550" Width="540"
DisplayMemberBinding="{Binding Name}" DisplayMemberBinding="{Binding Name}"
Header="{DynamicResource Name}" /> Header="{DynamicResource Name}" />
<GridViewColumn <GridViewColumn
Width="100" Width="100"
DisplayMemberBinding="{Binding Duration}" DisplayMemberBinding="{Binding Duration}"
Header="{DynamicResource Duration}" /> Header="{DynamicResource Duration}" />
<GridViewColumn Width="100" Header="{DynamicResource AudioQuality}"> <GridViewColumn Width="120" Header="{DynamicResource AudioQuality}">
<GridViewColumn.CellTemplate> <GridViewColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Grid> <Grid>
@ -644,7 +644,13 @@
IsSynchronizedWithCurrentItem="True" IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding VideoQualityList, Mode=TwoWay, IsAsync=True}" ItemsSource="{Binding VideoQualityList, Mode=TwoWay, IsAsync=True}"
SelectedItem="{Binding VideoQuality, Mode=TwoWay}" SelectedItem="{Binding VideoQuality, Mode=TwoWay}"
SelectedValuePath="Quality" /> SelectedValuePath="Quality">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding VideoQualitySelectedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</GridViewColumn.CellTemplate> </GridViewColumn.CellTemplate>

Loading…
Cancel
Save