Compare commits

..
245 Commits
Author SHA1 Message Date
croire dc4033cd8b 修改版本号到1.5.6 2023-01-06 16:59:36 +08:00
croire 844a110edf 修复弹幕无法下载的bug 2023-01-06 16:02:48 +08:00
croire c95840c681 Fix FormatFileName 2023-01-06 15:27:25 +08:00
croire ade4c78190 修正多线程下载的bug 2023-01-06 15:09:52 +08:00
croire 8958cf46c4 修改版本号到1.5.5 2022-11-06 15:49:39 +08:00
croire b4d619eca9 Merge branch 'v1.5.x-feature-view-follow' into v1.5.x 2022-11-05 21:34:02 +08:00
croire 05b678e2b8 完成粉丝页面 2022-11-05 21:30:47 +08:00
croire 60813ce903 完成关注页面 2022-11-05 19:59:49 +08:00
croire 4188daca72 去掉警告 2022-11-05 19:29:00 +08:00
croire 84c3403a94 完成PageFriendsFollowing的左侧table加载 2022-11-04 16:07:54 +08:00
croire 5ade29a4f6 更新分区列表 2022-10-23 15:56:59 +08:00
croire 4b36040f39 纠正用户关注和粉丝的对应英文 2022-10-23 11:03:53 +08:00
croire 3eead3252e Merge branch 'v1.5.x' into v1.5.x-feature-view-follow 2022-10-21 23:46:08 +08:00
croire 1c2cffccda 更新依赖包 2022-10-21 23:34:35 +08:00
croire 47fe322244 微调代码 2022-10-20 22:34:21 +08:00
croire 79ccebf160 优先解析视频编码顺序为AV1、HEVC、AVC 2022-10-20 22:30:46 +08:00
croire a95014cee5 修复命名格式无AV1编码的问题 2022-10-20 16:14:19 +08:00
croire aaae6352bc 更新依赖包 2022-10-16 22:14:27 +08:00
croire 8b6e286d18 修改Friends包名 2022-10-16 17:33:07 +08:00
croire 0356b94d71 修改Friends包名 2022-10-16 17:04:08 +08:00
croire 0c5cc2d7ca 修改Friends包名 2022-10-16 16:58:24 +08:00
croire 0cb78dc396 合并主要开发分支,解决冲突 2022-10-16 16:54:50 +08:00
croire e750a19f0f 修复自定义aria服务器监听端口设置无效的问题 2022-10-16 14:52:37 +08:00
croire 6c28569401 修改版本号到1.5.4 2022-10-16 14:19:36 +08:00
croire 0dde0bceb5 支持AV1编码视频 2022-10-16 14:03:15 +08:00
croire a35d8a0334 支持Hi-Res无损音频格式 2022-10-16 02:13:50 +08:00
croire 74a0f7b96d 音视频分离页面微调 2022-10-16 00:52:38 +08:00
croire 3092033906 增加了 对新的分享链接的直接识别 2022-10-16 00:27:11 +08:00
croire 338d7d3c87 音视频分离支持多选 2022-10-16 00:20:10 +08:00
croire 4c260854f3 视频无杜比视界时支持杜比全景声 2022-07-28 10:58:37 +08:00
croire bbe818d125 支持自定义aria服务器token 2022-07-19 01:12:35 +08:00
croire 3b2d9d3bb3 支持自定义aria服务器,本地测试通过 2022-07-19 01:06:36 +08:00
croire aac78d508a 支持UP主用户空间的合集和列表 2022-06-16 00:12:48 +08:00
croire 4fdb1c3f16 完成合集和列表api 2022-06-15 22:35:40 +08:00
croire 6b3044e9f7 新增查询用户的合集和列表api 2022-06-07 16:44:57 +08:00
croire 0fc08b12e9 Merge branch 'v1.5.x' into v1.5.x-feature-view-follow 2022-06-05 21:42:45 +08:00
croire 755790aae0 修改版本号到1.5.3 2022-06-05 12:00:57 +08:00
croire e597596e66 新增下载流的https控制 2022-06-05 00:20:00 +08:00
croire 80c1024b51 每个视频页面都增加下载管理页面入口 2022-06-04 23:42:14 +08:00
croire e268f731c4 优化封面命名2 2022-06-04 23:05:07 +08:00
croire 78b247d4a1 修复监听剪贴板失效的问题 2022-06-04 22:01:03 +08:00
croire 049778b76f 优化UI 2022-06-04 21:42:42 +08:00
croire 591ea2cf06 修复批量操作时偶尔崩溃的问题 2022-06-04 21:42:34 +08:00
croire 682e80ae0e 优化封面命名 2022-06-04 21:19:37 +08:00
croire c977ca928c 新增支持出行分区 2022-06-04 21:08:51 +08:00
croire 2c11e4243e 暂存修改 2022-06-04 21:01:28 +08:00
croire 9ef5354e73 修改注释 2022-05-15 16:13:47 +08:00
croire bb760b238d Merge branch 'v1.5.x' into v1.5.x-feature-view-follow 2022-05-15 14:58:30 +08:00
croire 79b7fbeb7a 修改版本号到1.5.2 2022-05-14 22:23:03 +08:00
croire 9a932b8759 处理异常 2022-05-14 22:15:02 +08:00
croire 3f8a1f7fd3 Merge branch 'v1.5.x-feature-inner-downloader' into v1.5.x 2022-05-14 21:56:56 +08:00
croire 6e6e5a4751 新增下载器切换 2022-05-14 21:56:27 +08:00
croire c7e4719152 完成内建下载器 2022-05-14 17:23:28 +08:00
croire 39e5d28a2d 更新依赖版本 2022-05-11 22:17:47 +08:00
croire 6e6e17e10a Merge branch 'v1.5.x' into v1.5.x-feature-inner-downloader 2022-05-11 21:48:22 +08:00
croire 32c892c380 创建内建下载器 2022-05-11 21:47:46 +08:00
croire 34d242780c 解决问题 SSL/TLS handshake failure 2022-05-11 19:59:27 +08:00
croire bb1637071f 下载列表监听事件优化 2022-05-10 22:59:20 +08:00
croire 1dff44f9d4 回退aria设置 2022-05-10 18:59:47 +08:00
croire 516c4cc1bc Merge branch 'v1.5.x' into v1.5.x-feature-view-follow
# Conflicts:
#	DownKyi/DownKyi.csproj
2022-05-10 12:58:02 +08:00
croire 4be9a74816 默认的Aria服务器端口号改为6801 2022-05-10 11:58:23 +08:00
croire 10ab358538 修改版本号到1.5.1 2022-05-09 21:57:20 +08:00
croire c4594cf4f7 修复未获取到杜比全景声却仍然显示出此选项的问题 2022-05-09 21:39:38 +08:00
croire ad5e3c2f70 调整依赖exe程序 2022-05-09 21:12:11 +08:00
croire e37b9d0e76 Aria下载器添加header 2022-05-09 20:27:24 +08:00
croire 568851bfaa 向下载管理页面添加弹窗提示 2022-05-07 21:00:13 +08:00
croire 76c968ac39 完成AlertDialog 2022-05-07 12:55:09 +08:00
croire 588599e1cf 当复制视频详情页的输入框中的字符时,不读取剪贴板内容 2022-05-03 23:37:25 +08:00
croire bf87565165 调整文件 2022-05-03 22:29:11 +08:00
croire 040d236310 WebP.Net重命名为WebPSharp 2022-05-03 22:21:55 +08:00
croire 36b6b174e6 支持WebP图像,改用WebP.Net库 2022-04-27 22:49:03 +08:00
croire 47e068e80c 修复运动分区无法显示的问题 2022-04-22 22:31:05 +08:00
croire 4d7ffe112f 新增文件命名模块中序号格式设置 2022-04-22 22:10:41 +08:00
croire d449c42bec 修复文件名异常导致的下载失败 2022-04-17 15:19:36 +08:00
croire a0a1d659ec 修复偶尔VideoSection重复的问题 2022-04-17 15:00:36 +08:00
croire ebfba6a59f 优化代码 2022-04-17 15:00:06 +08:00
croire 0c559a9bf0 支持webp图像 2022-04-05 17:19:05 +08:00
croire 363bf2ccce 修改版本号到1.5.0 2022-04-04 16:51:36 +08:00
croire 4733d1e1bf 修复下载完成后的动作设置无效的问题 2022-04-04 16:48:55 +08:00
croire 1027a9e702 数据库中基础数据丢失的item不读取 2022-04-04 00:41:35 +08:00
croire f199f35247 增加代码来源注释 2022-04-04 00:27:31 +08:00
croire 8ec6c21505 文件命名格式设置可以拖拽 2022-04-04 00:25:34 +08:00
croire ec8b03166f 修复下载内容设置偶尔不生效的问题 2022-04-03 21:13:51 +08:00
croire 8a2274fc08 如果图片格式为webp时无法加载,捕获此异常,未解决问题 2022-04-03 01:51:01 +08:00
croire cb2a6055a4 增加null判断 2022-03-27 23:15:00 +08:00
croire 19a11c6fe3 更新ffmpeg的LICENSE 2022-03-26 19:56:18 +08:00
croire 6392311d31 修改版本号到1.5.0-alpha7 2022-03-26 19:27:37 +08:00
croire 8dfd2e11f9 批量下载时过滤UGC、其他季或花絮内容 2022-03-26 18:51:31 +08:00
croire 94237b5ee9 设置下载视频内容 2022-03-26 16:40:03 +08:00
croire 74a9450680 保存下载视频内容到设置 2022-03-26 16:20:53 +08:00
croire e64d27dc0a 修复笔误 2022-03-26 16:09:00 +08:00
croire 9b8e143135 微调界面 2022-03-26 15:48:35 +08:00
croire cd1e6608d3 新增“解析后自动下载已解析视频”设置 2022-03-26 15:48:27 +08:00
croire 6cd1d58755 更新ffmpeg为gpl版本 2022-03-26 14:13:27 +08:00
croire 1dc0ef02bd 修复只下载音频失败的问题 2022-03-26 14:13:08 +08:00
croire ce9b292500 解决Settings被占用无法读取的问题 2022-03-25 20:22:40 +08:00
croire a5f7b1e7ac 修复因路径导致无法下载的问题 2022-03-22 23:30:24 +08:00
croire 07dcba5714 默认的aria的文件预分配改为none 2022-03-22 22:49:56 +08:00
croire 6f67462ee9 设置增加初始值 2022-03-22 22:47:15 +08:00
croire 0126c1b21f 去水印默认尺寸为0 2022-03-22 12:52:36 +08:00
croire 68025448b6 设置管理打印异常log 2022-03-22 12:29:48 +08:00
croire 3938a3bfd2 修复Release版本中无法正确关闭数据库的问题 2022-03-20 17:37:57 +08:00
croire 023eff8e81 修改版本号到1.5.0-alpha6 2022-03-20 00:26:33 +08:00
croire f0c4553997 Merge branch 'v1.5.x-fix-sqlite-locked' into v1.5.x 2022-03-20 00:22:46 +08:00
croire 796be050a5 UpdateUserInfo()添加异常捕获 2022-03-19 20:34:47 +08:00
croire 73b2fa9739 UpdateUserInfo()添加异常捕获 2022-03-19 20:29:19 +08:00
croire 59c75e3fdd Login()添加异常捕获 2022-03-19 20:06:29 +08:00
croire dc199a4559 修改版本号到1.5.0-alpha5 2022-03-19 17:10:40 +08:00
croire 56db28c913 修复视频标题和分P标题相同时找不到下载文件的问题 2022-03-19 17:00:30 +08:00
croire 8317865b41 150%缩放下的窗口不超出屏幕 2022-03-19 16:32:43 +08:00
croire 287b3b528d 减小界面最小尺寸 2022-03-17 22:30:21 +08:00
croire 62deb1e40e 注释coverDb.Close()和headerDb.Close()的调用 2022-03-17 22:18:22 +08:00
croire e838202f43 Merge branch 'v1.5.x-fix-sqlite-locked' into v1.5.x 2022-03-17 00:09:17 +08:00
croire 08224774c3 aria服务器添加UserAgent 2022-03-17 00:08:51 +08:00
croire fdba90ff1e 修复多线程操作sqlite的异常问题 2022-03-15 23:30:48 +08:00
croire 127ffd5dc6 机器码去掉硬盘信息 2022-03-15 19:46:47 +08:00
croire 084d4ab363 整理代码格式 2022-03-15 19:43:44 +08:00
croire 5959088dfc 合并255 pull request 2022-03-14 13:06:05 +08:00
croire 7253a0ee12 好友页面框架搭建 2022-03-13 17:18:18 +08:00
croire e50159fdb6 完善文件命名中的时间格式 2022-03-13 11:43:24 +08:00
croire 42fbfaeb1f Merge branch 'v1.5.x-feature-extend-FileName' into v1.5.x 2022-03-13 11:39:06 +08:00
croire 778d2829fa 文件命名格式中,时间格式可设置 2022-03-13 11:37:53 +08:00
croire 440ebff101 修改版本号到1.5.0-alpha4 2022-03-12 23:29:26 +08:00
croire b0947151e7 去除重复的参数 2022-03-12 23:12:37 +08:00
croire 99b3e5393d 优化UI显示 2022-03-12 23:02:05 +08:00
croire 3a918a6e5c 合并253 pull request 2022-03-12 23:01:24 +08:00
croire 60880abb8b 将配置文件路径改为当前程序目录下 2022-03-12 22:29:20 +08:00
croire a7cc7d3ba1 整理代码 2022-03-12 13:17:00 +08:00
croire c2b70c3ab1 修复因Query数据库异常导致数据库锁死的问题 2022-03-12 12:52:34 +08:00
croire f6536284e9 修复DownloadBase为空时崩溃的问题 2022-03-12 12:51:51 +08:00
croire 6f21977c8f 合并252 pull request 2022-03-12 12:51:14 +08:00
croire 9fda62b962 修改版本号到1.5.0-alpha3 2022-03-12 02:10:23 +08:00
croire f7cd3c734c SettingsManager类添加异常捕获 2022-03-12 01:55:28 +08:00
croire f93306509d HardDisk类添加异常捕获 2022-03-12 01:50:53 +08:00
croire 6c8a738e02 添加条件编译 2022-03-12 01:25:59 +08:00
croire 4a3f0d43eb 捕获数据库操作的所有异常 2022-03-12 01:20:45 +08:00
croire 013c6f2fe7 修复用户空间性别保密时崩溃的问题 2022-03-12 01:11:39 +08:00
croire 52e36b0fd7 避免下载时的可能出现的问题 2022-03-08 23:21:52 +08:00
croire 093652f0d6 取消下载时不弹出提示 2022-03-08 22:55:45 +08:00
croire d98730b64f 修复存在episode时VideoPage.Owner为null的问题 2022-03-08 22:53:02 +08:00
croire a023935c7c 解决一些问题 2022-03-08 12:30:49 +08:00
croire 1b0bacbd33 修复下载提示为负数的问题 2022-03-08 11:58:35 +08:00
croire fbda4865af 添加私有属性保存输入字符串,避免被用户修改 2022-03-07 20:16:13 +08:00
croire dcc54225db 修改版本号到1.5.0-alpha2 2022-03-06 23:29:03 +08:00
croire 32aeb711ac 修复全选按钮选中的问题 2022-03-06 23:15:03 +08:00
croire 012cb42042 优化我的收藏夹和我的订阅页面UI 2022-03-06 21:56:31 +08:00
croire d0b2f577c8 使用深复制,保证外部修改list后,不会影响其他调用处 2022-03-06 20:56:12 +08:00
croire d4693f525e 解决Constant.GetAudioQualities被外部修改list后,影响其他调用处的问题 2022-03-06 20:54:07 +08:00
croire 4ad4de5578 修复我的收藏夹界面全选按钮选中的问题 2022-03-06 20:42:36 +08:00
croire d5f4902663 捕获重复下载图片后File.Move()的异常 2022-03-06 16:32:41 +08:00
croire efa01234cb 设置选中的视频编码 2022-03-06 16:32:00 +08:00
croire 062bb81589 解决视频编码可能出现空白项的问题 2022-03-06 14:12:11 +08:00
croire 9df0a74fe2 Merge branch 'v1.5.x-feature-extend-FileName' into v1.5.x 2022-03-06 13:28:33 +08:00
croire c1ea829215 文件命名格式新增视频发布时间 2022-03-06 13:25:23 +08:00
croire 0257df9fbe 文件命名格式新增UP信息 2022-03-05 17:01:03 +08:00
croire 35e6d2e8c8 捕获Constant.GetAudioQualities()中item数量异常,暂时未知原因 2022-03-05 16:16:19 +08:00
croire 1ba868d613 文件命名格式新增avid、bvid、cid 2022-03-05 16:13:02 +08:00
croire 4773a2b0c8 更新解析URL的注释 2022-03-05 02:07:06 +08:00
croire 41a7d71a98 修改AppInfo 2022-03-04 12:30:20 +08:00
croire 6ce7b69a56 完成稍后再看页面;修复一些问题 2022-03-04 12:08:41 +08:00
croire ed180a0699 完成历史记录页面;修复一些问题 2022-03-04 01:02:42 +08:00
croire 1a7c9cd6fc 新增历史记录和稍后再看api 2022-03-02 23:24:10 +08:00
croire fea42637b2 硬编码字符串迁移至语言模块中 2022-03-02 00:46:31 +08:00
croire 62a0528112 完成“我的订阅”页面;修复一些问题 2022-03-02 00:39:29 +08:00
croire 7b8b6b9009 Brotli.NET更新到.Net 4.7.2 2022-02-28 23:07:25 +08:00
croire 656b877cba ffmpeg更新为5.0,UI显示 2022-02-28 21:42:17 +08:00
croire e45107b635 完成我的收藏夹页面;修复一些问题 2022-02-28 21:36:29 +08:00
croire 7b5b7de1fb 标题导航从访问网页改为视频详情页 2022-02-27 23:18:47 +08:00
croire 700b4df9da 解决解析视频时VideoQuality属性为null时崩溃的问题 2022-02-27 22:49:39 +08:00
croire a9b84875c3 完成Channel页面 2022-02-27 20:39:37 +08:00
croire b6e993e1e3 修复Publication页面的一些问题 2022-02-27 20:39:18 +08:00
croire f52230166d 支持https://www.bilibili.com/medialist/play/ml94341835/BV1Ei4y1t7wf链接 2022-02-27 19:49:42 +08:00
croire 1d7e156c11 支持https://www.bilibili.com/medialist/play/ml94341835/BV1Ei4y1t7wf链接 2022-02-27 17:31:31 +08:00
croire 99a83b06a9 修改欢迎页 2022-02-27 16:59:53 +08:00
croire fe9c9ff415 完成Publication页面 2022-02-27 16:35:34 +08:00
croire b31c7830d4 完成CustomPager 2022-02-26 22:23:59 +08:00
croire 4b1af53db7 添加CustomPager 2022-02-25 23:44:37 +08:00
croire 30535c11cd 合集和列表的API备注 2022-02-14 16:59:10 +08:00
croire dbc6804dca 欢迎页增加版本号,开源提示 2022-02-14 16:58:50 +08:00
croire 123b74d85f 调整用户空间的界面UI 2022-02-13 01:38:27 +08:00
croire 67400b45bf 支持用户空间链接中mid在中间的情况(https://space.bilibili.com/27899754/channel/series) 2022-02-13 01:03:54 +08:00
croire 8f6553d401 完成UserSpace页面 2022-02-13 00:41:58 +08:00
croire c2351ae21b 设置文件在release时加密 2022-02-02 11:13:48 +08:00
croire 4c09ded9c1 调整UserAgent 2022-02-02 10:06:45 +08:00
croire 0a37220fe9 支持杜比全景声、杜比视界 2022-01-31 02:09:19 +08:00
croire c664ecd9f6 解决下载的一些bug;收藏夹中的一些bug;整理代码 2022-01-30 20:38:24 +08:00
croire 195838929e 屏蔽收藏夹中的已失效视频 2022-01-30 20:35:37 +08:00
croire c552411b91 移除文件夹名/文件名前导和尾部的dot符 2022-01-30 20:32:42 +08:00
croire 3f0457b7db 增加Aria部分代码的健壮性 2022-01-30 19:50:57 +08:00
croire 994eb158b9 收藏夹中的图片使用缩略图 2022-01-22 16:07:14 +08:00
croire ab97c43a8f 实现下载完成页面的排序功能 2022-01-12 13:44:18 +08:00
croire 384b394014 重启后不会自动开始下载 2022-01-12 01:13:40 +08:00
croire 3b2de59d0b 优化下载中列表UI 2022-01-12 01:11:30 +08:00
croire ba1235669c 完成下载中和下载完成列表的UI 2022-01-12 00:32:09 +08:00
croire a95070ffae 微调我的用户空间页面 2022-01-11 13:25:40 +08:00
croire 1962150ec6 统一处理用户输入,分别调用 2022-01-11 13:16:17 +08:00
croire 5ffdfcab77 整理代码 2022-01-11 02:26:05 +08:00
croire fcf388870f 完成我的用户空间页面设计 2022-01-11 02:13:42 +08:00
croire fd7fabeaba 更新项目文件 2022-01-09 19:15:14 +08:00
croire bd61bd6dcf 添加用户空间默认背景图片资源 2022-01-09 19:13:50 +08:00
croire 86de932f56 添加性别图标资源 2022-01-09 19:13:31 +08:00
croire 8715e4bb29 添加等级图标资源 2022-01-09 19:13:14 +08:00
croire 1880a2a806 优化欢迎页显示 2022-01-07 19:56:21 +08:00
croire f10c2d2d80 添加欢迎页;完成下载列表存储功能 2022-01-07 01:04:59 +08:00
croire 53be15c7ab 一点补充 2022-01-05 23:55:38 +08:00
croire fb0fcf1e7e 整理代码。将models中的viewModel迁移至ViewModels中;下载列表的数据库设计;其他异常检测 2022-01-05 23:26:39 +08:00
croire 158c77f951 设置json取消格式化 2022-01-04 23:51:07 +08:00
croire 2ffa86420a 下载列表添加无数据显示 2021-12-23 13:17:56 +08:00
croire e06f3a51ce 修复缺少System.Runtime.CompilerServices.Unsafe.dll的问题 2021-12-23 01:13:43 +08:00
croire 49380ee775 更新依赖的版本 2021-12-23 01:13:13 +08:00
croire e0d02a2622 微调下载列表显示 2021-12-23 00:41:05 +08:00
croire 65f87c8517 修复下载列表视频分区图标部分不显示的问题 2021-12-23 00:23:44 +08:00
croire 59d9854611 修复封面下载 2021-12-23 00:09:07 +08:00
croire 580705652f 修复封面下载 2021-12-23 00:06:19 +08:00
croire 71a4d657c1 修复封面下载 2021-12-23 00:01:13 +08:00
croire 3c2ef7cf1e 调整代码结构 2021-12-22 23:07:10 +08:00
croire 31d82a9309 增加音质选择设置 2021-12-22 22:32:32 +08:00
croire 2ccdff96a8 文件命名格式设置添加恢复默认按钮 2021-12-22 22:09:55 +08:00
croire 251619a4ba 基本实现下载功能 2021-12-22 00:09:24 +08:00
croire 7c43873e87 完善下载服务中,20211221暂存 2021-12-21 01:04:37 +08:00
croire 966b707165 修复设置中文件命名格式的一些问题 2021-12-19 00:51:20 +08:00
croire 6a3b1e96b5 文件命名系统添加视频章节 2021-12-19 00:00:02 +08:00
croire a809245e95 文件命名系统设置 2021-12-18 23:43:39 +08:00
croire e781c72d68 删除不需要的设置 2021-12-17 23:30:15 +08:00
croire 0a26704f2a 开发下载服务中,保存工作,20211215 2021-12-15 21:42:16 +08:00
croire be6b0d47a5 开发下载服务中,保存工作 2021-11-19 00:08:12 +08:00
croire 35fa8d6cd5 解决当视频时长>60分钟后,弹幕的时间有误导致弹幕卡住的问题 2021-11-10 23:11:32 +08:00
croire 4d2590605e PagePublicFavorites开发工作中,完成页面设计,20211026暂存 2021-10-26 23:51:49 +08:00
croire fee511cf33 PagePublicFavorites开发工作中,完成页面设计,20211024暂存 2021-10-24 17:48:54 +08:00
croire c48ecc86c9 解决监听剪贴板事件连续执行2次的问题 2021-10-24 15:38:47 +08:00
croire e0f3c978cd 解决同时向数据库插入时冲突的问题 2021-10-24 15:03:26 +08:00
croire 653aff5a02 PagePublicFavorites开发工作中,20211023暂存 2021-10-24 00:06:39 +08:00
croire 9e685be6a2 监听剪贴板同步支持 2021-10-23 16:15:46 +08:00
croire 88bf600c40 下载文件夹选择器修改为下载设置器,并增加下载内容选择项 2021-10-23 13:42:30 +08:00
croire 3699afe0fb 选择视频dialog函数提取到DialogUtils类中 2021-10-23 00:42:55 +08:00
croire 0e9f12d3c6 完成B站收藏夹api 2021-10-23 00:10:06 +08:00
croire 5a58a2e284 Debug修改为Debugging 2021-10-21 12:44:14 +08:00
croire c63597efbd Debug修改为Debugging 2021-10-21 12:39:18 +08:00
croire c41c81db3d 短链接支持番剧 2021-10-21 12:15:14 +08:00
croire f5febf148a 合并 2021-10-21 12:04:10 +08:00
croire 1e851ce1c2 支持短链接和/s的url 2021-10-21 12:03:02 +08:00
croire 58c67c86d2 支持短链接和/s的url 2021-10-21 11:47:31 +08:00
croire 7a0f3df4fb 新增收藏夹信息api 2021-10-21 10:21:48 +08:00
flyself 67e7f38f9d 添加项目文件。 2021-10-20 15:26:20 +08:00
flyself af5c453337 添加 .gitignore 和 .gitattributes。 2021-10-20 15:25:49 +08:00
561 changed files with 3367 additions and 2195 deletions
View File
+2
View File
@@ -0,0 +1,2 @@
!runtimes/x64
!runtimes/x86
+47
View File
@@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
<Version>2.1.1.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Brotli.NET</PackageId>
<Authors>Jinjun Xie</Authors>
<Company>Jinjun Xie</Company>
<Copyright>Copyright Jinjun Xie 2016</Copyright>
<PackageLicenseUrl></PackageLicenseUrl>
<PackageProjectUrl>https://github.com/XieJJ99/brotli.net</PackageProjectUrl>
<PackageTags>Brotli Compress Decompress .NET Standard Stream</PackageTags>
<PackageReleaseNotes>Add async stream support, update brotli core to v1.0.9</PackageReleaseNotes>
<Description>Supported on dotnet standard2(Windows/Linux/OSX), provide similar interface to Google offical API.Quality and window control is supported.
The library use the native runtime and its performance should be better than System.IO.Compress.BrotliStream.
For more document,please visit https://github.com/XieJJ99/brotli.net.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<AssemblyVersion>2.1.1.0</AssemblyVersion>
<Platforms>AnyCPU;x64;x86</Platforms>
</PropertyGroup>
<ItemGroup>
<!-- <None Update="runtimes\**" Pack="true" PackagePath="." /> -->
<None Include="runtimes\**">
<PackagePath>runtimes</PackagePath>
<Pack>true</Pack>
</None>
</ItemGroup>
<Import Project="build\Brotli.NET.targets" />
<ItemGroup>
<None Remove="build\Brotli.NET.targets~RF6be2dbfa.TMP" />
</ItemGroup>
<ItemGroup>
<!-- <None Update="runtimes\**" Pack="true" PackagePath="." /> -->
<!-- <None Include="runtimes\**\*.dll">
<PackagePath>build\runtimes</PackagePath>
<Pack>true</Pack>
</None> -->
<None Include="build\Brotli.NET.targets">
<PackagePath>build</PackagePath>
<Pack>true</Pack>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" Condition=" '$(TargetFramework)' == 'net45' " />
</ItemGroup>
</Project>
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Brotli
{
public enum BrotliDecoderParameter:int
{
DisableRingBufferReallocation=0,
LargeWindow=1,
}
}
+22
View File
@@ -0,0 +1,22 @@
namespace Brotli
{
public enum BrotliDecoderResult:int
{
/// <summary>
/// Decoding error, e.g. corrupt input or memory allocation problem
/// </summary>
Error = 0,
/// <summary>
/// Decoding successfully completed
/// </summary>
Success = 1,
/// <summary>
/// Partially done; should be called again with more input
/// </summary>
NeedsMoreInput = 2,
/// <summary>
/// Partially done; should be called again with more output
/// </summary>
NeedsMoreOutput = 3
};
}
@@ -0,0 +1,26 @@
namespace Brotli
{
public enum BrotliEncoderOperation : int
{
Process = 0,
/// <summary>
/// Request output stream to flush. Performed when input stream is depleted
/// and there is enough space in output stream.
/// </summary>
Flush = 1,
/// <summary>
/// Request output stream to finish. Performed when input stream is depleted
/// and there is enough space in output stream.
/// </summary>
Finish = 2,
/// <summary>
/// Emits metadata block to stream. Stream is soft-flushed before metadata
/// block is emitted. CAUTION: when operation is started, length of the input
/// buffer is interpreted as length of a metadata block; changing operation,
/// expanding or truncating input before metadata block is completely emitted
/// will cause an error; metadata block must not be greater than 16MiB.
/// </summary>
EmitMetadata = 3
};
}
@@ -0,0 +1,22 @@
namespace Brotli
{
public enum BrotliEncoderParameter : int
{
Mode = 0,
/// <summary>
/// Controls the compression-speed vs compression-density tradeoffs. The higher
/// the quality, the slower the compression. Range is 0 to 11.
/// </summary>
Quality = 1,
/// <summary>
/// Base 2 logarithm of the sliding window size. Range is 10 to 24.
/// </summary>
LGWin = 2,
/// <summary>
/// Base 2 logarithm of the maximum input block size. Range is 16 to 24.
/// If set to 0, the value will be set based on the quality.
/// </summary>
LGBlock = 3
};
}
@@ -0,0 +1,25 @@
using System;
namespace Brotli
{
public class BrotliDecodeException : BrotliException
{
public int Code { get; set; }
public String ErrorText { get; set; }
public BrotliDecodeException(int code, String errorText) : base() {
Code = code;
ErrorText = errorText;
}
public BrotliDecodeException(String message, int code, String errorText) : base(message) {
Code = code;
ErrorText = errorText;
}
public BrotliDecodeException(String message, Exception innerException, int code, String errorText) : base(message, innerException) {
Code = code;
ErrorText = errorText;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
using System;
namespace Brotli
{
public class BrotliException:Exception
{
public BrotliException() : base() { }
public BrotliException(String message) : base(message) { }
public BrotliException(String message, Exception innerException) : base(message, innerException) { }
}
}
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Brotli
{
public static class BrotliExtensions
{
/// <summary>
/// Compress the data with brotli
/// </summary>
/// <param name="rawData">inputData</param>
/// <param name="quality">quality,0~11</param>
/// <param name="window">compress window(10~24)</param>
/// <returns>compressed bytes</returns>
public static byte[] CompressToBrotli(this byte[] rawData, uint quality = 5, uint window = 22)
{
if (rawData == null) throw new ArgumentNullException(nameof(rawData));
using (var msInput = new System.IO.MemoryStream(rawData))
{
return CompressToBrotli(msInput, quality, window);
}
}
/// <summary>
/// Compress the data with brotli
/// </summary>
/// <param name="inStream">input stream</param>
/// <param name="quality">quality,0~11</param>
/// <param name="window">compress window(10~24)</param>
/// <returns>compressed bytes</returns>
public static byte[] CompressToBrotli(this System.IO.Stream inStream, uint quality = 5, uint window = 22)
{
using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
{
CompressToBrotli(inStream, msOutput, quality, window);
var output = msOutput.ToArray();
return output;
}
}
/// <summary>
/// Compress the data with brotli
/// </summary>
/// <param name="inStream">input stream</param>
/// <param name="destStream">dest output stream</param>
/// <param name="quality">quality,0~11</param>
/// <param name="window">compress window(10~24)</param>
public static void CompressToBrotli(this System.IO.Stream inStream, System.IO.Stream destStream, uint quality = 5, uint window = 22)
{
using (BrotliStream bs = new BrotliStream(destStream, System.IO.Compression.CompressionMode.Compress))
{
bs.SetQuality(quality);
bs.SetWindow(window);
inStream.CopyTo(bs);
bs.Close();
}
}
public static byte[] DecompressFromBrotli(this byte[] rawData)
{
if (rawData == null) throw new ArgumentNullException(nameof(rawData));
using (var msInput = new System.IO.MemoryStream(rawData))
{
return DecompressFromBrotli(msInput);
}
}
public static byte[] DecompressFromBrotli(this System.IO.Stream inStream)
{
using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
{
DecompressFromBrotli(inStream, msOutput);
var output = msOutput.ToArray();
return output;
}
}
public static void DecompressFromBrotli(this System.IO.Stream inStream,System.IO.Stream destStream)
{
using (BrotliStream bs = new BrotliStream(inStream, System.IO.Compression.CompressionMode.Decompress))
{
bs.CopyTo(destStream);
destStream.Flush();
}
}
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace Brotli
{
internal class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None, TaskCreationOptions.None,
TaskContinuationOptions.None, TaskScheduler.Default);
internal static void RunSync(Func<Task> func, bool await = false)
{
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
CultureInfo culture = CultureInfo.CurrentCulture;
_myTaskFactory.StartNew(delegate
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func();
}).Unwrap().ConfigureAwait(await).GetAwaiter().GetResult();
}
// Microsoft.AspNet.Identity.AsyncHelper
internal static TResult RunSync<TResult>(Func<Task<TResult>> func, bool await = false)
{
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
CultureInfo culture = CultureInfo.CurrentCulture;
return _myTaskFactory.StartNew<Task<TResult>>(delegate
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func();
}).Unwrap<TResult>().ConfigureAwait(await).GetAwaiter().GetResult();
}
internal static TResult RunSync<TResult>(Func<object, Task<TResult>> func, object state, bool await = false)
{
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
CultureInfo culture = CultureInfo.CurrentCulture;
return _myTaskFactory.StartNew<Task<TResult>>(delegate
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func(state);
}, state).Unwrap<TResult>().ConfigureAwait(await).GetAwaiter().GetResult();
}
internal static TResult RunSync<TResult>(Func<object, Task<TResult>> func, object state, CancellationToken cancellationToken, bool await = false)
{
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
CultureInfo culture = CultureInfo.CurrentCulture;
return _myTaskFactory.StartNew<Task<TResult>>(delegate
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func(state);
}, state, cancellationToken).Unwrap<TResult>().ConfigureAwait(await).GetAwaiter().GetResult();
}
}
}
+316
View File
@@ -0,0 +1,316 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Brotli
{
public class Brolib
{
static bool UseX86 = IntPtr.Size == 4;
#region Encoder
public static IntPtr BrotliEncoderCreateInstance()
{
if (UseX86)
{
return Brolib32.BrotliEncoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
else
{
return Brolib64.BrotliEncoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
}
public static IntPtr GetModuleHandle(String moduleName)
{
IntPtr r = IntPtr.Zero;
foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
{
if (String.Compare(mod.ModuleName,moduleName,true)==0)
{
r = mod.BaseAddress;
break;
}
}
return r;
}
public static void FreeLibrary()
{
IntPtr libHandle = IntPtr.Zero;
libHandle = GetModuleHandle(LibPathBootStrapper.LibPath);
if (libHandle!=IntPtr.Zero)
{
NativeLibraryLoader.FreeLibrary(libHandle);
}
}
public static bool BrotliEncoderSetParameter(IntPtr state, BrotliEncoderParameter parameter, UInt32 value)
{
if (UseX86)
{
return Brolib32.BrotliEncoderSetParameter(state, parameter, value);
}
else
{
return Brolib64.BrotliEncoderSetParameter(state, parameter, value);
}
}
//@to rewrite using the following APIs
//BrotliGetDictionary
//BrotliGetTransforms
//BrotliSetDictionaryData
//BrotliTransformDictionaryWord
//public static void BrotliEncoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict)
//{
// if (UseX86)
// {
// Brolib32.BrotliEncoderSetCustomDictionary(state, size, dict);
// }
// else
// {
// Brolib64.BrotliEncoderSetCustomDictionary(state, size, dict);
// }
//}
public static bool BrotliEncoderCompressStream(
IntPtr state, BrotliEncoderOperation op, ref UInt32 availableIn,
ref IntPtr nextIn, ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut)
{
if (UseX86)
{
return Brolib32.BrotliEncoderCompressStream(state, op, ref availableIn, ref nextIn, ref availableOut, ref nextOut, out totalOut);
}
else
{
UInt64 availableInL = availableIn;
UInt64 availableOutL = availableOut;
UInt64 totalOutL = 0;
var r = Brolib64.BrotliEncoderCompressStream(state, op, ref availableInL, ref nextIn, ref availableOutL, ref nextOut, out totalOutL);
availableIn = (UInt32)availableInL;
availableOut = (UInt32)availableOutL;
totalOut = (UInt32)totalOutL;
return r;
}
}
public static bool BrotliEncoderIsFinished(IntPtr state)
{
if (UseX86)
{
return Brolib32.BrotliEncoderIsFinished(state);
}
else
{
return Brolib64.BrotliEncoderIsFinished(state);
}
}
public static void BrotliEncoderDestroyInstance(IntPtr state)
{
if (UseX86)
{
Brolib32.BrotliEncoderDestroyInstance(state);
}
else
{
Brolib64.BrotliEncoderDestroyInstance(state);
}
}
public static UInt32 BrotliEncoderVersion()
{
if (UseX86)
{
return Brolib32.BrotliEncoderVersion();
}
else
{
return Brolib64.BrotliEncoderVersion();
}
}
public static IntPtr BrotliDecoderTakeOutput(IntPtr state, ref UInt32 size)
{
if (UseX86)
{
return Brolib32.BrotliDecoderTakeOutput(state, ref size);
}
else
{
UInt64 longSize = size;
var r = Brolib64.BrotliDecoderTakeOutput(state, ref longSize);
size = (UInt32)longSize;
return r;
}
}
#endregion
#region Decoder
public static IntPtr BrotliDecoderCreateInstance()
{
if (UseX86)
{
return Brolib32.BrotliDecoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
else
{
return Brolib64.BrotliDecoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
}
public static bool BrotliDecoderSetParameter(IntPtr state, BrotliDecoderParameter param, UInt32 value)
{
if (UseX86)
{
return Brolib32.BrotliDecoderSetParameter(state,param,value);
}
else
{
return Brolib64.BrotliDecoderSetParameter(state, param, value);
}
}
//@to rewrite using the following APIs
//BrotliGetDictionary
//BrotliGetTransforms
//BrotliSetDictionaryData
//BrotliTransformDictionaryWord
//public static void BrotliDecoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict)
//{
// if (UseX86)
// {
// Brolib32.BrotliDecoderSetCustomDictionary(state, size, dict);
// }
// else
// {
// Brolib64.BrotliDecoderSetCustomDictionary(state, size, dict);
// }
//}
public static BrotliDecoderResult BrotliDecoderDecompressStream(
IntPtr state, ref UInt32 availableIn,
ref IntPtr nextIn, ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut)
{
if (UseX86)
{
return Brolib32.BrotliDecoderDecompressStream(state, ref availableIn, ref nextIn, ref availableOut, ref nextOut, out totalOut);
}
else
{
UInt64 availableInL = availableIn;
UInt64 availableOutL = availableOut;
UInt64 totalOutL = 0;
var r = Brolib64.BrotliDecoderDecompressStream(state, ref availableInL, ref nextIn, ref availableOutL, ref nextOut, out totalOutL);
availableIn = (UInt32)availableInL;
availableOut = (UInt32)availableOutL;
totalOut = (UInt32)totalOutL;
return r;
}
}
public static void BrotliDecoderDestroyInstance(IntPtr state)
{
if (UseX86)
{
Brolib32.BrotliDecoderDestroyInstance(state);
}
else
{
Brolib64.BrotliDecoderDestroyInstance(state);
}
}
public static UInt32 BrotliDecoderVersion()
{
if (UseX86)
{
return Brolib32.BrotliDecoderVersion();
}
else
{
return Brolib64.BrotliDecoderVersion();
}
}
public static bool BrotliDecoderIsUsed(IntPtr state)
{
if (UseX86)
{
return Brolib32.BrotliDecoderIsUsed(state);
}
else
{
return Brolib64.BrotliDecoderIsUsed(state);
}
}
public static bool BrotliDecoderIsFinished(IntPtr state)
{
if (UseX86)
{
return Brolib32.BrotliDecoderIsFinished(state);
}
else
{
return Brolib64.BrotliDecoderIsFinished(state);
}
}
public static Int32 BrotliDecoderGetErrorCode(IntPtr state)
{
if (UseX86)
{
return Brolib32.BrotliDecoderGetErrorCode(state);
}
else
{
return Brolib64.BrotliDecoderGetErrorCode(state);
}
}
public static String BrotliDecoderErrorString(Int32 code)
{
IntPtr r = IntPtr.Zero;
if (UseX86)
{
r = Brolib32.BrotliDecoderErrorString(code);
}
else
{
r = Brolib64.BrotliDecoderErrorString(code);
}
if (r != IntPtr.Zero)
{
return Marshal.PtrToStringAnsi(r);
}
return String.Empty;
}
public static IntPtr BrotliEncoderTakeOutput(IntPtr state, ref UInt32 size)
{
if (UseX86)
{
return Brolib32.BrotliEncoderTakeOutput(state, ref size);
}
else
{
UInt64 longSize = size;
var r = Brolib64.BrotliEncoderTakeOutput(state, ref longSize);
size = (UInt32)longSize;
return r;
}
}
#endregion
}
}
+443
View File
@@ -0,0 +1,443 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Brotli
{
public class BrotliStream : Stream
{
const int BufferSize = 64 * 1024;
protected Stream _stream = null;
protected MemoryStream _intermediateStream = new MemoryStream();
protected CompressionMode _mode = CompressionMode.Compress;
protected IntPtr _state = IntPtr.Zero;
protected IntPtr _ptrInputBuffer = IntPtr.Zero;
protected IntPtr _ptrOutputBuffer = IntPtr.Zero;
protected IntPtr _ptrNextInput = IntPtr.Zero;
protected IntPtr _ptrNextOutput = IntPtr.Zero;
protected UInt32 _availableIn = 0;
protected UInt32 _availableOut = BufferSize;
protected Byte[] _managedBuffer;
protected Boolean _endOfStream = false;
protected int _readOffset = 0;
protected BrotliDecoderResult _lastDecodeResult = BrotliDecoderResult.NeedsMoreInput;
protected Boolean _leaveOpen = false;
public BrotliStream(Stream baseStream, CompressionMode mode,bool leaveOpen)
{
if (baseStream == null) throw new ArgumentNullException("baseStream");
_mode = mode;
_stream = baseStream;
_leaveOpen = leaveOpen;
if (_mode == CompressionMode.Compress)
{
_state = Brolib.BrotliEncoderCreateInstance();
if (_state == IntPtr.Zero)
{
throw new BrotliException("Unable to create brotli encoder instance");
}
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.Quality, 5);
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.LGWin, 22);
}
else
{
_state = Brolib.BrotliDecoderCreateInstance();
if (_state == IntPtr.Zero)
{
throw new BrotliException("Unable to create brotli decoder instance");
}
//follow the brotli default standard
var succ = Brolib.BrotliDecoderSetParameter(_state, BrotliDecoderParameter.LargeWindow, 1U);
if (!succ)
{
throw new BrotliException("failed to set decoder parameter to large window");
}
}
_ptrInputBuffer = Marshal.AllocHGlobal(BufferSize);
_ptrOutputBuffer = Marshal.AllocHGlobal(BufferSize);
_ptrNextInput = _ptrInputBuffer;
_ptrNextOutput = _ptrOutputBuffer;
_managedBuffer = new Byte[BufferSize];
}
public BrotliStream(Stream baseStream, CompressionMode mode):this(baseStream,mode,false)
{
}
/// <summary>
/// Set the compress quality(0~11)
/// </summary>
/// <param name="quality">compress quality</param>
public void SetQuality(uint quality)
{
if (quality < 0 || quality > 11)
{
throw new ArgumentException("quality", "the range of quality is 0~11");
}
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.Quality, quality);
}
/// <summary>
/// Set the compress LGWin(10~24)
/// </summary>
/// <param name="window">the window size</param>
public void SetWindow(uint window)
{
if (window < 10 || window > 24)
{
throw new ArgumentException("window", "the range of window is 10~24");
}
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.LGWin, window);
}
public override bool CanRead
{
get
{
if (_stream == null)
{
return false;
}
return (_mode == System.IO.Compression.CompressionMode.Decompress && _stream.CanRead);
}
}
public override bool CanSeek
{
get
{
return false;
}
}
public override bool CanWrite
{
get
{
if (_stream == null)
{
return false;
}
return (_mode == System.IO.Compression.CompressionMode.Compress && _stream.CanWrite);
}
}
public override long Length
{
get
{
throw new NotImplementedException();
}
}
public override long Position
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override async Task FlushAsync(CancellationToken cancellationToken)
{
if (_stream == null)
{
throw new ObjectDisposedException(null, "Underlying stream is disposed");
}
if (_mode == CompressionMode.Compress)
{
await FlushBrotliStreamAsync(false).ConfigureAwait(false);
}
}
public override void Flush()
{
AsyncHelper.RunSync(() => FlushAsync());
}
protected virtual async Task FlushBrotliStreamAsync(Boolean finished)
{
//test if the resource has been freed
if (_state == IntPtr.Zero) return;
if (Brolib.BrotliEncoderIsFinished(_state)) return;
BrotliEncoderOperation op = finished ? BrotliEncoderOperation.Finish : BrotliEncoderOperation.Flush;
UInt32 totalOut = 0;
while (true)
{
var compressOK = Brolib.BrotliEncoderCompressStream(_state, op, ref _availableIn, ref _ptrNextInput, ref _availableOut, ref _ptrNextOutput, out totalOut);
if (!compressOK) throw new BrotliException("Unable to finish encode stream");
var extraData = _availableOut != BufferSize;
if (extraData)
{
var bytesWrote = (int)(BufferSize - _availableOut);
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, bytesWrote);
await _stream.WriteAsync(_managedBuffer, 0, bytesWrote).ConfigureAwait(false);
_availableOut = BufferSize;
_ptrNextOutput = _ptrOutputBuffer;
}
if (Brolib.BrotliEncoderIsFinished(_state)) break;
if (!extraData) break;
}
}
protected virtual void FlushBrotliStream(Boolean finished)
{
AsyncHelper.RunSync(() => FlushBrotliStreamAsync(finished));
}
protected override void Dispose(bool disposing)
{
if (_mode == CompressionMode.Compress)
{
FlushBrotliStream(true);
}
base.Dispose(disposing);
if (!_leaveOpen) _stream.Dispose();
_intermediateStream.Dispose();
if (_ptrInputBuffer!=IntPtr.Zero) Marshal.FreeHGlobal(_ptrInputBuffer);
if (_ptrOutputBuffer != IntPtr.Zero) Marshal.FreeHGlobal(_ptrOutputBuffer);
_managedBuffer = null;
_ptrInputBuffer = IntPtr.Zero;
_ptrOutputBuffer = IntPtr.Zero;
if (_state != IntPtr.Zero)
{
if (_mode == CompressionMode.Compress)
{
Brolib.BrotliEncoderDestroyInstance(_state);
}
else
{
Brolib.BrotliDecoderDestroyInstance(_state);
}
_state = IntPtr.Zero;
}
}
public void TruncateBeginning(MemoryStream ms, int numberOfBytesToRemove)
{
#if NETSTANDARD2_0
ArraySegment<byte> buf;
if(ms.TryGetBuffer(out buf))
{
Buffer.BlockCopy(buf.Array, numberOfBytesToRemove, buf.Array, 0, (int)ms.Length - numberOfBytesToRemove);
ms.SetLength(ms.Length - numberOfBytesToRemove);
}
else
{
throw new UnauthorizedAccessException();
}
#else
byte[] buf = ms.GetBuffer();
Buffer.BlockCopy(buf, numberOfBytesToRemove, buf, 0, (int)ms.Length - numberOfBytesToRemove);
ms.SetLength(ms.Length - numberOfBytesToRemove);
#endif
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (_mode != CompressionMode.Decompress) throw new BrotliException("Can't read on this stream");
int bytesRead = (int)(_intermediateStream.Length - _readOffset);
uint totalCount = 0;
Boolean endOfStream = false;
Boolean errorDetected = false;
while (bytesRead < count)
{
while (true)
{
if (_lastDecodeResult == BrotliDecoderResult.NeedsMoreInput)
{
_availableIn = (UInt32) await _stream.ReadAsync(_managedBuffer, 0, (int)BufferSize).ConfigureAwait(false);
_ptrNextInput = _ptrInputBuffer;
if (_availableIn <= 0)
{
endOfStream = true;
break;
}
Marshal.Copy(_managedBuffer, 0, _ptrInputBuffer, (int)_availableIn);
}
else if (_lastDecodeResult == BrotliDecoderResult.NeedsMoreOutput)
{
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, BufferSize);
await _intermediateStream.WriteAsync(_managedBuffer, 0, BufferSize).ConfigureAwait(false);
bytesRead += BufferSize;
_availableOut = BufferSize;
_ptrNextOutput = _ptrOutputBuffer;
}
else
{
//Error or OK
endOfStream = true;
break;
}
_lastDecodeResult = Brolib.BrotliDecoderDecompressStream(_state, ref _availableIn, ref _ptrNextInput,
ref _availableOut, ref _ptrNextOutput, out totalCount);
if (bytesRead >= count) break;
}
if (endOfStream && !Brolib.BrotliDecoderIsFinished(_state))
{
errorDetected = true;
}
if (_lastDecodeResult == BrotliDecoderResult.Error || errorDetected)
{
var error = Brolib.BrotliDecoderGetErrorCode(_state);
var text = Brolib.BrotliDecoderErrorString(error);
throw new BrotliDecodeException(String.Format("Unable to decode stream,possibly corrupt data.Code={0}({1})", error, text), error, text);
}
if (endOfStream && !Brolib.BrotliDecoderIsFinished(_state) && _lastDecodeResult == BrotliDecoderResult.NeedsMoreInput)
{
throw new BrotliException("Unable to decode stream,unexpected EOF");
}
if (endOfStream && _ptrNextOutput != _ptrOutputBuffer)
{
int remainBytes = (int)(_ptrNextOutput.ToInt64() - _ptrOutputBuffer.ToInt64());
bytesRead += remainBytes;
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, remainBytes);
await _intermediateStream.WriteAsync(_managedBuffer, 0, remainBytes).ConfigureAwait(false);
_ptrNextOutput = _ptrOutputBuffer;
}
if (endOfStream) break;
}
if (_intermediateStream.Length - _readOffset >= count || endOfStream)
{
_intermediateStream.Seek(_readOffset, SeekOrigin.Begin);
var bytesToRead = (int)(_intermediateStream.Length - _readOffset);
if (bytesToRead > count) bytesToRead = count;
await _intermediateStream.ReadAsync(buffer, offset, bytesToRead).ConfigureAwait(false);
TruncateBeginning(_intermediateStream, _readOffset + bytesToRead);
_readOffset = 0;
return bytesToRead;
}
return 0;
}
public override int Read(byte[] buffer, int offset, int count)
{
async Task<int> task()
{
return await ReadAsync(buffer,offset,count).ConfigureAwait(false);
}
return AsyncHelper.RunSync(task);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
static int totalWrote = 0;
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (_mode != CompressionMode.Compress) throw new BrotliException("Can't write on this stream");
totalWrote += count;
//Console.WriteLine(String.Format("Write {0} bytes,total={1} bytes.", count, totalWrote));
UInt32 totalOut = 0;
int bytesRemain = count;
int currentOffset = offset;
Boolean compressOK = true;
while (bytesRemain > 0)
{
int copyLen = bytesRemain > BufferSize ? BufferSize : bytesRemain;
Marshal.Copy(buffer, currentOffset, _ptrInputBuffer, copyLen);
bytesRemain -= copyLen;
currentOffset += copyLen;
_availableIn = (UInt32)copyLen;
_ptrNextInput = _ptrInputBuffer;
while (_availableIn > 0)
{
compressOK = Brolib.BrotliEncoderCompressStream(_state, BrotliEncoderOperation.Process, ref _availableIn, ref _ptrNextInput, ref _availableOut,
ref _ptrNextOutput, out totalOut);
if (!compressOK) throw new BrotliException("Unable to compress stream");
if (_availableOut != BufferSize)
{
var bytesWrote = (int)(BufferSize - _availableOut);
//Byte[] localBuffer = new Byte[bytesWrote];
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, bytesWrote);
await _stream.WriteAsync(_managedBuffer, 0, bytesWrote).ConfigureAwait(false);
_availableOut = BufferSize;
_ptrNextOutput = _ptrOutputBuffer;
}
}
if (Brolib.BrotliEncoderIsFinished(_state)) break;
}
}
public override void Write(byte[] buffer, int offset, int count)
{
async Task task()
{
await WriteAsync(buffer,offset,count).ConfigureAwait(false);
}
AsyncHelper.RunSync(task);
}
}
#if NET35
/// <summary>
/// Improve compability issue on FX35
/// </summary>
public static class StreamCopyExtension
{
public static void CopyTo(this Stream source,Stream destination, int bufferSize=4*1024)
{
if (source==null)
{
throw new ArgumentNullException(nameof(source));
}
if (destination==null)
{
throw new ArgumentNullException(nameof(destination));
}
if (!source.CanRead)
{
throw new InvalidOperationException("source stream is not readable");
}
if (!destination.CanWrite)
{
throw new InvalidOperationException("destination stream is not writeable");
}
if (bufferSize<=0)
{
throw new InvalidOperationException("buffer size should be greate than zero");
}
byte[] buffer = new byte[bufferSize];
int read;
while ((read = source.Read(buffer, 0, buffer.Length)) > 0)
destination.Write(buffer, 0, read);
}
}
#endif
}
+62
View File
@@ -0,0 +1,62 @@
using System;
using System.Runtime.InteropServices;
namespace Brotli
{
class Brolib32
{
static Brolib32()
{
var path = LibPathBootStrapper.LibPath;
NativeLibraryLoader nl = new NativeLibraryLoader(path);
#region set encoder
nl.FillDelegate(out BrotliEncoderCreateInstance);
nl.FillDelegate(out BrotliEncoderSetParameter);
nl.FillDelegate(out BrotliEncoderCompressStream);
nl.FillDelegate(out BrotliEncoderIsFinished);
nl.FillDelegate(out BrotliEncoderDestroyInstance);
nl.FillDelegate(out BrotliEncoderVersion);
nl.FillDelegate(out BrotliEncoderVersion);
nl.FillDelegate(out BrotliEncoderTakeOutput);
#endregion
#region set decoder
nl.FillDelegate(out BrotliDecoderCreateInstance);
nl.FillDelegate(out BrotliDecoderSetParameter);
nl.FillDelegate(out BrotliDecoderDecompressStream);
nl.FillDelegate(out BrotliDecoderDestroyInstance);
nl.FillDelegate(out BrotliDecoderVersion);
nl.FillDelegate(out BrotliDecoderIsUsed);
nl.FillDelegate(out BrotliDecoderIsFinished);
nl.FillDelegate(out BrotliDecoderGetErrorCode);
nl.FillDelegate(out BrotliDecoderErrorString);
nl.FillDelegate(out BrotliDecoderTakeOutput);
#endregion
}
#region Encoder
internal static Delegate32.BrotliEncoderCreateInstanceDelegate BrotliEncoderCreateInstance;
internal static Delegate32.BrotliEncoderSetParameterDelegate BrotliEncoderSetParameter;
//internal static Delegate32.BrotliEncoderSetCustomDictionaryDelegate BrotliEncoderSetCustomDictionary;
internal static Delegate32.BrotliEncoderCompressStreamDelegate BrotliEncoderCompressStream;
internal static Delegate32.BrotliEncoderIsFinishedDelegate BrotliEncoderIsFinished;
internal static Delegate32.BrotliEncoderDestroyInstanceDelegate BrotliEncoderDestroyInstance;
internal static Delegate32.BrotliEncoderVersionDelegate BrotliEncoderVersion;
internal static Delegate32.BrotliEncoderTakeOutputDelegate BrotliEncoderTakeOutput;
#endregion
#region Decoder
internal static Delegate32.BrotliDecoderCreateInstanceDelegate BrotliDecoderCreateInstance;
internal static Delegate32.BrotliDecoderSetParameter BrotliDecoderSetParameter;
//internal static Delegate32.BrotliDecoderSetCustomDictionary BrotliDecoderSetCustomDictionary;
internal static Delegate32.BrotliDecoderDecompressStreamDelegate BrotliDecoderDecompressStream;
internal static Delegate32.BrotliDecoderDestroyInstanceDelegate BrotliDecoderDestroyInstance;
internal static Delegate32.BrotliDecoderVersionDelegate BrotliDecoderVersion;
internal static Delegate32.BrotliDecoderIsUsedDelegate BrotliDecoderIsUsed;
internal static Delegate32.BrotliDecoderIsFinishedDelegate BrotliDecoderIsFinished;
internal static Delegate32.BrotliDecoderGetErrorCodeDelegate BrotliDecoderGetErrorCode;
internal static Delegate32.BrotliDecoderErrorStringDelegate BrotliDecoderErrorString;
internal static Delegate32.BrotliDecoderTakeOutputDelegate BrotliDecoderTakeOutput;
#endregion
}
}
+62
View File
@@ -0,0 +1,62 @@
using System;
using System.Runtime.InteropServices;
namespace Brotli
{
class Brolib64
{
static Brolib64()
{
var path = LibPathBootStrapper.LibPath;
NativeLibraryLoader nl = new NativeLibraryLoader(path);
#region set encoder
nl.FillDelegate(out BrotliEncoderCreateInstance);
nl.FillDelegate(out BrotliEncoderSetParameter);
nl.FillDelegate(out BrotliEncoderCompressStream);
nl.FillDelegate(out BrotliEncoderIsFinished);
nl.FillDelegate(out BrotliEncoderDestroyInstance);
nl.FillDelegate(out BrotliEncoderVersion);
nl.FillDelegate(out BrotliEncoderVersion);
nl.FillDelegate(out BrotliEncoderTakeOutput);
#endregion
#region set decoder
nl.FillDelegate(out BrotliDecoderCreateInstance);
nl.FillDelegate(out BrotliDecoderSetParameter);
nl.FillDelegate(out BrotliDecoderDecompressStream);
nl.FillDelegate(out BrotliDecoderDestroyInstance);
nl.FillDelegate(out BrotliDecoderVersion);
nl.FillDelegate(out BrotliDecoderIsUsed);
nl.FillDelegate(out BrotliDecoderIsFinished);
nl.FillDelegate(out BrotliDecoderGetErrorCode);
nl.FillDelegate(out BrotliDecoderErrorString);
nl.FillDelegate(out BrotliDecoderTakeOutput);
#endregion
}
#region Encoder
internal static Delegate64.BrotliEncoderCreateInstanceDelegate BrotliEncoderCreateInstance;
internal static Delegate64.BrotliEncoderSetParameterDelegate BrotliEncoderSetParameter;
//internal static Delegate64.BrotliEncoderSetCustomDictionaryDelegate BrotliEncoderSetCustomDictionary;
internal static Delegate64.BrotliEncoderCompressStreamDelegate BrotliEncoderCompressStream;
internal static Delegate64.BrotliEncoderIsFinishedDelegate BrotliEncoderIsFinished;
internal static Delegate64.BrotliEncoderDestroyInstanceDelegate BrotliEncoderDestroyInstance;
internal static Delegate64.BrotliEncoderVersionDelegate BrotliEncoderVersion;
internal static Delegate64.BrotliEncoderTakeOutputDelegate BrotliEncoderTakeOutput;
#endregion
#region Decoder
internal static Delegate64.BrotliDecoderCreateInstanceDelegate BrotliDecoderCreateInstance;
internal static Delegate64.BrotliDecoderSetParameter BrotliDecoderSetParameter;
//internal static Delegate64.BrotliDecoderSetCustomDictionary BrotliDecoderSetCustomDictionary;
internal static Delegate64.BrotliDecoderDecompressStreamDelegate BrotliDecoderDecompressStream;
internal static Delegate64.BrotliDecoderDestroyInstanceDelegate BrotliDecoderDestroyInstance;
internal static Delegate64.BrotliDecoderVersionDelegate BrotliDecoderVersion;
internal static Delegate64.BrotliDecoderIsUsedDelegate BrotliDecoderIsUsed;
internal static Delegate64.BrotliDecoderIsFinishedDelegate BrotliDecoderIsFinished;
internal static Delegate64.BrotliDecoderGetErrorCodeDelegate BrotliDecoderGetErrorCode;
internal static Delegate64.BrotliDecoderErrorStringDelegate BrotliDecoderErrorString;
internal static Delegate64.BrotliDecoderTakeOutputDelegate BrotliDecoderTakeOutput;
#endregion
}
}
+72
View File
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Brotli
{
internal class Delegate32
{
#region Encoder
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliEncoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliEncoderSetParameterDelegate(IntPtr state, BrotliEncoderParameter parameter, UInt32 value);
//delegate void BrotliEncoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliEncoderCompressStreamDelegate(
IntPtr state, BrotliEncoderOperation op, ref UInt32 availableIn,
ref IntPtr nextIn, ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliEncoderIsFinishedDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void BrotliEncoderDestroyInstanceDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate UInt32 BrotliEncoderVersionDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliEncoderTakeOutputDelegate(IntPtr state, ref UInt32 size);
#endregion
#region Decoder
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliDecoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliDecoderSetParameter(IntPtr state, BrotliDecoderParameter param, UInt32 value);
//delegate void BrotliDecoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate BrotliDecoderResult BrotliDecoderDecompressStreamDelegate(
IntPtr state, ref UInt32 availableIn, ref IntPtr nextIn,
ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void BrotliDecoderDestroyInstanceDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate UInt32 BrotliDecoderVersionDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliDecoderIsUsedDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliDecoderIsFinishedDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 BrotliDecoderGetErrorCodeDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliDecoderErrorStringDelegate(Int32 code);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliDecoderTakeOutputDelegate(IntPtr state, ref UInt32 size);
#endregion
}
}
+73
View File
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Brotli
{
internal class Delegate64
{
#region Encoder
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliEncoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliEncoderSetParameterDelegate(IntPtr state, BrotliEncoderParameter parameter, UInt32 value);
//delegate void BrotliEncoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliEncoderCompressStreamDelegate(
IntPtr state, BrotliEncoderOperation op, ref UInt64 availableIn,
ref IntPtr nextIn, ref UInt64 availableOut, ref IntPtr nextOut, out UInt64 totalOut);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliEncoderIsFinishedDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void BrotliEncoderDestroyInstanceDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate UInt32 BrotliEncoderVersionDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliEncoderTakeOutputDelegate(IntPtr state, ref UInt64 size);
#endregion
#region Decoder
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliDecoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliDecoderSetParameter(IntPtr state, BrotliDecoderParameter param, UInt32 value);
//delegate void BrotliDecoderSetCustomDictionary(IntPtr state, UInt64 size, IntPtr dict);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate BrotliDecoderResult BrotliDecoderDecompressStreamDelegate(
IntPtr state, ref UInt64 availableIn, ref IntPtr nextIn,
ref UInt64 availableOut, ref IntPtr nextOut, out UInt64 totalOut);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void BrotliDecoderDestroyInstanceDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate UInt32 BrotliDecoderVersionDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliDecoderIsUsedDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool BrotliDecoderIsFinishedDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 BrotliDecoderGetErrorCodeDelegate(IntPtr state);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliDecoderErrorStringDelegate(Int32 code);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr BrotliDecoderTakeOutputDelegate(IntPtr state, ref UInt64 size);
#endregion
}
}
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
namespace Brotli
{
internal class LibPathBootStrapper
{
internal static string LibPath { get; private set; }
static LibPathBootStrapper()
{
string fileName = null;
if (NativeLibraryLoader.IsWindows)
{
if (NativeLibraryLoader.Is64Bit)
{
fileName = "brolib_x64.dll";
}
else
{
fileName = "brolib_x86.dll";
}
} else if (NativeLibraryLoader.IsLinux)
{
if (NativeLibraryLoader.Is64Bit)
{
fileName = "brolib_x64.so";
}
else
{
fileName = "brolib_x86.so";
}
} else if (NativeLibraryLoader.IsMacOSX)
{
if (NativeLibraryLoader.Is64Bit)
{
fileName = "brolib_x64.dylib";
}
}
if (string.IsNullOrEmpty(fileName)) throw new NotSupportedException($"OS not supported:{Environment.OSVersion.ToString()}");
var paths = NativeLibraryLoader.GetPossibleRuntimeDirectories();
var libFound = false;
foreach(var path in paths)
{
var fullPath = Path.Combine(path, fileName);
if (System.IO.File.Exists(fullPath))
{
LibPath = fullPath;
libFound = true;
break;
}
}
if (!libFound) throw new NotSupportedException($"Unable to find library {fileName}");
}
}
}
+234
View File
@@ -0,0 +1,234 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace Brotli
{
internal class NativeLibraryLoader
{
internal static bool IsWindows = false;
internal static bool IsLinux = false;
internal static bool IsMacOSX = false;
internal static bool IsNetCore = false;
internal static bool Is64Bit = false;
static NativeLibraryLoader()
{
#if NET35 || NET40
IsWindows=true;
#else
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
IsMacOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
IsNetCore = RuntimeInformation.FrameworkDescription.StartsWith(".NET Core");
#endif
if (!IsWindows && !IsLinux && !IsMacOSX)
{
throw new InvalidOperationException("Unsupported platform.");
}
Is64Bit = IntPtr.Size == 8;
}
// dlopen flags
const int RtldLazy = 1;
const int RtldGlobal = 8;
readonly string _libraryPath;
internal IntPtr Handle { get; private set; }
internal NativeLibraryLoader(string libraryPath)
{
_libraryPath = libraryPath;
Handle = LoadLibrary(_libraryPath, out var errorMsg);
if (!String.IsNullOrEmpty(errorMsg))
{
throw new BrotliException($"unable to load library {libraryPath}");
}
}
public static IntPtr GetWin32ModuleHandle(String moduleName)
{
IntPtr r = IntPtr.Zero;
foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
{
if (mod.ModuleName == moduleName)
{
r = mod.BaseAddress;
break;
}
}
return r;
}
/// <summary>
/// Loads method in the library
/// </summary>
/// <param name="symbolName">The methold of the library</param>
/// <returns>method address</returns>
private IntPtr LoadSymbol(string symbolName)
{
if (IsWindows)
{
return WindowsLoader.GetProcAddress(Handle, symbolName);
}
if (IsLinux)
{
if (IsNetCore)
{
return CoreCLRLoader.dlsym(Handle, symbolName);
}
return LinuxLoader.dlsym(Handle, symbolName);
}
if (IsMacOSX)
{
return MacOSXLoader.dlsym(Handle, symbolName);
}
throw new InvalidOperationException("Unsupported platform.");
}
public void FillDelegate<T>(out T delegateType) where T : class
{
var typeName = typeof(T).Name;
var kt = "Delegate";
if (typeName.EndsWith(kt))
{
typeName = typeName.Substring(0, typeName.Length - kt.Length);
}
delegateType = GetNativeMethodDelegate<T>(typeName);
}
public T GetNativeMethodDelegate<T>(string methodName) where T : class
{
var ptr = LoadSymbol(methodName);
if (ptr == IntPtr.Zero)
{
throw new MissingMethodException(string.Format("The native method \"{0}\" does not exist", methodName));
}
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; // generic version not available in .NET45
}
internal static string[] GetPossibleRuntimeDirectories()
{
#if NET35 || NET40
var assemblyDirectory = Path.GetDirectoryName(typeof(LibPathBootStrapper).Assembly.Location);
#else
var assemblyDirectory = Path.GetDirectoryName(typeof(LibPathBootStrapper).GetTypeInfo().Assembly.Location);
#endif
//var platform = "win";
//if (IsLinux)
//{
// platform= "linux";
//}
//if (IsMacOSX)
//{
// platform= "osx";
//}
//string runtimesDirectory = string.Format("runtimes/{0}/native", platform);
string runtimesDirectory;
if (Is64Bit)
{
runtimesDirectory = "x64"; // string.Format("x64/{0}", platform);
}
else
{
runtimesDirectory = "x86"; // string.Format("x86/{0}", platform);
}
string runtimesFullDirectory = Path.Combine(assemblyDirectory,runtimesDirectory);
var iisBaseDirectory = $"{AppDomain.CurrentDomain.BaseDirectory}bin/{runtimesDirectory}";
var execAssemblyDirectory= System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\","")+"/"+ runtimesDirectory;
#if NET35
var netCoreAppStyleDirectory = Path.Combine(Path.Combine(assemblyDirectory, "../.."), runtimesDirectory);
#else
var netCoreAppStyleDirectory = Path.Combine(assemblyDirectory, "../..", runtimesDirectory);
#endif
string[] paths = new[] { assemblyDirectory, runtimesFullDirectory, runtimesDirectory, netCoreAppStyleDirectory,iisBaseDirectory,execAssemblyDirectory };
paths = paths.Select(v => v.Replace('/', Path.DirectorySeparatorChar)).ToArray();
return paths;
}
internal static bool FreeLibrary(IntPtr handle)
{
string errorMsg = null;
if (IsWindows)
{
return WindowsLoader.FreeLibrary(handle);
}
if (IsLinux)
{
if (IsNetCore)
{
return UnloadLibraryPosix(CoreCLRLoader.dlclose, CoreCLRLoader.dlerror, handle, out errorMsg);
}
return UnloadLibraryPosix(LinuxLoader.dlclose, LinuxLoader.dlerror, handle, out errorMsg);
}
if (IsMacOSX)
{
return UnloadLibraryPosix(MacOSXLoader.dlclose, MacOSXLoader.dlerror, handle, out errorMsg);
}
throw new InvalidOperationException("Unsupported platform.");
}
/// <summary>
/// Load library
/// </summary>
internal static IntPtr LoadLibrary(string libraryPath, out string errorMsg)
{
if (IsWindows)
{
errorMsg = null;
//var handle = GetWin32ModuleHandle(libraryPath);
//if (handle != IntPtr.Zero) return handle;
var handle= WindowsLoader.LoadLibrary(libraryPath);
if (handle== IntPtr.Zero)
{
throw new System.ComponentModel.Win32Exception($"failed to load library {libraryPath}");
}
return handle;
}
if (IsLinux)
{
if (IsNetCore)
{
return LoadLibraryPosix(CoreCLRLoader.dlopen, CoreCLRLoader.dlerror, libraryPath, out errorMsg);
}
return LoadLibraryPosix(LinuxLoader.dlopen, LinuxLoader.dlerror, libraryPath, out errorMsg);
}
if (IsMacOSX)
{
return LoadLibraryPosix(MacOSXLoader.dlopen, MacOSXLoader.dlerror, libraryPath, out errorMsg);
}
throw new InvalidOperationException("Unsupported platform.");
}
static IntPtr LoadLibraryPosix(Func<string, int, IntPtr> dlopenFunc, Func<IntPtr> dlerrorFunc, string libraryPath, out string errorMsg)
{
errorMsg = null;
IntPtr ret = dlopenFunc(libraryPath, RtldGlobal + RtldLazy);
if (ret == IntPtr.Zero)
{
errorMsg = Marshal.PtrToStringAnsi(dlerrorFunc());
}
return ret;
}
static bool UnloadLibraryPosix(Func<IntPtr,int> dlcloseFunc, Func<IntPtr> dlerrorFunc, IntPtr handle,out string errorMsg)
{
errorMsg = null;
var r = dlcloseFunc(handle);
if (r!=0)
{
errorMsg= Marshal.PtrToStringAnsi(dlerrorFunc());
return false;
}
return true;
}
}
}
+72
View File
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Brotli
{
static class WindowsLoader
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllFilePath);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
static class LinuxLoader
{
[DllImport("libdl.so")]
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("libdl.so")]
internal static extern IntPtr dlerror();
[DllImport("libdl.so")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so")]
internal static extern int dlclose(IntPtr handle);
}
static class MacOSXLoader
{
[DllImport("libSystem.dylib")]
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("libSystem.dylib")]
internal static extern IntPtr dlerror();
[DllImport("libSystem.dylib")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libSystem.dylib")]
internal static extern int dlclose(IntPtr handle);
}
/// <summary>
/// Similarly as for Mono on Linux, we load symbols for
/// dlopen and dlsym from the "libcoreclr.so",
/// to avoid the dependency on libc-dev Linux.
/// </summary>
static class CoreCLRLoader
{
[DllImport("libcoreclr.so")]
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("libcoreclr.so")]
internal static extern IntPtr dlerror();
[DllImport("libcoreclr.so")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libcoreclr.so")]
internal static extern int dlclose(IntPtr handle);
}
}
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeLibs Include="$(MSBuildThisFileDirectory)..\runtimes\**\*.*" />
<None Include="@(NativeLibs)">
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<!--
<NativePdbs Include="$(MSBuildThisFileDirectory)..\runtimes\**\*.pdb" />
<None Include="@(NativePdbs)" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(AllowedReferenceRelatedFileExtensions)', '\.pdb'))">
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> -->
</Project>
Binary file not shown.
Binary file not shown.
-238
View File
@@ -1,238 +0,0 @@
# 更新日志
## `2023/12/10` v1.6.1
* [优化] 如果存在下载完成列表,弹出选择框是否再次下载。
* [修复] 更新wbi签名算法,解决无法解析下载视频的问题。
## `2023/12/09` v1.6.0
* [优化] 下载列表弹出框。
* [优化] 添加任务栏图标。
* [优化] 视频流API、视频详细信息API。
* [修复] 文件名导致的闪退问题。
* [修复] 程序反复读取设置文件的问题。
* [修复] 修复扫码登录的问题。
* [修复] 在下载设置窗口界面取消或关闭窗口之后导致的DownKyi闪退问题 #907。
## `2023/05/24` v1.5.9
* [新增] 下载完成系统提示。
* [修复] UP主个人空间访问。
## `2023/04/30` v1.5.8
* [新增] 视频详情页搜索功能。
* [优化] 确认下载路径之前检查盘符是否存在。
* [优化] 弹出框的UI。
* [优化] 音质描述【普通音质有3档质量,但不是固定的320K或192K,因此仅用高中低表述,以免产生误解】。
* [修复] 下载管理在只下载音频的情况下点击打开文件夹无响应。
* [修复] 解决tabId溢出的问题。
## `2023/02/18` v1.5.7
* [新增] 自定义UserAgent。
* [新增] 程序检查更新。
* [优化] 下载前检测无效的下载目录。
* [优化] 更新依赖版本。
* [优化] 输出Aria2错误信息到UI。
* [修复] 默认编码为AVC,但画质为杜比视界时,不会自动选中HEVC编码的问题。
* [修复] 删除下载项时内建下载器崩溃的问题。
## `2023/01/06` v1.5.6
* [修复] 文件名包含非法字符。
* [修复] 多线程下载的bug。
* [修复] 弹幕无法下载的bug。
## `2022/11/06` v1.5.5
* [优化] 更新分区列表。
* [优化] 更新依赖包。
* [新增] 关注和粉丝页面。
* [修复] 命名格式无AV1编码的问题。
* [修复] 优先解析视频编码顺序为AV1、HEVC、AVC。
* [修复] 自定义aria服务器监听端口设置无效的问题。
## `2022/10/16` v1.5.4
* [新增] 支持AV1编码视频。
* [新增] 支持Hi-Res无损音频格式。
* [新增] 支持UP主用户空间的合集和列表。
* [新增] 支持自定义aria服务器。
* [新增] 音视频分离支持多选。
* [修复] 视频无杜比视界时支持杜比全景声。
## `2022/06/05` v1.5.3
* [优化] 封面命名。
* [新增] 启用https控制。
* [新增] 支持出行分区。
* [新增] 下载管理页面入口。
* [修复] 批量操作时偶尔崩溃的问题。
* [修复] 监听剪贴板失效的问题。
## `2022/05/09` v1.5.2
* [优化] 更新依赖版本。
* [新增] 内建下载器。
* [新增] 下载器切换设置。
* [修复] 问题 SSL/TLS handshake failure。
---
* `2022/05/09` v1.5.1
1. [优化] 当复制视频详情页的输入框中的字符时,不读取剪贴板内容。
2. [优化] Aria下载器添加header。
3. [新增] 向下载管理页面添加弹窗提示。
4. [新增] 文件命名模块中序号格式设置。
5. [新增] 支持WebP图像。
6. [修复] 未获取到杜比全景声却仍然显示出此选项的问题。
7. [修复] 运动分区无法显示的问题。
8. [修复] 文件名异常导致的下载失败。
9. [修复] 偶尔VideoSection重复的问题。
* `2022/04/04` v1.5.0
1. [优化] 跳过数据库中的不完整数据。
2. [优化] 文件命名格式设置支持拖拽。
3. [修复] 下载完成后的动作设置无效的问题。
4. [修复] 视频BV1rr4y1i74o无法加载的问题。
5. [修复] 下载内容设置偶尔不生效的问题。
* `2022/03/26` v1.5.0-alpha7
1. [优化] 批量下载时过滤UGC、其他季或花絮内容。
2. [优化] 保存下载视频内容到设置。
3. [优化] 更新ffmpeg为gpl版本。
4. [优化] 默认的aria的文件预分配改为NONE。
5. [新增] “解析后自动下载已解析视频”设置。
6. [修复] 只下载音频失败的问题。
7. [修复] Settings被占用无法读取的问题。
8. [修复] 因路径导致无法下载的问题。
9. [修复] 无法正确关闭数据库的问题。
* `2022/03/20` v1.5.0-alpha6
1. [修复] 一些已知问题。
* `2022/03/19` v1.5.0-alpha5
1. [优化] 文件命名格式中,时间格式可设置。
2. [修复] 数据库异常锁定的问题。
3. [修复] 视频标题和分P标题相同时找不到下载文件的问题。
4. [修复] 150%缩放下的窗口不超出屏幕。
5. [修复] 其他已知问题。
* `2022/03/13` v1.5.0-alpha4
1. [优化] 配置文件目录改为当前程序目录。
2. [修复] 部分UI显示。
3. [修复] 因数据库中的重复内容导致的闪退问题。
4. [修复] 其他已知问题。
* `2022/03/12` v1.5.0-alpha3
1. [修复] 当用户性别为保密时,程序闪退的问题。
2. [修复] 批量下载UP主视频时,程序偶尔闪退的问题。
3. [修复] 其他已知问题。
* `2022/03/07` v1.5.0-alpha2
1. [优化] 重构程序架构,解决一些已知问题。
2. [优化] 界面UI的显示与操作。
3. [新增] 文件命名格式:avid、bvid、cid、UP主信息、视频发布时间。
4. [修复] 视频音质列表导致的闪退问题。
5. [修复] 图片下载导致的闪退问题。
* `2022/03/05` v1.5.0-alpha1
1. [优化] 重构程序架构,解决一些已知问题。
2. [新增] 最高支持8K视频。
3. [新增] 支持杜比全景声和杜比视界。
4. [新增] 支持字幕下载。
5. [新增] 支持部分短链接(如 <https://b23.tv/BV17x411w7KC> )。
6. [新增] 下载内容可选,可根据需要选择下载视频、音频、弹幕、字幕、封面。
7. [新增] 下载文件命名模块,可自主设置文件名。
* `2021/06/12` v1.4.0
1. [修复] 视频无封面时崩溃的问题。
2. [优化] 视频分区代码与图标。
3. [优化] 屏蔽频道中的失效视频。
4. [优化] 二维码登录逻辑。
5. [新增] 弹幕下载(借鉴并重写于项目 [niconvert](https://github.com/muzuiget/niconvert))。
6. [新增] 弹幕样式设置。
7. [新增] 下载弹幕、下载封面的选项。
* `2021/04/27` v1.3.8
1. [修复] FLV视频只有1个分段时下载失败的问题。
2. [修复] UP主视频页面闪退的问题。
3. [修复] 电视剧图标丢失的问题。
4. [新增] UP主视频页面下载全部视频的按钮。
* `2021/03/28` v1.3.7
1. [修复] 播放数为空白的视频存在时,整页视频列表无法加载的问题。
2. [修复] 特殊字符(控制字符、末尾空格等)导致的下载失败。
3. [修复] 由于某些封面图片metadata损坏导致的程序崩溃。
4. [修复] 监听剪贴板数据异常报错的问题。
5. [优化] 部分界面显示。
6. [优化] 程序逻辑。
7. [新增] 监听剪贴板和自动解析的设置持久化。
8. [新增] 列表支持shift&ctrl多选。
9. [新增] 下载中列表重试按钮。
* `2021/03/04` v1.3.6
1. [修复] 下载FLV时失败的问题。
2. [修复] 主页的登录信息更新不及时的问题。
3. [优化] 主页下方按钮居中。
4. [优化] 首页搜索框添加搜索按钮,点击可进行搜索。
5. [新增] 监听剪贴板。
6. [新增] 已下载视频列表排序。
7. [新增] 下载管理页面增加全部暂停、全部开始、全部删除。
* `2021/02/21` v1.3.5
1. [修复] 分P标题相同时会下载失败的问题。
2. [修复] 个人空间中的头像可能显示不全的问题。
3. [优化] 订阅页面采用分页显示。
4. [优化] 增强程序健壮性。
5. [优化] 部分界面UI。
6. [优化] 视频详情页获取视频后不自动解析下载链接。
7. [新增] 视频详情页“自动解析”选项,“解析视频”按钮,列表右键菜单“解析”。
8. [新增] 视频详情页支持输入av号和BV号。
9. [新增] 视频详情页的UP主头像增加进入用户空间的入口。
10. [新增] 历史记录和稍后再看的up主头像增加进入用户空间的入口。
* `2021/02/10` v1.3.4
1. [修复] 修复在未登录时进入UP主用户空间,程序崩溃的问题。
2. [优化] 更新视频分区。
3. [优化] 视频数为0的频道不显示。
4. [优化] 部分界面UI。
* `2021/01/30` v1.3.3
1. [修复] 输入avid和bvid可能无法解析的问题。
2. [优化] 程序的一些显示。
3. [优化] 程序核心代码结构。
4. [新增] 访问用户空间。
5. [新增] UP主投稿视频列表展示。
6. [新增] UP主频道列表展示。
7. [新增] 意见反馈入口,将进入github的issue页。
* `2021/01/05` v1.3.2 beta
1. [修复] 向Aria添加下载时参数错误问题。
2. [修复] 分P标题为空时,标题为总标题+数字。
3. [优化] 更新视频分区。
4. [优化] 文件夹、订阅、稍后再看的健壮性。
* `2021/01/01` v1.3.1 beta
1. [修复] Aria2c下载时出现503错误的问题。
2. [修复] 选择文件夹时,若取消选择仍然会添加到下载的问题。
3. [修复] 标题中含有转义字符时的问题。
4. [修复] 其他已知问题。
5. [优化] 启动时先杀死以开启的Aria2c进程。
6. [优化] 关于页面添加github链接。
* `2020/12/26` v1.3.0 beta
1. [新增] 使用Aria下载器。
2. [新增] 暂停、继续、删除下载项功能。
3. [新增] 下载时自动下载视频封面。
4. [新增] B站助手工具,包括av与bv互转,弹幕发送者查询。
5. [优化] 工具箱页面的按钮的样式。
6. [优化] 更新QRCoder版本到1.4.1。
7. [新增] 在视频详情页添加解析后自动下载所有选项。
8. [新增] 支持avid和bvid输入。
9. [修复] 在没有解析完网址的时候粘贴新的网址会出现闪退的问题。
10. [优化] 下载管理上方控制面板是否显示根据已下载视频数量动态变化。
11. [新增] 下载列表的历史记录,重启程序后恢复下载。
12. [新增] 视频详情页的封面增加右键菜单:复制封面图片、复制封面url。
+9
View File
@@ -0,0 +1,9 @@
<prism:PrismApplication x:Class="DatabaseManager.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:DatabaseManager">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
+23
View File
@@ -0,0 +1,23 @@
using DatabaseManager.Views;
using Prism.Ioc;
using System.Windows;
namespace DatabaseManager
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<ViewCover>("Cover");
containerRegistry.RegisterForNavigation<ViewHeader>("Header");
}
}
}
+142
View File
@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{95F12C16-86B5-43D5-AF3E-D2489E2DB239}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DatabaseManager</RootNamespace>
<AssemblyName>DatabaseManager</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Models\CoverModel.cs" />
<Compile Include="ViewModels\ViewCoverViewModel.cs" />
<Compile Include="ViewModels\ViewHeaderViewModel.cs" />
<Compile Include="Views\ViewCover.xaml.cs">
<DependentUpon>ViewCover.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewHeader.xaml.cs">
<DependentUpon>ViewHeader.xaml</DependentUpon>
</Compile>
<Page Include="Views\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="Views\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Views\ViewCover.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewHeader.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Prism.DryIoc" Version="8.1.97" />
<PackageReference Include="System.Data.SQLite.Core">
<Version>1.0.112.2</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DownKyi.Core\DownKyi.Core.csproj">
<Project>{4fde0364-f65b-4812-bfe8-34e886624fbd}</Project>
<Name>DownKyi.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+47
View File
@@ -0,0 +1,47 @@
namespace DatabaseManager.Models
{
public class CoverModel
{
public long Avid { get; set; }
public string Bvid { get; set; }
public long Cid { get; set; }
public string Url { get; set; }
public string Md5 { get; set; }
//private long avid;
//public long Avid
//{
// get { return avid; }
// set { SetProperty(ref avid, value); }
//}
//private string bvid;
//public string Bvid
//{
// get { return bvid; }
// set { SetProperty(ref bvid, value); }
//}
//private long cid;
//public long Cid
//{
// get { return cid; }
// set { SetProperty(ref cid, value); }
//}
//private string url;
//public string Url
//{
// get { return url; }
// set { SetProperty(ref url, value); }
//}
//private string md5;
//public string Md5
//{
// get { return md5; }
// set { SetProperty(ref md5, value); }
//}
}
}
@@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DatabaseManager")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DatabaseManager")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+71
View File
@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace DatabaseManager.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DatabaseManager.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+30
View File
@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace DatabaseManager.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
@@ -0,0 +1,47 @@
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
namespace DatabaseManager.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager regionManager;
private string _title = "DatabaseManager";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainWindowViewModel(IRegionManager regionManager)
{
this.regionManager = regionManager;
}
private DelegateCommand coverCommand;
public DelegateCommand CoverCommand => coverCommand ?? (coverCommand = new DelegateCommand(ExecuteCoverCommand));
private void ExecuteCoverCommand()
{
regionManager.RequestNavigate("ContentRegion", "Cover");
}
private DelegateCommand headerCommand;
public DelegateCommand HeaderCommand => headerCommand ?? (headerCommand = new DelegateCommand(ExecuteHeaderCommand));
private void ExecuteHeaderCommand()
{
regionManager.RequestNavigate("ContentRegion", "Header");
}
}
}
@@ -0,0 +1,66 @@
using DownKyi.Core.Storage.Database;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace DatabaseManager.ViewModels
{
public class ViewCoverViewModel : BindableBase, INavigationAware
{
private ObservableCollection<Cover> coverList;
public ObservableCollection<Cover> CoverList
{
get { return coverList; }
set { SetProperty(ref coverList, value); }
}
public ViewCoverViewModel()
{
CoverList = new ObservableCollection<Cover>();
}
public async void OnNavigatedTo(NavigationContext navigationContext)
{
await Task.Run(() =>
{
CoverDb coverDb = new CoverDb();
var covers = coverDb.QueryAll();
if (covers == null)
{
return;
}
Application.Current.Dispatcher.Invoke(new Action(() =>
{
CoverList.Clear();
foreach (var cover in covers)
{
//CoverModel newCover = new CoverModel
//{
// Avid = cover.Avid,
// Bvid = cover.Bvid,
// Cid = cover.Cid,
// Url = cover.Url,
// Md5 = cover.Md5
//};
CoverList.Add(cover);
}
}));
});
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
}
}
@@ -0,0 +1,57 @@
using DownKyi.Core.Storage.Database;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace DatabaseManager.ViewModels
{
public class ViewHeaderViewModel : BindableBase, INavigationAware
{
private ObservableCollection<Header> headerList;
public ObservableCollection<Header> HeaderList
{
get { return headerList; }
set { SetProperty(ref headerList, value); }
}
public ViewHeaderViewModel()
{
HeaderList = new ObservableCollection<Header>();
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
public async void OnNavigatedTo(NavigationContext navigationContext)
{
await Task.Run(() =>
{
HeaderDb headerDb = new HeaderDb();
var headers = headerDb.QueryAll();
if (headers == null)
{
return;
}
Application.Current.Dispatcher.Invoke(new Action(() =>
{
HeaderList.Clear();
foreach (var cover in headers)
{
HeaderList.Add(cover);
}
}));
});
}
}
}
+32
View File
@@ -0,0 +1,32 @@
<Window x:Class="DatabaseManager.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/" xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="700" Width="1200">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" BorderThickness="0 0 1 0">
<ListBoxItem Content="Cover">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding CoverCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
<ListBoxItem Content="Header">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding HeaderCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
</ListBox>
<ContentControl Grid.Column="1" prism:RegionManager.RegionName="ContentRegion" />
</Grid>
</Window>
+15
View File
@@ -0,0 +1,15 @@
using System.Windows;
namespace DatabaseManager.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
+18
View File
@@ -0,0 +1,18 @@
<UserControl x:Class="DatabaseManager.Views.ViewCover"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<DataGrid ItemsSource="{Binding CoverList}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Avid" Binding="{Binding Avid}"/>
<DataGridTextColumn Header="Bvid" Binding="{Binding Bvid}"/>
<DataGridTextColumn Header="Cid" Binding="{Binding Cid}"/>
<DataGridTextColumn Header="Url" Binding="{Binding Url}"/>
<DataGridTextColumn Header="Md5" Binding="{Binding Md5}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
+15
View File
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DatabaseManager.Views
{
/// <summary>
/// Interaction logic for ViewCover
/// </summary>
public partial class ViewCover : UserControl
{
public ViewCover()
{
InitializeComponent();
}
}
}
+17
View File
@@ -0,0 +1,17 @@
<UserControl x:Class="DatabaseManager.Views.ViewHeader"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<DataGrid ItemsSource="{Binding HeaderList}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Avid" Binding="{Binding Mid}"/>
<DataGridTextColumn Header="Bvid" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Url" Binding="{Binding Url}"/>
<DataGridTextColumn Header="Md5" Binding="{Binding Md5}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
+15
View File
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DatabaseManager.Views
{
/// <summary>
/// Interaction logic for ViewHeader
/// </summary>
public partial class ViewHeader : UserControl
{
public ViewHeader()
{
InitializeComponent();
}
}
}
+175
View File
@@ -0,0 +1,175 @@
using Brotli;
using DownKyi.Core.BiliApi.Login;
using DownKyi.Core.BiliApi.Models.Json;
using DownKyi.Core.BiliApi.VideoStream;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
namespace DownKyi.Core.Test.BiliApi
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var player = VideoStream.PlayerV2(464087531, "BV1HL411u765", 439599721);
foreach (var subtitle in player.Subtitle.Subtitles)
{
string referer = "https://www.bilibili.com";
string response = RequestWeb($"https:{subtitle.SubtitleUrl}", referer);
try
{
//Console.WriteLine(subtitle.SubtitleUrl);
//string json = @"D:\test.json";
//WebClient mywebclient = new WebClient();
//mywebclient.DownloadFile($"https:{subtitle.SubtitleUrl}", json);
//StreamReader streamReader = File.OpenText(json);
//string jsonWordTemplate = streamReader.ReadToEnd();
//streamReader.Close();
var subtitleJson = JsonConvert.DeserializeObject<SubtitleJson>(response);
if (subtitleJson == null) { return; }
string srt = subtitleJson.ToSubRip();
File.WriteAllText($"D:/{subtitle.LanDoc}.srt", srt);
}
catch (Exception e)
{
Utils.Debugging.Console.PrintLine("PlayerV2()发生异常: {0}", e);
}
}
}
public string RequestWeb(string url, string referer = null, string method = "GET", Dictionary<string, string> parameters = null, int retry = 3)
{
// 重试次数
if (retry <= 0) { return ""; }
// post请求,发送参数
if (method == "POST" && parameters != null)
{
StringBuilder builder = new StringBuilder();
int i = 0;
foreach (var item in parameters)
{
if (i > 0)
{
builder.Append("&");
}
builder.AppendFormat("{0}={1}", item.Key, item.Value);
i++;
}
url += "?" + builder.ToString();
}
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method;
request.Timeout = 30 * 1000;
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36";
//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-encoding"] = "gzip, deflate, br";
// referer
if (referer != null)
{
request.Referer = referer;
}
// 构造cookie
if (!url.Contains("getLogin"))
{
request.Headers["origin"] = "https://www.bilibili.com";
CookieContainer cookies = LoginHelper.GetLoginInfoCookies();
if (cookies != null)
{
request.CookieContainer = cookies;
}
}
string html = string.Empty;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if (response.ContentEncoding.ToLower().Contains("gzip"))
{
using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
else if (response.ContentEncoding.ToLower().Contains("deflate"))
{
using (DeflateStream stream = new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
else if (response.ContentEncoding.ToLower().Contains("br"))
{
using (BrotliStream stream = new BrotliStream(response.GetResponseStream(), CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
else
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
}
return html;
}
catch (WebException e)
{
Console.WriteLine("RequestWeb()发生Web异常: {0}", e);
Logging.LogManager.Error(e);
return RequestWeb(url, referer, method, parameters, retry - 1);
}
catch (IOException e)
{
Console.WriteLine("RequestWeb()发生IO异常: {0}", e);
Logging.LogManager.Error(e);
return RequestWeb(url, referer, method, parameters, retry - 1);
}
catch (Exception e)
{
Console.WriteLine("RequestWeb()发生其他异常: {0}", e);
Logging.LogManager.Error(e);
return RequestWeb(url, referer, method, parameters, retry - 1);
}
}
}
}
@@ -0,0 +1,35 @@
using DownKyi.Core.BiliApi.Video;
using DownKyi.Core.BiliApi.Video.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace DownKyi.Core.Test.BiliApi.Video
{
[TestClass]
public class DynamicTest
{
// 主分区tid
private readonly int[] typeIdList = { 1, 13, 167, 3, 129, 4, 36, 234, 223, 160, 211, 217, 119, 155, 5, 181, 177, 23, 11 };
[TestMethod]
public void TestRegionDynamicList()
{
foreach (var tid in typeIdList)
{
var time = DateTime.Now;
Random random = new Random(time.GetHashCode());
int ps = random.Next(1, 51);
var regionDynamicList = Dynamic.RegionDynamicList(tid, 1, ps);
Assert.IsInstanceOfType(regionDynamicList, typeof(List<DynamicVideoView>));
Assert.IsInstanceOfType(regionDynamicList[0], typeof(DynamicVideoView));
Assert.IsNotNull(regionDynamicList[0]);
Assert.AreEqual(regionDynamicList.Count, ps);
}
}
}
}
@@ -0,0 +1,34 @@
using DownKyi.Core.BiliApi.Video;
using DownKyi.Core.BiliApi.Video.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace DownKyi.Core.Test.BiliApi.Video
{
[TestClass]
public class RankingTest
{
// 主分区tid
private readonly int[] typeIdList = { 1, 13, 167, 3, 129, 4, 36, 234, 223, 160, 211, 217, 119, 155, 5, 181, 177, 23, 11 };
[TestMethod]
public void TestRegionRankingList()
{
foreach (var tid in typeIdList)
{
var regionRankingList = Ranking.RegionRankingList(tid, 3);
Assert.IsInstanceOfType(regionRankingList, typeof(List<RankingVideoView>));
Assert.IsInstanceOfType(regionRankingList[0], typeof(RankingVideoView));
Assert.IsNotNull(regionRankingList[0]);
regionRankingList = Ranking.RegionRankingList(tid, 7);
Assert.IsInstanceOfType(regionRankingList, typeof(List<RankingVideoView>));
Assert.IsInstanceOfType(regionRankingList[0], typeof(RankingVideoView));
Assert.IsNotNull(regionRankingList[0]);
}
}
}
}
@@ -0,0 +1,42 @@
using DownKyi.Core.BiliApi.Video;
using DownKyi.Core.BiliApi.Video.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DownKyi.Core.Test.BiliApi.Video
{
[TestClass]
public class VideoInfoTest
{
// 主分区tid
private readonly int[] typeIdList = { 1, 13, 167, 3, 129, 4, 36, 234, 223, 160, 211, 217, 119, 155, 5, 181, 177, 23, 11 };
[TestMethod]
public void TestVideoViewInfo()
{
foreach (var tid in typeIdList)
{
var regionDynamicList = Dynamic.RegionDynamicList(tid, 1, 12);
Assert.IsNotNull(regionDynamicList);
foreach (var videoView in regionDynamicList)
{
long aid = videoView.Aid;
string bvid = videoView.Bvid;
var bv = VideoInfo.VideoViewInfo(bvid, -1);
Assert.IsNotNull(bv);
Assert.IsInstanceOfType(bv, typeof(VideoView));
Assert.IsNotNull(bv.Pages);
var av = VideoInfo.VideoViewInfo(null, aid);
Assert.IsNotNull(av);
Assert.IsInstanceOfType(av, typeof(VideoView));
Assert.IsNotNull(av.Pages);
}
}
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.Storage.Database.Download;
using DownKyi.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace DownKyi.Core.Test.Database
{
[TestClass]
public class BinaryTest
{
[TestMethod]
public void TestMethod1()
{
Downloading downloading = new Downloading
{
Gid = "gid",
PlayStreamType = PlayStreamType.VIDEO,
DownloadContent = "视频",
DownloadStatusTitle = "下载中",
Progress = 50,
DownloadingFileSize = "60MB/120MB",
MaxSpeed = 123456,
SpeedDisplay = "5MB/s",
};
DownloadingDb db = new DownloadingDb();
db.Insert("testId", downloading);
}
[TestMethod]
public void TestMethod2()
{
DownloadingDb db = new DownloadingDb();
Dictionary<string, object> query = db.QueryAll();
Downloading downloading = (Downloading)query["testId"];
Console.WriteLine(downloading.Gid);
Console.WriteLine(downloading.PlayStreamType);
Console.WriteLine(downloading.DownloadContent);
Console.WriteLine(downloading.DownloadStatusTitle);
Console.WriteLine(downloading.Progress);
Console.WriteLine(downloading.DownloadingFileSize);
Console.WriteLine(downloading.MaxSpeed);
Console.WriteLine(downloading.SpeedDisplay);
}
}
}
+113
View File
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{81B9719E-DA29-444F-BB72-CBD5819A654D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DownKyi.Core.Test</RootNamespace>
<AssemblyName>DownKyi.Core.Test</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SQLite, Version=1.0.112.1, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>..\packages\System.Data.SQLite.Core.1.0.112.2\lib\net40\System.Data.SQLite.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BiliApi\UnitTest1.cs" />
<Compile Include="BiliApi\Video\DynamicTest.cs" />
<Compile Include="BiliApi\Video\RankingTest.cs" />
<Compile Include="BiliApi\Video\VideoInfoTest.cs" />
<Compile Include="Database\BinaryTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Test\UnitTest1.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Brotli.Core\Brotli.Core.csproj">
<Project>{3107CD63-E257-455E-AE81-1FD3582B067A}</Project>
<Name>Brotli.Core</Name>
</ProjectReference>
<ProjectReference Include="..\DownKyi.Core\DownKyi.Core.csproj">
<Project>{4fde0364-f65b-4812-bfe8-34e886624fbd}</Project>
<Name>DownKyi.Core</Name>
</ProjectReference>
<ProjectReference Include="..\DownKyi\DownKyi.csproj">
<Project>{97075FCD-6E8F-4FF9-B73A-994197F3765A}</Project>
<Name>DownKyi</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets'))" />
</Target>
<Import Project="..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets')" />
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" />
</Project>
@@ -0,0 +1,20 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("DownKyi.Core.Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DownKyi.Core.Test")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("81b9719e-da29-444f-bb72-cbd5819a654d")]
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+35
View File
@@ -0,0 +1,35 @@
using DownKyi.Core.BiliApi.Danmaku;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Net;
namespace DownKyi.Core.Test.Test
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
string url = "https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid=421769791&pid=420986799&segment_index=1";
string localFile = @"C:\Users\FlySelf\Desktop\test.proto";
WebClient mywebclient = new WebClient();
mywebclient.DownloadFile(url, localFile);
}
[TestMethod]
public void TestMethod2()
{
var danmakus = DanmakuProtobuf.GetAllDanmakuProto(420986799, 421769791);
Console.WriteLine(danmakus.Count);
foreach (var dan in danmakus)
{
Console.WriteLine(dan.ToString());
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<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>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MSTest.TestAdapter" version="2.2.10" targetFramework="net472" />
<package id="MSTest.TestFramework" version="2.2.10" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net472" />
<package id="System.Data.SQLite.Core" version="1.0.112.2" targetFramework="net472" />
</packages>
@@ -5,6 +5,8 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace DownKyi.Core.Aria2cNet.Server
{
@@ -20,7 +22,7 @@ namespace DownKyi.Core.Aria2cNet.Server
/// <param name="output"></param>
/// <param name="window"></param>
/// <returns></returns>
public static async Task<bool> StartServerAsync(AriaConfig config, Action<string> action)
public static async Task<bool> StartServerAsync(AriaConfig config, TextBox output = null, Window window = null)
{
// aria端口
ListenPort = config.ListenPort;
@@ -112,11 +114,17 @@ namespace DownKyi.Core.Aria2cNet.Server
null, (s, e) =>
{
if (e.Data == null || e.Data == "" || e.Data.Replace(" ", "") == "") { return; }
Utils.Debugging.Console.PrintLine(e.Data);
LogManager.Debug("AriaServer", e.Data);
action.Invoke(e.Data);
if (output != null && window != null)
{
window.Dispatcher.Invoke(new Action(() =>
{
output.Text += e.Data + "\n";
output.ScrollToEnd();
}));
}
});
});

Some files were not shown because too many files have changed in this diff Show More