Compare commits

...

458 Commits

Author SHA1 Message Date
曹儒士子 de86c861d8 Merge pull request #401 from caorushizi/v3.0.1
feat:   v3.0.1
2025-01-14 16:22:28 +08:00
caorushizi af3b8a2a6b feat: v3.0.1 2025-01-14 15:34:57 +08:00
曹儒士子 47d3d786ca Merge pull request #396 from caorushizi/dev/perfermance
Dev/perfermance
2025-01-03 04:25:10 +08:00
caorushizi 1c755b4bd5 feat: video sniffing page added one-click cleanup and one-click download 2025-01-03 04:19:31 +08:00
caorushizi 0cece2b194 perf: 🚀 use memoized function 2025-01-03 03:37:35 +08:00
caorushizi 840fc610f0 style: 💄 optimized the file reference path problem 2025-01-03 03:06:33 +08:00
caorushizi 6e55fe9f34 feat: some performance issues were optimized 2025-01-03 03:01:53 +08:00
曹儒士子 1620b8e4c4 Merge pull request #395 from caorushizi/docs/packages
docs: 📝  simplify download buttons and supplement documentation
2025-01-02 07:03:12 +08:00
caorushizi f798bd3d8b feat: remove redux/toolkit 2025-01-02 06:54:49 +08:00
caorushizi 65850f158c docs: 📝 simplify download buttons and supplement documentation 2025-01-02 05:05:51 +08:00
曹儒士子 8f5991e65f Merge pull request #394 from caorushizi/feat/package-version
fix: 🐛  modify home page copy
2025-01-02 04:10:47 +08:00
caorushizi 5492e1df35 fix: 🐛 modify home page copy 2025-01-02 04:08:46 +08:00
曹儒士子 93fbd8768b Merge pull request #393 from caorushizi/feat/package-version
fix: 🐛  urlschema add headers params
2025-01-02 02:48:39 +08:00
caorushizi 246f079905 fix: 🐛 urlschema add headers params 2025-01-02 02:47:20 +08:00
曹儒士子 b25285fcc2 Merge pull request #392 from caorushizi/feat/package-version
feat:   use the silent parameter for immediate download
2025-01-02 02:33:36 +08:00
caorushizi 7a2b31d328 feat: use the silent parameter for immediate download 2025-01-02 02:32:47 +08:00
曹儒士子 a4ac847f0d Merge pull request #391 from caorushizi/feat/package-version
fix: 🐛  pass the request header when downloading
2025-01-02 01:19:50 +08:00
caorushizi 6b632b5502 fix: 🐛 pass the request header when downloading 2025-01-02 01:18:06 +08:00
曹儒士子 86e1345684 Merge pull request #389 from caorushizi/feat/package-version
feat:   update adblocker
2025-01-02 00:38:02 +08:00
caorushizi b91de0e442 feat: update adblocker
feat #388
2025-01-02 00:29:35 +08:00
曹儒士子 62e47aac4c Merge pull request #387 from caorushizi/fix/bug
Fix some bug
2025-01-01 18:27:28 +08:00
caorushizi 43fb92ac82 fix: 🐛 fixed issues with YouTube login and cloudflare verification 2025-01-01 13:38:56 +08:00
caorushizi de5ecb570f fix: 🐛 fixed the createDate type error 2025-01-01 13:34:51 +08:00
caorushizi 014c851a03 fix: 🐛 fixed last character counld not be deleted 2025-01-01 13:32:37 +08:00
caorushizi eae07b1d3b fix: 🐛 fix Bilibili video file name 2025-01-01 13:30:06 +08:00
caorushizi df06736722 fix: 🐛 windows script 2024-12-19 20:39:31 +08:00
曹儒士子 25b90a0993 Merge pull request #378 from caorushizi/dev/docs
feat:   update readme
2024-12-19 20:11:45 +08:00
caorushizi ad1b58bf53 feat: update readme 2024-12-19 20:10:49 +08:00
曹儒士子 259118e48b Merge pull request #377 from caorushizi/dev/docs
feat:   update readme
2024-12-19 20:08:46 +08:00
caorushizi 145ac6bb12 feat: update readme 2024-12-19 20:08:01 +08:00
曹儒士子 7b581ff917 Merge pull request #376 from caorushizi/dev/docs
Dev/docs
2024-12-19 17:16:27 +08:00
caorushizi 62423f8156 feat: update README.md 2024-12-19 17:15:10 +08:00
caorushizi 5fd539445e docs: 📝 use English annotations 2024-12-19 16:54:28 +08:00
曹儒士子 7c756cccef feat: docker platform (#371)
* feat:   docker platform

* feat:   docker arch
2024-12-15 10:56:35 +08:00
曹儒士子 786826b434 Merge pull request #370 from woniuxingdong/master
feat: display created date for items in download list
2024-12-14 11:56:52 +08:00
spencer 56f41999b5 feat: display created date for items in download list 2024-12-13 17:42:58 +08:00
曹儒士子 7423cf89ab Merge pull request #369 from caorushizi/dev-bt
docs: update README.md
2024-12-13 16:03:32 +08:00
caorushizi 8c6ee20b30 docs: update README.md 2024-12-13 16:02:03 +08:00
曹儒士子 17ffa1acc0 Merge pull request #368 from woniuxingdong/master 2024-12-12 20:43:13 +08:00
spencer cec95c9f0a fix: add one setting item to control if the browser need to play audio 2024-12-12 17:33:49 +08:00
spencer eaf3d46e24 fix: defaultly to play audio 2024-12-10 16:48:47 +08:00
曹儒士子 c30badabbf Merge pull request #365 from caorushizi/feat/remove-docs
docs: 📝  remove docs
2024-12-09 12:56:18 +08:00
caorushizi 40cdecc820 docs: 📝 remove docs 2024-12-09 12:55:18 +08:00
caorushizi 3c1088b6d6 feat: website SEO 2024-11-28 17:18:20 +08:00
士子☀️ ac9a4c8f48 Update README.md 2024-10-17 11:03:32 +08:00
caorushizi b79ab2ee3f feat: release v3.0 2024-10-08 00:32:48 +08:00
caorushizi ceef11bca6 feat: v3.0.0 2024-10-08 00:23:01 +08:00
士子☀️ 5ce80eddb6 Merge pull request #323 from caorushizi/v3.0.0
v3.0.0
2024-10-07 22:37:04 +08:00
caorushizi 8bc3e229d7 v3.0.0 2024-10-07 22:34:46 +08:00
士子☀️ f939ce138c Merge pull request #322 from caorushizi/dev-docker-1
feat:   release scripts
2024-10-07 17:34:35 +08:00
caorushizi ad89281927 feat: release scripts 2024-10-07 17:33:53 +08:00
士子☀️ c9ae9e6b32 Fix mac build (#319)
* fix: 🐛  Mac build
#230 修复 intel 无法打开的问题
2024-10-07 14:53:08 +08:00
士子☀️ ce7dd57d36 Merge pull request #314 from caorushizi/fix-mac-build
Fix mac build
2024-10-07 00:59:36 +08:00
caorushizi 43ed1f8e3f fix: 🐛 mac build 2024-10-07 00:52:52 +08:00
caorushizi 9d1e796a20 fix: 🐛 mac build 2024-10-07 00:48:06 +08:00
士子☀️ 80bfe5f979 Merge pull request #313 from caorushizi/v3.0.0-beta.5
feat:   v3.0.0-beta.5
2024-10-06 17:12:57 +08:00
caorushizi 13ee214026 feat: v3.0.0-beta.5 2024-10-06 17:09:59 +08:00
士子☀️ 08e38d752a Merge pull request #312 from caorushizi/v3.0.0-beta.3
feat:   v3.0.0-beta.3
2024-10-06 16:38:44 +08:00
caorushizi aef4d4ffee feat: v3.0.0-beta.3 2024-10-06 16:37:28 +08:00
士子☀️ a1b2c70fdd Merge pull request #311 from caorushizi/v3.0.0-beta.3
feat:   v3.0.0-beta.3
2024-10-06 16:32:47 +08:00
caorushizi c9b4525baf feat: v3.0.0-beta.3 2024-10-06 16:30:59 +08:00
caorushizi 0b0666912e feat: supports urlscheme
#203
2024-10-04 23:47:29 +08:00
士子☀️ 9dbb5681f7 Merge pull request #310 from caorushizi/fix-merge-video
fix: 🐛  merge video
2024-10-04 16:11:34 +08:00
caorushizi eaa7bdd736 fix: 🐛 merge video 2024-10-04 16:10:28 +08:00
士子☀️ 0a65bbae5d Merge pull request #307 from caorushizi/dev-gulp
Dev gulp
2024-10-04 14:43:28 +08:00
caorushizi 82cfc1cabb feat: live streams are automatically merged 2024-10-04 14:42:11 +08:00
caorushizi f4402ac57b feat: add download folder 2024-10-04 14:26:26 +08:00
士子☀️ f6514f85dc Merge pull request #306 from caorushizi/dev-gulp
feat:   optimize web Some interaction & optimize engineering logic
2024-10-04 00:01:57 +08:00
caorushizi 1cf4c0ce39 feat: optimize web Some interaction & optimize engineering logic 2024-10-03 23:59:26 +08:00
士子☀️ 3ffe7a63e9 Merge pull request #305 from david88558855/master
Update README.md
2024-10-03 22:24:13 +08:00
david88558855 a532d9d209 Update README.md 2024-10-03 22:21:02 +08:00
士子☀️ 9c1f2f6662 Merge pull request #304 from caorushizi/dev-docker
fix: 🐛  compressed image volume
2024-10-03 14:45:20 +08:00
caorushizi 0b9ef9ff4c fix: 🐛 compressed image volume 2024-10-03 11:29:28 +08:00
caorushizi 35f25abd8a fix: 🐛 fragments are not deleted after downloading 2024-10-02 23:22:40 +08:00
士子☀️ 70bed8c006 Merge pull request #303 from caorushizi/package-version
fix: 🐛  lock version
2024-10-02 17:12:21 +08:00
caorushizi dcfad6a3c0 fix: 🐛 lock version 2024-10-02 17:01:24 +08:00
士子☀️ e7d1540b72 Merge pull request #302 from caorushizi/docker
feat:   support docker
2024-10-02 16:27:14 +08:00
caorushizi 4bc09d74ff feat: support docker 2024-10-02 16:23:47 +08:00
士子☀️ 7ab45498e6 Merge pull request #301 from caorushizi/fix-charset
Fix charset
2024-10-01 22:17:22 +08:00
caorushizi da7ffd9c12 feat: docker file 2024-10-01 22:15:51 +08:00
caorushizi b5d7ec111d feat: remote docker image 2024-10-01 21:52:07 +08:00
caorushizi 9077eb836c fix: 🐛 database charset 2024-10-01 20:32:08 +08:00
士子☀️ 6f3c2666ca Merge pull request #300 from caorushizi/dev-web
feat:   dev web
2024-10-01 01:28:10 +08:00
caorushizi eaa3170f01 feat: support web 2024-10-01 01:26:55 +08:00
caorushizi 7e1c425676 feat: dev web 2024-09-30 23:02:25 +08:00
caorushizi 7df980f881 feat: dev web 2024-09-30 18:28:34 +08:00
士子☀️ 7f0259e9cc Merge pull request #294 from caorushizi/dev-web
feat:   web
2024-09-30 13:14:24 +08:00
caorushizi c7b2f99c43 feat: backend log 2024-09-30 13:12:57 +08:00
caorushizi 4534238216 feat: nodejs 2024-09-30 03:04:57 +08:00
caorushizi 2085ef3063 feat: web 2024-09-29 02:39:49 +08:00
士子☀️ 7d3d69eae5 Merge pull request #293 from caorushizi/fix-list-style
fix: 🐛  fix list style
2024-09-28 15:06:49 +08:00
caorushizi 5c129e050b feat: nodejs version 2024-09-28 15:01:59 +08:00
caorushizi 73163de408 fix: 🐛 fix list style 2024-09-27 02:46:36 +08:00
士子☀️ f18bdc4375 Merge pull request #292 from caorushizi/fix-error
fix: 🐛  error message style in dark mode
2024-09-26 23:24:55 +08:00
caorushizi 2d9a226378 fix: 🐛 error message style in dark mode 2024-09-26 23:23:42 +08:00
士子☀️ 6cd4094159 Merge pull request #291 from caorushizi/dev-icon
fix: 🐛  optimize some styles
2024-09-26 23:06:30 +08:00
caorushizi d4c43ece23 fix: 🐛 optimize some styles 2024-09-26 22:58:35 +08:00
士子☀️ 9ac8d5d2bf Merge pull request #290 from caorushizi/dev-icon
feat:   optimized app ICONS
2024-09-26 21:52:22 +08:00
caorushizi 049ef746f4 feat: optimized app ICONS 2024-09-26 21:51:09 +08:00
士子☀️ 83d26211a0 Merge pull request #289 from caorushizi/v3.0.0-beta.2
feat:   v3.0.0-beta.2
2024-09-26 19:42:49 +08:00
caorushizi 680641707e feat: v3.0.0-beta.2 2024-09-26 19:40:58 +08:00
士子☀️ 27d4e092cf Merge pull request #288 from caorushizi/feature-export
feat:   added video link export & new download style optimization
2024-09-26 19:38:29 +08:00
caorushizi 5b477b9e9e feat: added video link export & new download style optimization 2024-09-26 19:36:59 +08:00
士子☀️ eb332b70e0 Merge pull request #287 from caorushizi/feature
feat:   video sniffing logic optimization
2024-09-26 17:59:52 +08:00
caorushizi 824df9cae2 feat: video sniffing logic optimization 2024-09-26 17:54:37 +08:00
士子☀️ 1fc73f324c Merge pull request #286 from caorushizi/feature
Feature
2024-09-26 16:47:15 +08:00
caorushizi 8dcdb1f8a3 fix: 🐛 automatically fill the video name
#127
2024-09-26 16:46:04 +08:00
caorushizi 4fe1d1ea66 feat: upgrade download program 2024-09-26 16:24:27 +08:00
士子☀️ 93b6f8c7b6 Merge pull request #285 from caorushizi/feature
Feature
2024-09-26 15:37:10 +08:00
caorushizi a33e7c3903 fix: 🐛 fixed an issue with ICONS adding favorites 2024-09-26 15:34:32 +08:00
caorushizi 4ea0180781 feat: display error message when download fails 2024-09-26 12:37:28 +08:00
caorushizi 1d4850d7fb feat: tdapp 2024-09-26 11:58:59 +08:00
士子☀️ cf77e6633e Merge pull request #284 from caorushizi/feature
feat:   new icon
2024-09-26 03:43:43 +08:00
caorushizi c692fdf6c3 feat: new icon 2024-09-26 03:41:24 +08:00
士子☀️ 1901b177cc Merge pull request #283 from caorushizi/feature
feat:   添加关闭窗口选项
2024-09-26 02:49:49 +08:00
caorushizi ce60d77c8d feat: 添加关闭窗口选项 2024-09-26 02:47:46 +08:00
士子☀️ fbe1d43488 Merge pull request #282 from caorushizi/feature
Feature
2024-09-26 02:21:42 +08:00
caorushizi ee8e75513d feat: 版本更新检查 2024-09-26 02:19:12 +08:00
caorushizi f094fd1e7f feat: main process adds multiple languages 2024-09-25 21:34:59 +08:00
士子☀️ 14c30e0e58 Merge pull request #281 from caorushizi/feature-batch
fix: 🐛  批量下载功能优化
2024-09-25 14:01:05 +08:00
caorushizi 872f1b9284 fix: 🐛 批量下载功能优化
#244, #198
2024-09-25 13:59:22 +08:00
士子☀️ 5680512573 Merge pull request #279 from caorushizi/v3.0.0-beta.1
feat:   v3.0.0-beta.1
2024-09-25 03:33:48 +08:00
caorushizi 2f6a43d98a feat: v3.0.0-beta.1 2024-09-25 03:32:14 +08:00
士子☀️ 1142c2c501 Merge pull request #278 from caorushizi/fix-issues
fix: 🐛  便携版上传
2024-09-25 03:20:01 +08:00
caorushizi c1502c0230 fix: 🐛 便携版上传 2024-09-25 03:04:59 +08:00
士子☀️ 55cf680b0c Merge pull request #276 from caorushizi/fix-issues
feat(download):   新建下载时默认带入上次表单信息
2024-09-25 02:54:25 +08:00
caorushizi 6c0d0cdf74 feat: 新增便携版 2024-09-25 02:52:40 +08:00
caorushizi 32ad030838 fix: 🐛 阻止 deeplink 打开 2024-09-25 01:55:21 +08:00
caorushizi 9811c18407 fix: 🐛 优化视频识别逻辑 & 添加完成列表的右键菜单 2024-09-25 01:44:30 +08:00
caorushizi a9c6e01294 fix: 🐛 修复批量下载 & icon 样式 2024-09-25 00:48:37 +08:00
caorushizi b904d6aaec fix: 🐛 pC 端的视频无法播放 2024-09-24 22:36:03 +08:00
caorushizi 78958d925a fix: 🐛 解决列表页面在操作时跳动的问题 2024-09-24 21:55:11 +08:00
caorushizi afba340028 fix: 🐛 新建收藏之后没有关闭弹窗 2024-09-24 21:03:07 +08:00
caorushizi ec4b24149f fix: 🐛 修复收藏页面中无法通过右键删除的问题 2024-09-24 20:52:02 +08:00
caorushizi 8e1bd8596f feat: 增加导入导出网址
#205
2024-09-24 20:33:03 +08:00
caorushizi f8785f8db8 fix: 🐛 收藏列表样式优化 2024-09-24 14:49:10 +08:00
caorushizi c508c1dd1a fix: 🐛 构建产物添加平台的名称 2024-09-24 13:28:11 +08:00
caorushizi c78b593afa feat: 将首页的【打开浏览器】按钮换成【素材提取】
#238
2024-09-24 13:20:10 +08:00
caorushizi 1b906804de feat(download): 新建下载时默认带入上次表单信息
#273 #273
2024-09-24 13:02:27 +08:00
士子☀️ 62561e9826 Merge pull request #265 from caorushizi/release-v3.0.0-beta.0
feat:   release 3.0.0-beta.0
2024-09-01 16:32:13 +08:00
caorushizi cbb9798174 feat: release 3.0.0-beta.0 2024-09-01 16:30:44 +08:00
caorushizi 2de6b6a1cc fix: 🐛 修复一些 bug 2024-09-01 16:28:00 +08:00
士子☀️ 5893d1492e Merge pull request #264 from caorushizi/fix/download-list-ui
fix: 🐛  fix: tag ui scaling bug
2024-09-01 01:52:19 +08:00
Charlie 5906f29180 fix: 🐛 fix: tag ui scaling bug 2024-09-01 01:32:00 +08:00
caorushizi 9b838e496e feat: fix macos 2024-08-27 02:12:24 +08:00
士子☀️ 106a1fa9eb Merge pull request #261 from caorushizi/dev-backend
Dev backend
2024-08-27 01:14:29 +08:00
caorushizi ecfb2371f4 feat: macos 2024-08-27 01:11:00 +08:00
caorushizi fe3ae95a22 feat: web 初步 2024-08-25 17:35:13 +08:00
士子☀️ 4ae352d5d2 Merge pull request #255 from caorushizi/dev-backend
feat:   add backend
2024-08-22 02:52:55 +08:00
caorushizi 67d56fc5ab feat: 完成 backend 基础工程 & 新增 docker 配置 2024-08-22 02:50:58 +08:00
士子☀️ 039f9eb092 Merge pull request #254 from caorushizi/dev-ui
feat:   local ip
2024-08-14 13:40:48 +08:00
caorushizi df67e52e47 feat: add backend 2024-08-14 13:38:31 +08:00
caorushizi e3f7c48f80 feat: local ip 2024-08-11 21:21:06 +08:00
士子☀️ 57b67ea55c Merge pull request #253 from caorushizi/dev-ui
feat:   add mobile player
2024-08-11 20:47:27 +08:00
caorushizi 21c3eb475f feat: add mobile player 2024-08-11 20:45:59 +08:00
士子☀️ 805f9435f3 Merge pull request #252 from caorushizi/dev-ui
feat:   new ui
2024-08-11 18:16:15 +08:00
士子☀️ 213261fbbb Merge pull request #250 from caorushizi/dev-ui
Dev UI
2024-08-11 18:10:25 +08:00
caorushizi ceda93a8cf feat: new ui 2024-08-11 18:06:24 +08:00
caorushizi 39ec4f863d feat: new ui 2024-08-11 18:02:33 +08:00
caorushizi 4d9188221f feat: new ui 2024-08-11 01:23:16 +08:00
caorushizi 30c8085964 feat: new ui 2024-08-11 01:14:24 +08:00
士子☀️ 97206279d8 Merge pull request #249 from ruixingshi/srx/add-version-info 2024-08-10 20:18:46 +08:00
shiruixing 8d3c8f4ad1 docs: change text 2024-08-10 20:15:27 +08:00
士子☀️ bf4075ba1c Merge pull request #248 from ruixingshi/srx/add-version-info 2024-08-10 18:23:43 +08:00
shiruixing 5f5892242b docs: add update info 2024-08-10 18:17:58 +08:00
fenglei 29602d9fa2 docs: update icon button (#243) 2024-08-07 18:37:23 +08:00
Hanzc f2f1f963d4 docs: 创建 axios 实例 (#242) 2024-08-07 18:29:00 +08:00
士子☀️ 56219c8fe4 V3.0.0 (#235)
* feat:   v3.0.0

* feat:   v3.0.0
2024-07-28 23:18:22 +08:00
士子☀️ ba211c1360 feat: v3.0.0 (#234)
* feat:   v3.0.0

* feat:   v3.0.0
2024-07-25 00:00:33 +08:00
caorushizi 2870a42cd4 feat: new ui 2024-07-23 22:09:30 +08:00
caorushizi f8a2188760 feat(ui): new ui 2024-07-23 22:09:30 +08:00
caorushizi 5c4020a52f fix: 🐛 remove @tailwindcss/line-clamp 2024-07-23 22:09:30 +08:00
caorushizi 4c060366b8 fix: 🐛 修复 @cliqz/adblocker 版本问题 2024-07-23 22:09:30 +08:00
caorushizi af219bde11 feat(ui): new ui 2024-07-23 22:09:30 +08:00
caorushizi caa279ce36 feat(ui): new ui 2024-07-23 22:09:30 +08:00
caorushizi 4651229a0d feat: update dependencies 2024-07-23 22:09:30 +08:00
caorushizi 6c8916a9e6 feat: new ui 2024-07-23 22:09:30 +08:00
caorushizi 8d831e2c9d feat(ui): new ui 2024-07-23 22:09:30 +08:00
caorushizi 1f3b4f5624 feat: new ui 2024-07-23 22:09:30 +08:00
caorushizi 04c8afe616 feat: ui 2024-07-23 22:09:30 +08:00
caorushizi e53aed0910 feat(ui): style revisions 2024-07-23 22:09:30 +08:00
caorushizi 520b63a8de feat: add mobile project 2024-07-23 22:09:30 +08:00
caorushizi 0e4aa730eb feat: add video server 2024-07-23 22:09:30 +08:00
caorushizi 07c7ddccad feat: 新 UI 重构 2024-07-23 22:09:30 +08:00
caorushizi 5ff7252ee9 feat: add tailwindcss 2024-07-23 22:09:30 +08:00
士子☀️ 5461e74539 Merge pull request #216 from caorushizi/release-v2.2.3
feat:   v2.2.3
2024-07-06 17:42:02 +08:00
caorushizi 417484cb6d feat: v2.2.3 2024-07-06 17:38:30 +08:00
士子☀️ 9aaffd3550 Merge pull request #214 from caorushizi/dev-docs
docs: 📝  更新文档
2024-07-03 15:40:36 +08:00
caorushizi 94759d48c7 docs: 📝 更新文档 2024-07-03 15:37:16 +08:00
士子☀️ c0e343b696 Merge pull request #204 from caorushizi/fix-search
fix: 🐛  修复新版本在更换安装目录后下载失败的问题
2024-06-30 19:01:26 +08:00
caorushizi f18ac7c444 fix: 🐛 修复新版本在更换安装目录后下载失败的问题
下载中的视频无法停止 #202
2024-06-30 18:58:58 +08:00
士子☀️ f637610734 Merge pull request #196 from caorushizi/fix-search
fix: 🐛  修复搜索时跳转的链接
2024-06-24 23:43:47 +08:00
caorushizi 5e1046dd5b fix: 🐛 修复搜索时跳转的链接 2024-06-23 11:41:33 +08:00
士子☀️ f25584cb2f Merge pull request #195 from caorushizi/fix-videoname
fix: 🐛  修复获取视频名称的问题
2024-06-23 00:13:13 +08:00
caorushizi 03999585d0 fix: 🐛 修复获取视频名称的问题 2024-06-23 00:12:06 +08:00
士子☀️ 772c2b0300 Merge pull request #194 from caorushizi/dev-webview
Dev webview
2024-06-22 22:59:28 +08:00
caorushizi 3622e67a56 fix: 🐛 修复浏览器背景颜色 2024-06-22 22:58:25 +08:00
caorushizi c51630cdd6 fix: 🐛 修复切换隐私模式时 Proxy 和嗅探问题 2024-06-22 22:14:49 +08:00
士子☀️ dab1c55a93 Merge pull request #193 from caorushizi/dev-webview
feat(settings):   新增无痕浏览模式
2024-06-22 21:48:11 +08:00
caorushizi 7b966bc988 feat(settings): 新增无痕浏览模式
设置页面新增无痕浏览模式

新增无痕浏览模式 #52
2024-06-22 21:46:27 +08:00
士子☀️ e5e46bee38 Merge pull request #192 from caorushizi/dev-webview
feat(settings):   添加自动更新选项
2024-06-22 15:55:09 +08:00
caorushizi 3365d96a03 feat(settings): 添加自动更新选项
设置页面添加自动更新选项,下次启动时生效

auto upgrade #185
2024-06-22 15:53:42 +08:00
士子☀️ fb223cd493 Merge pull request #191 from caorushizi/dev-webview
feat:   添加下载代理开关 & 添加清空缓存
2024-06-22 15:36:18 +08:00
caorushizi 60d49c4773 feat: 添加下载代理开关 & 添加清空缓存 2024-06-22 15:35:08 +08:00
士子☀️ e7aa4ae147 Merge pull request #190 from caorushizi/dev-webview
build: 🛠  portable
2024-06-22 12:42:50 +08:00
caorushizi c45be41ddc build: 🛠 portable 2024-06-22 12:41:45 +08:00
士子☀️ 85b37facee Merge pull request #189 from caorushizi/dev-webview
Dev webview
2024-06-22 12:27:58 +08:00
caorushizi 90567009ef Merge branch 'dev-webview' of https://github.com/caorushizi/m3u8-downloader into dev-webview 2024-06-22 12:26:36 +08:00
caorushizi 899afc156e build: 🛠 upload artifact 2024-06-22 12:25:51 +08:00
caorushizi 9e33b7e488 build: 🛠 upload artifact 2024-06-22 12:24:24 +08:00
士子☀️ e7ba60a51f Merge pull request #188 from caorushizi/dev-webview
build: 🛠  portable
2024-06-22 12:11:55 +08:00
caorushizi 2a3ad325c2 build: 🛠 portable 2024-06-22 12:11:19 +08:00
caorushizi 7575b80d31 build: 🛠 portable 2024-06-22 12:08:33 +08:00
士子☀️ 8bb9d119b5 Merge pull request #187 from caorushizi/dev-webview
Dev webview
2024-06-22 11:54:18 +08:00
caorushizi 5da3f2b1c7 build: 🛠 优化构建 2024-06-22 11:50:40 +08:00
caorushizi da6cbcfb75 feat: 修复 webview 中加载的问题 2024-06-22 10:44:34 +08:00
caorushizi 3d7aff41ee feat: 优化内置浏览器逻辑 2024-06-22 03:42:15 +08:00
士子☀️ 2cc49e8679 Merge pull request #186 from caorushizi/dev-ap
feat:   ap
2024-06-21 23:44:42 +08:00
caorushizi 0e961c0647 feat: use td app 2024-06-21 23:39:45 +08:00
caorushizi 4d5757a6ce feat: ap 2024-06-21 00:04:21 +08:00
士子☀️ 62ae0e5075 Merge pull request #184 from caorushizi/feat/v2.2.2
feat:   v2.2.2
2024-06-18 09:08:22 +08:00
caorushizi 7513fe2882 feat: v2.2.2 2024-06-18 09:06:42 +08:00
士子☀️ c945dc8360 Merge pull request #183 from caorushizi/feat/v2.2.1
feat:   release v2.2.1
2024-06-17 23:59:20 +08:00
caorushizi de7e0da045 feat: release v2.2.1 2024-06-17 23:57:36 +08:00
士子☀️ a706429395 Merge pull request #182 from caorushizi/feat/v2.2.1
feat:   v2.2.1
2024-06-17 23:34:01 +08:00
caorushizi f26c9761c3 feat: v2.2.1 2024-06-17 23:32:58 +08:00
士子☀️ 9424dd4c0e Merge pull request #181 from caorushizi/dev/form
Dev/form
2024-06-17 23:30:55 +08:00
caorushizi 271294a8e7 feat: conversion page 2024-06-17 23:29:27 +08:00
caorushizi 6b2786292f feat: conversion page 2024-06-10 00:17:32 +08:00
caorushizi c36247b5e1 feat: update form 2024-06-09 23:09:55 +08:00
士子☀️ c182afff2c Merge pull request #177 from caorushizi/feat/v2.2.1-beta.0
feat:   release 2.2.1-beta.0
2024-06-09 20:25:36 +08:00
caorushizi 1129d70dca feat: release 2.2.1-beta.0 2024-06-09 20:24:20 +08:00
士子☀️ bde71d13f9 Merge pull request #176 from caorushizi/dev/download-items
fix: 🐛  download items
2024-06-08 18:37:57 +08:00
caorushizi 67b513d380 fix: 🐛 merge master 2024-06-08 18:36:51 +08:00
caorushizi 8d8d1ee238 fix: 🐛 download item 2024-06-08 18:32:23 +08:00
caorushizi 7c10715607 Merge branch 'master' of https://github.com/caorushizi/m3u8-downloader 2024-06-08 18:27:50 +08:00
caorushizi a939f06fcd Revert "fix: 🐛 下载嗅探到的最后一个文件"
This reverts commit 2a42a02f3d.
2024-06-08 18:24:38 +08:00
士子☀️ c50625b0c8 Merge pull request #170 from caorushizi/feat/addForm
fix: 🐛  下载嗅探到的最后一个文件
2024-06-08 18:20:48 +08:00
caorushizi bfa2d88935 fix: 🐛 download items 2024-06-08 18:02:38 +08:00
士子☀️ b04ea61e83 Merge pull request #170 from caorushizi/feat/addForm
fix: 🐛  下载嗅探到的最后一个文件
2024-05-31 12:10:06 +08:00
caorushizi 2a42a02f3d fix: 🐛 下载嗅探到的最后一个文件 2024-05-31 12:08:25 +08:00
士子☀️ 1e80278a1d Merge pull request #167 from caorushizi/dependabot/npm_and_yarn/cz-git-1.9.2
chore(deps-dev): bump cz-git from 1.9.1 to 1.9.2
2024-05-27 21:20:01 +08:00
士子☀️ f38d9156c5 Merge pull request #169 from caorushizi/feat/addForm
docs: 📝  release
2024-05-27 21:18:58 +08:00
caorushizi 0f32864079 docs: 📝 release 2024-05-27 21:16:59 +08:00
士子☀️ f8fbecebc9 Merge pull request #168 from caorushizi/feat/addForm
fix: 🐛  build scripts
2024-05-27 20:52:39 +08:00
caorushizi 40c5656080 fix: 🐛 build scripts 2024-05-27 20:47:07 +08:00
dependabot[bot] ddf36a7091 chore(deps-dev): bump cz-git from 1.9.1 to 1.9.2
Bumps [cz-git](https://github.com/Zhengqbbb/cz-git/tree/HEAD/packages/cz-git) from 1.9.1 to 1.9.2.
- [Release notes](https://github.com/Zhengqbbb/cz-git/releases)
- [Changelog](https://github.com/Zhengqbbb/cz-git/blob/main/packages/cz-git/CHANGELOG.md)
- [Commits](https://github.com/Zhengqbbb/cz-git/commits/v1.9.2/packages/cz-git)

---
updated-dependencies:
- dependency-name: cz-git
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 04:15:52 +00:00
士子☀️ 258c67554d Merge pull request #166 from caorushizi/feat/addForm
feat:   完善表单项
2024-05-27 04:40:01 +08:00
caorushizi 007ff31200 feat: 完善表单项 2024-05-27 04:37:50 +08:00
士子☀️ ff75e3d94b Merge pull request #165 from caorushizi/feat/addForm
feat:   修改创建修改表单
2024-05-27 01:52:01 +08:00
caorushizi aaa18e0048 feat: 修改创建修改表单 2024-05-27 01:51:07 +08:00
士子☀️ 5c6f89a067 Merge pull request #164 from caorushizi/feat/dependencies
refactor: 📦️  update eslint
2024-05-26 20:00:37 +08:00
caorushizi c4efc4c293 refactor: 📦️ update eslint 2024-05-26 19:40:51 +08:00
士子☀️ 2d955257e6 Merge pull request #163 from caorushizi/feat/dependencies
fix: 🐛  update dependencies
2024-05-26 18:57:29 +08:00
caorushizi 3cf84a2992 fix: 🐛 update dependencies 2024-05-26 18:56:02 +08:00
士子☀️ 94a795fe69 Merge pull request #162 from caorushizi/feat/dependencies
feat:   update dependencies
2024-05-26 18:10:18 +08:00
caorushizi cc10ae8b2e feat: update dependencies 2024-05-26 17:58:40 +08:00
caorushizi 63ed7cdaca fix: 🐛 直播视频不展示下载进度 2024-05-26 17:21:58 +08:00
caorushizi 064919e0a2 fix: 🐛 build variable 2024-05-26 17:14:27 +08:00
士子☀️ 31b2652c9b Merge pull request #161 from caorushizi/fix/scripts
fix: 🐛  build script
2024-05-26 16:38:58 +08:00
caorushizi d080d709d1 fix: 🐛 build script 2024-05-26 16:37:59 +08:00
士子☀️ 0c301c79f2 Merge pull request #160 from caorushizi/fix/scripts
fix: 🐛  build
2024-05-26 15:59:19 +08:00
caorushizi a1dbb6234f fix: 🐛 build 2024-05-26 15:56:40 +08:00
士子☀️ 30248194af Merge pull request #159 from caorushizi/fix/scripts
fix: 🐛  pnpm actions
2024-05-26 15:32:03 +08:00
caorushizi 8f54ebeb3a fix: 🐛 pnpm actions 2024-05-26 15:30:34 +08:00
士子☀️ d8ef0b9eee Merge pull request #158 from caorushizi/fix/scripts
fix: 🐛  npm rebuild
2024-05-26 15:10:52 +08:00
caorushizi 6a3bfd071a fix: 🐛 npm rebuild 2024-05-26 15:05:58 +08:00
士子☀️ 849df04c05 Merge pull request #157 from caorushizi/fix/scripts
fix: 🐛  打包分片
2024-05-26 14:29:25 +08:00
caorushizi a40ae5ef82 fix: 🐛 打包分片 2024-05-26 14:28:18 +08:00
士子☀️ 00c535665f Merge pull request #156 from caorushizi/fix/scripts
fix: 🐛  scripts name
2024-05-26 02:29:51 +08:00
caorushizi 8b4a4d8ff8 fix: 🐛 scripts name 2024-05-26 02:29:05 +08:00
士子☀️ f9fecd541c Merge pull request #155 from caorushizi/fix/adblocker
Fix/adblocker
2024-05-26 02:07:25 +08:00
caorushizi 93b1028498 fix: 🐛 some bug
'
2024-05-26 02:05:53 +08:00
caorushizi a0a3dba188 refactor: 📦️ 代码分割 2024-05-25 23:37:23 +08:00
caorushizi 92ded00495 feat: 构建流程优化 2024-05-25 22:00:31 +08:00
caorushizi bcbe258f60 fix: 🐛 修复打包完成后没有权限执行的问题 2024-05-25 15:23:26 +08:00
caorushizi 660f9c7c9b feat: support linux 2024-05-25 03:02:49 +08:00
caorushizi 8c5ef29894 feat: support linux 2024-05-25 02:59:48 +08:00
caorushizi 612fc4c533 fix: 🐛 修复开启广告过滤时无法沉浸式嗅探 2024-05-24 21:27:36 +08:00
士子☀️ 635377d227 Merge pull request #153 from caorushizi/feat/webcontentsView
Feat/webcontents view
2024-05-22 21:11:38 +08:00
caorushizi dc86ab8f4c feat: release 2.2.0 2024-05-22 21:09:25 +08:00
caorushizi 36b63ad916 fix: 🐛 bilibili 2024-05-22 20:56:18 +08:00
士子☀️ e1b378811d Merge pull request #152 from caorushizi/feat/webcontentsView
fix: 🐛  .env
2024-05-22 19:30:00 +08:00
caorushizi 37fb9bba75 fix: 🐛 .env 2024-05-22 19:28:19 +08:00
士子☀️ 848253c678 Merge pull request #151 from caorushizi/feat/webcontentsView
Feat/webcontents view
2024-05-22 18:19:33 +08:00
caorushizi b64e779ed1 feat: release 2.2.0-beta.4 2024-05-22 18:18:07 +08:00
caorushizi 046a62cde3 fix: 🐛 load url 2024-05-22 18:16:38 +08:00
caorushizi 1a9e6efb90 feat: use webcontents view and capture page 2024-05-22 15:15:39 +08:00
士子☀️ fd422c15ba Merge pull request #150 from caorushizi/fix/addForm
fix: 🐛  fix run release scripts
2024-05-22 04:04:18 +08:00
caorushizi c338f76f8d fix: 🐛 fix run release scripts 2024-05-22 04:03:32 +08:00
士子☀️ 4285b3f4f7 Merge pull request #149 from caorushizi/fix/addForm
feat:   支持直播视频下载
2024-05-22 03:51:41 +08:00
caorushizi d0109869a6 feat: 支持直播视频下载 2024-05-22 03:50:38 +08:00
士子☀️ d29ad44c54 Merge pull request #148 from caorushizi/fix/addForm
fix: 🐛  float button position
2024-05-22 01:02:50 +08:00
caorushizi be61b07fea fix: 🐛 float button position 2024-05-22 01:01:38 +08:00
士子☀️ e5e171fb6f Merge pull request #147 from caorushizi/fix/addForm
fix: 🐛  release 2.2.0-beta.3
2024-05-22 00:33:59 +08:00
caorushizi 805d97c3ca fix: 🐛 release 2.2.0-beta.3 2024-05-22 00:32:35 +08:00
士子☀️ 040222f259 Merge pull request #146 from caorushizi/fix/addForm
fix: 🐛  fix browser window event
2024-05-21 22:52:39 +08:00
caorushizi 09ed55eba4 fix: 🐛 fix browser window event 2024-05-21 22:51:40 +08:00
士子☀️ a6d4f8cf98 Merge pull request #145 from caorushizi/fix/addForm
fix: 🐛  release 2.2.0-beta.2
2024-05-21 02:38:48 +08:00
caorushizi d19b2394e8 fix: 🐛 release 2.2.0-beta.2 2024-05-21 02:37:40 +08:00
士子☀️ 036a99d84d Merge pull request #143 from caorushizi/fix/video
Fix/video
2024-05-14 12:22:24 +08:00
caorushizi b022335af7 feat: release 2.2.0-beta.1 2024-05-14 12:21:21 +08:00
caorushizi a66c20c9d5 feat: 修复页面中下载嗅探问题 2024-05-14 12:19:47 +08:00
caorushizi f9fc135647 fix: 🐛 修复 dom-ready 执行的顺序 2024-05-13 09:49:34 +08:00
士子☀️ fbbee9c114 Merge pull request #142 from caorushizi/fix/docs
Fix/docs
2024-05-13 09:42:35 +08:00
caorushizi a65fbcbaf8 fix: 🐛 修复插件展现运行的时机 2024-05-13 09:41:06 +08:00
士子☀️ 39b68b71d4 refactor: 📦️ modify mediago protocol, upgrade adblocker 2024-05-13 01:51:13 +08:00
士子☀️ 4d12a0a937 Merge pull request #140 from caorushizi/fix/docs
ci: 🎡  github actions
2024-05-02 19:01:16 +08:00
士子☀️ 960973302e ci: 🎡 github actions 2024-05-02 18:58:01 +08:00
士子☀️ 1a68b00bdd Merge pull request #139 from caorushizi/fix/docs
ci: 🎡  modify github actions
2024-05-02 18:32:22 +08:00
士子☀️ dba73fc473 ci: 🎡 modify github actions 2024-05-02 18:30:24 +08:00
士子☀️ 211f7314ce Merge pull request #138 from caorushizi/fix/docs
docs: 📝  remove reaction
2024-05-02 18:18:19 +08:00
士子☀️ 64d719a63a docs: 📝 remove reaction 2024-05-02 18:17:19 +08:00
士子☀️ 0304e6b569 Merge pull request #135 from caorushizi/feat/mediago
Feat/mediago
2024-04-05 23:46:23 +08:00
士子☀️ 190447a0bd feat: release v2.2.0-beta.0 2024-04-05 23:44:13 +08:00
士子☀️ 497d1265f0 chore: 🔨 add lint-staged 2024-04-05 23:42:35 +08:00
士子☀️ 6d459e0692 feat: rename mediago 2024-04-05 23:09:30 +08:00
士子☀️ 45cde40cea chore: 🔨 fix pre-commit 2024-04-05 22:36:13 +08:00
士子☀️ e9deb4c7f7 chore: 🔨 use tsx instead of ts-node 2024-04-05 22:02:59 +08:00
caorushizi 1abfc763dc docs: 📝 update waline client 2024-03-26 14:31:00 +08:00
caorushizi b84ddcc88d docs: 📝 update vitepress 2024-03-26 13:02:22 +08:00
士子☀️ 33f7951901 refactor: 📦️ remove submodule 2024-03-20 23:23:09 +08:00
士子☀️ d3354f9109 Merge pull request #125 from caorushizi/feat/player
refactor: 📦️  remove tsno
2024-03-20 19:32:06 +08:00
caorushizi d252816cc3 refactor: 📦️ remove tsno 2024-03-20 19:29:27 +08:00
士子☀️ 6e31904e95 Merge pull request #124 from caorushizi/feat/player
refactor: 📦️  remove video player
2024-03-20 16:59:12 +08:00
caorushizi 2825d1f4c7 refactor: 📦️ remove video player 2024-03-20 16:50:58 +08:00
士子☀️ fcb10c6137 Merge pull request #118 from caorushizi/feat/player
fix: 🐛  catch video
2024-03-17 18:04:27 +08:00
士子☀️ f564739578 fix: 🐛 catch video 2024-03-17 18:03:24 +08:00
士子☀️ 40faf4b383 Merge pull request #117 from caorushizi/feat/player
fix: 🐛  fix mobile video size
2024-03-17 17:46:01 +08:00
士子☀️ affff353bd fix: 🐛 fix mobile video size 2024-03-17 17:45:04 +08:00
士子☀️ f410fabff7 Merge pull request #116 from caorushizi/feat/player
fix: 🐛  fix video container
2024-03-17 17:22:13 +08:00
士子☀️ 7d4b201b6e fix: 🐛 fix video container 2024-03-17 17:21:10 +08:00
士子☀️ a9ac0aa16b Merge pull request #115 from caorushizi/2.1.0-beta.1
feat:   v2.1.0-beta.1
2024-03-17 16:09:16 +08:00
士子☀️ 5419970080 feat: v2.1.0-beta.1 2024-03-17 16:08:34 +08:00
士子☀️ 506a573180 Merge pull request #114 from caorushizi/feat/dialog
fix: 🐛 按照获取时间正序排列
2024-03-17 02:03:43 +08:00
士子☀️ 17b2450b43 feat: use download dialog 2024-03-17 02:01:32 +08:00
士子☀️ 2942e65a54 fix: 🐛 按照获取时间正序排列 2024-03-17 00:17:47 +08:00
士子☀️ 913a7bd9e5 Merge pull request #113 from caorushizi/feat/dialog
feat:   show download dialog
2024-03-17 00:12:31 +08:00
士子☀️ c5f2edd9de feat: show download dialog 2024-03-17 00:09:34 +08:00
士子☀️ 24d511e6b6 Merge pull request #112 from caorushizi/feat/plugins
feat:  bilibili plguins
2024-03-10 19:23:15 +08:00
士子☀️ 47f3336f9a feat: 2.1.0-beta.0 2024-03-10 19:22:30 +08:00
士子☀️ e0e6e5dbed feat: bilibili plguins 2024-03-10 19:19:27 +08:00
士子☀️ aa7f3e7bf7 Merge pull request #111 from caorushizi/feat/terminal
feat:  use terminal
2024-03-10 16:43:04 +08:00
caorushizi 065a6c45f7 feat: terminal 2024-03-10 16:40:25 +08:00
士子☀️ b13174dda1 feat: use terminal 2024-03-10 16:19:16 +08:00
士子☀️ 9e6a931a41 Merge pull request #109 from caorushizi/feat/terminal
feat:  terminal
2024-03-09 08:57:23 +08:00
士子☀️ cdabdfd2f8 feat: layout style 2024-03-09 01:06:49 +08:00
士子☀️ b4cdbd7547 feat: show terminal 2024-03-09 00:05:15 +08:00
caorushizi 75fe603919 feat: terminal 2024-03-08 21:35:05 +08:00
士子☀️ 16ef9ae642 Merge pull request #104 from caorushizi/feat/actions
feat:   add vscode debug config
2024-02-27 23:13:35 +08:00
士子☀️ 7db3162748 feat: add vscode debug config 2024-02-27 23:11:37 +08:00
士子☀️ 3f0e6d9856 Merge pull request #102 from caorushizi/feat/actions
feat:   update actions version
2024-02-27 01:04:51 +08:00
士子☀️ d87fc4a400 feat: update actions version 2024-02-27 01:03:26 +08:00
士子☀️ ec6241b79e Merge pull request #101 from caorushizi/fix/node-pty
fix: 🐛  cannot find module 'node-pty'
2024-02-27 00:50:42 +08:00
士子☀️ 9b37398e9f fix: 🐛 cannot find module 'node-pty' 2024-02-27 00:49:05 +08:00
士子☀️ 3fca8694ee fix: 🐛 filename 2024-02-25 23:39:24 +08:00
士子☀️ 78efffa29b Merge pull request #95 from caorushizi/dev/terminal
Dev/terminal
2024-02-25 22:40:02 +08:00
士子☀️ 737ecbdadd fix: 🐛 build player 2024-02-25 22:37:34 +08:00
士子☀️ fa6ce22ea7 Merge pull request #94 from caorushizi/dev/terminal
Dev/terminal
2024-02-25 22:22:36 +08:00
士子☀️ 315c55c844 feat: terminal 2024-02-25 18:28:37 +08:00
士子☀️ d9ba60e1a5 feat: terminal 2024-02-25 17:31:58 +08:00
士子☀️ 7503322d01 feat: terminal 2024-02-25 13:36:14 +08:00
士子☀️ 2e5f2dc687 Merge pull request #91 from caorushizi/dev/plugins
style: 💄 eslint
2024-02-24 23:28:27 +08:00
士子☀️ e4afd27908 fix: 🐛 add tsconfig 2024-02-24 23:19:09 +08:00
士子☀️ 6fe5d5523e feat: remove player page. use node-pty 2024-02-24 22:50:03 +08:00
士子☀️ 7335946ec2 refactor: 📦️ refactoring the project directory structure 2024-02-23 19:32:06 +08:00
士子☀️ eb4576de9b feat: 使用 node 伪终端 2024-02-21 22:17:02 +08:00
士子☀️ 1e41a9ee99 feat: node 伪终端获取详细日志 2024-02-21 21:44:12 +08:00
士子☀️ dd5226ab47 refactor: 📦️ downloader 2024-02-12 09:56:07 +08:00
士子☀️ 989e5535eb feat: new player 2024-02-12 01:55:11 +08:00
士子☀️ 65efeed692 style: 💄 eslint 2024-02-11 23:18:45 +08:00
士子☀️ fcddb2d382 Merge pull request #88 from caorushizi/dev/plugins
fix: 🐛  types
2024-02-11 18:13:57 +08:00
士子☀️ bbc892ec81 fix: 🐛 types 2024-02-11 18:08:51 +08:00
士子☀️ ca1c2821a7 Merge pull request #87 from caorushizi/dev/plugins
fix: 🐛  types
2024-02-11 18:02:50 +08:00
士子☀️ c8d4f763fd fix: 🐛 types 2024-02-11 18:00:08 +08:00
士子☀️ a3d587af44 Merge pull request #85 from caorushizi/dev/plugins
feat:  new plugin
2024-02-11 17:00:28 +08:00
士子☀️ ce2146cc89 feat: add plugin 2024-02-11 16:59:02 +08:00
士子☀️ 8455f17517 style: 💄 somthing 2024-02-11 10:45:32 +08:00
士子☀️ c075bdd4f9 feat: new plugin 2024-02-09 22:18:35 +08:00
士子☀️ 65d88d0896 Merge pull request #82 from caorushizi/dev/i18n
feat: display language
2024-02-09 17:01:55 +08:00
士子☀️ 1c62640301 style: 💄 add lint-staged 2024-02-09 17:00:48 +08:00
士子☀️ dd6684c550 feat: build plugin
build plugin with lit.
2024-02-09 15:54:22 +08:00
士子☀️ 2e1a753583 test 2024-02-09 15:41:34 +08:00
士子☀️ cbf6e4ecfb test 2024-02-09 15:26:20 +08:00
士子☀️ 5af471fe1a plugin 2024-02-09 13:23:52 +08:00
士子☀️ 0deb205faa plugin 2024-02-09 00:11:40 +08:00
士子☀️ 73eaf0ecaa plugin 2024-02-09 00:10:32 +08:00
士子☀️ 4791defbdd sniffing helper 2024-02-08 18:23:49 +08:00
士子☀️ 926249184b i18n 2024-02-08 15:12:08 +08:00
士子☀️ 659b2755ef feat: display language 2024-02-04 20:15:43 +08:00
士子☀️ e9d36edaa4 v2.0.3-beta.3 2024-01-22 23:01:56 +08:00
士子☀️ fdcdbf27eb dev tools 2024-01-22 22:25:29 +08:00
士子☀️ 2f5cc2eb80 Merge branch 'master' of https://github.com/caorushizi/m3u8-downloader 2024-01-21 19:11:42 +08:00
士子☀️ c087fa4956 webview 2024-01-21 19:10:11 +08:00
士子☀️ ed33ec6532 actions 2024-01-21 17:54:37 +08:00
士子☀️ 2d96c2730c .npmrc 2024-01-21 17:41:59 +08:00
士子☀️ 5bcec10be3 docs 2024-01-21 17:18:02 +08:00
士子☀️ 207bd15b14 .npmrc 2024-01-21 17:07:41 +08:00
士子☀️ 00f0bfc84b os version 2024-01-21 17:06:59 +08:00
士子☀️ 7bc3f83c88 update electron. 2024-01-21 16:56:59 +08:00
士子☀️ 1af2803c22 eslint 2024-01-21 01:20:02 +08:00
士子☀️ fd6a81abfd package version 2024-01-21 00:01:09 +08:00
士子☀️ a383093914 Merge pull request #71 from caorushizi/dependabot/npm_and_yarn/typescript-eslint/parser-6.19.0
build(deps-dev): bump @typescript-eslint/parser from 5.60.0 to 6.19.0
2024-01-20 23:29:33 +08:00
士子☀️ 13656429af Merge pull request #70 from caorushizi/dependabot/npm_and_yarn/better-sqlite3-9.3.0
build(deps): bump better-sqlite3 from 8.7.0 to 9.3.0
2024-01-20 23:29:11 +08:00
dependabot[bot] bc34881b38 build(deps-dev): bump @typescript-eslint/parser from 5.60.0 to 6.19.0
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.60.0 to 6.19.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.19.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-20 15:11:08 +00:00
dependabot[bot] e3b11cb087 build(deps): bump better-sqlite3 from 8.7.0 to 9.3.0
Bumps [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) from 8.7.0 to 9.3.0.
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](https://github.com/WiseLibs/better-sqlite3/compare/v8.7.0...v9.3.0)

---
updated-dependencies:
- dependency-name: better-sqlite3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-20 15:11:00 +00:00
士子☀️ 8df78ca377 Merge pull request #61 from caorushizi/dependabot/npm_and_yarn/typescript-5.3.3
build(deps-dev): bump typescript from 5.1.6 to 5.3.3
2024-01-20 23:08:49 +08:00
士子☀️ f12919c6bc Update README.md 2024-01-16 23:02:29 +08:00
士子☀️ 00df324ae7 Merge pull request #66 from caorushizi/readme
readme
2024-01-15 22:25:23 +08:00
士子☀️ f14f9ffc1b readme 2024-01-15 22:23:40 +08:00
dependabot[bot] a388b725bc build(deps-dev): bump typescript from 5.1.6 to 5.3.3
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.1.6 to 5.3.3.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.1.6...v5.3.3)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-14 07:37:58 +00:00
caorushizi e64eaeefef macos 2024-01-14 15:35:15 +08:00
士子☀️ 6830d69b62 build script. 2024-01-14 12:09:08 +08:00
士子☀️ 8f609a8e93 checkout 2024-01-14 10:42:54 +08:00
士子☀️ 99c23f47c5 setup go 2024-01-14 10:36:14 +08:00
士子☀️ 95f9e20f39 go build 2024-01-14 01:34:08 +08:00
士子☀️ df1e664bc9 Merge pull request #60 from caorushizi/dev0114
add plugin
2024-01-14 01:25:05 +08:00
士子☀️ fec30a6453 add plugin 2024-01-14 01:24:24 +08:00
士子☀️ a048211486 add plugin 2024-01-14 01:14:02 +08:00
士子☀️ 465e9b2988 add plugin 2024-01-13 23:19:19 +08:00
士子☀️ af1ff19cb2 add web plugin 2024-01-13 20:28:58 +08:00
士子☀️ eae470f2ec video server 2024-01-13 12:24:52 +08:00
士子☀️ 1933799e32 feat: video list. 2024-01-13 01:03:46 +08:00
士子☀️ c7977bf7b4 Merge pull request #55 from caorushizi/dependabot/npm_and_yarn/electron-25.8.4
build(deps-dev): bump electron from 25.2.0 to 25.8.4
2023-12-29 16:40:43 +08:00
士子☀️ ce8407ce46 Merge pull request #58 from caorushizi/dependabot/npm_and_yarn/axios-1.6.0
build(deps): bump axios from 1.4.0 to 1.6.0
2023-12-29 16:40:01 +08:00
dependabot[bot] 5d313df190 build(deps): bump axios from 1.4.0 to 1.6.0
Bumps [axios](https://github.com/axios/axios) from 1.4.0 to 1.6.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.4.0...v1.6.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-11 13:41:05 +00:00
dependabot[bot] c560a09904 build(deps-dev): bump electron from 25.2.0 to 25.8.4
Bumps [electron](https://github.com/electron/electron) from 25.2.0 to 25.8.4.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v25.2.0...v25.8.4)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-05 17:37:26 +00:00
士子☀️ df66a92989 Merge pull request #46 from caorushizi/feat/v2.1.0
m3u8
2023-08-22 14:49:01 +08:00
士子☀️ 52c9611e49 m3u8 2023-08-07 23:54:19 +08:00
士子☀️ 4018112a1d 优化二进制调用逻辑 2023-08-02 21:26:46 +08:00
士子☀️ 633a257e65 优化表单 2023-08-01 23:49:22 +08:00
caorushizi 0666d41226 工程优化 2023-07-29 14:14:37 +08:00
士子☀️ c2cfe55e24 Merge pull request #43 from caorushizi/dev/2.1.0 2023-07-29 13:43:37 +08:00
士子☀️ cb7fbddd7a 工程优化 2023-07-29 13:41:16 +08:00
士子☀️ 135d9fed1b 工程优化 2023-07-29 10:39:27 +08:00
士子☀️ 267aedc594 工程优化 2023-07-29 09:24:11 +08:00
士子☀️ 325d0da930 工程优化 2023-07-29 00:28:01 +08:00
士子☀️ 615bc74d15 Merge pull request #42 from caorushizi/dev/2.1.0 2023-07-27 17:59:32 +08:00
士子☀️ 1ca6935d36 download form. 2023-07-24 23:49:10 +08:00
士子☀️ 3bfb7139d3 download form. 2023-07-22 12:56:56 +08:00
士子☀️ 14d44765e5 form name 2023-07-22 00:03:58 +08:00
士子☀️ 807dd2d920 request 2023-07-21 23:39:02 +08:00
士子☀️ c9a0a7f7c2 request 2023-07-21 23:31:07 +08:00
士子☀️ a3eea6d501 v2.1.0 2023-07-20 23:25:33 +08:00
士子☀️ 4ce7dcac1b Merge pull request #38 from caorushizi/dev 2023-07-18 23:51:35 +08:00
士子☀️ 096762f24c some thing 2023-07-18 23:49:03 +08:00
士子☀️ baf358d223 something 2023-07-18 23:44:22 +08:00
士子☀️ e72973346b add: get web request. 2023-07-12 00:30:15 +08:00
士子☀️ 41258ecee8 add: get web request response. 2023-07-11 22:48:14 +08:00
士子☀️ b6a5be152a Merge pull request #37 from caorushizi/dev0709 2023-07-09 15:39:55 +08:00
士子☀️ d5d45c4935 fix: download use proxy. 2023-07-09 15:38:48 +08:00
士子☀️ 81eb4ecf09 Merge pull request #36 from caorushizi/dev0709 2023-07-09 15:09:23 +08:00
士子☀️ 5a4cc8c449 bin dir 2023-07-09 15:07:57 +08:00
士子☀️ e7ab664310 release: v2.0.2 2023-07-09 14:54:21 +08:00
士子☀️ 3cb2fa27b9 release: v2.0.2 2023-07-09 14:18:41 +08:00
士子☀️ e29e41aa4c release: v2.0.2 2023-07-09 14:01:15 +08:00
士子☀️ cc62613640 Merge pull request #35 from caorushizi/release/v2.0.2 2023-07-09 13:53:19 +08:00
士子☀️ 2720bcc685 release: v2.0.2 2023-07-09 13:52:40 +08:00
353 changed files with 26063 additions and 12874 deletions
+66
View File
@@ -0,0 +1,66 @@
acodec
adblocker
ahooks
aliyuncs
antd
aplus
behaviour
bili
bilibili
bodyparser
bodys
buildx
cancle
cliqz
clsx
commitlint
compat
Conpty
consola
conventionalcommits
datetime
DDTHH
deeplink
esmfile
execa
ghostery
idtype
immer
inversify
KHTML
languagedetector
localforage
lucide
mediago
metas
nocheck
optimizelegibility
outdir
pinia
Qrcode
redownload
Redownload
reduxjs
remusao
rmvb
shadcn
Sider
smaz
stylelint
svgr
svgz
tailwindcss
TDAPP
tiptap
tldts
tseslint
typeorm
vaul
vitepress
vuedraggable
vuejs
waline
watting
Watting
xgplayer
zustand
+3 -4
View File
@@ -1,6 +1,5 @@
APP_NAME=media-downloader
# FIXME: APP_ 开头的会暴漏给前端
APP_NAME=mediago
APP_ID=mediago.ziying.site
APP_COPYRIGHT=caorushizi
APP_VERSION=2.0.2
APP_SERVER_PORT=8433
APP_VERSION=3.0.1
+1 -1
View File
@@ -1,5 +1,5 @@
APP_TD_APPID=
APP_DOWNLOAD_DEBUG=true
GH_TOKEN=
LOAD_DEVTOOLS=
DEBUG_PLUGINS=true
+1 -1
View File
@@ -1,4 +1,4 @@
APP_TD_APPID=
APP_DOWNLOAD_DEBUG=
GH_TOKEN=
DEBUG_PLUGINS=false
+1 -1
View File
@@ -5,7 +5,7 @@
version: 2
updates:
- package-ecosystem: "" # See documentation for possible values
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
+18 -8
View File
@@ -8,6 +8,7 @@ on:
push:
branches:
- master
workflow_dispatch:
# Workflow's jobs
jobs:
@@ -23,32 +24,41 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
os: [windows-latest, macos-latest, macos-13, ubuntu-latest]
# create steps
steps:
# step1: check out repository
- name: Check out git repository
uses: actions/checkout@v3
uses: actions/checkout@v4
# step2: install node env
- name: Install Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "16.x"
node-version: 20
- uses: pnpm/action-setup@v2
# step4: install python env
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
# step5: install pnpm env
- uses: pnpm/action-setup@v3
with:
version: latest
run_install: true
standalone: true
- name: Build & release app
run: pnpm run release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
APP_TD_APPID: ${{ secrets.APP_TD_APPID }}
APP_CLARITY_APPID: ${{ secrets.APP_CLARITY_APPID}}
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: artifact
path: packages/main/release/media-downloader-setup-*
name: mediago-${{ matrix.os }}
path: packages/main/release/mediago-*
+51
View File
@@ -0,0 +1,51 @@
name: Build and Push Multi-arch Docker Image
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v3
with:
version: latest
run_install: true
standalone: true
- name: Build
run: pnpm build:web-release
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Aliyun Container Registry
uses: docker/login-action@v3
with:
registry: registry.cn-beijing.aliyuncs.com
username: ${{ secrets.ALIYUN_USERNAME }}
password: ${{ secrets.ALIYUN_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
registry.cn-beijing.aliyuncs.com/caorushizi/mediago:latest
registry.cn-beijing.aliyuncs.com/caorushizi/mediago:${{ github.sha }}
-49
View File
@@ -1,49 +0,0 @@
name: Deploy Downloader Docs.
on:
push:
branches: ["master"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
env:
BUILD_PATH: "."
BUCKET: downloader-docs
ENDPOINT: oss-cn-beijing.aliyuncs.com
ACCESS_KEY: LTAI5tLckcUrBtj7bCiUYwWz
ACCESS_KEY_SECRET: ${{ secrets.ACCESS_KEY_SECRET }}
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "16"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install
working-directory: ${{ env.BUILD_PATH }}
- name: Build with Vitepress
run: pnpm run docs:build
working-directory: ${{ env.BUILD_PATH }}
- name: Install Alibaba Cloud OSSUTIL
run: wget http://gosspublic.alicdn.com/ossutil/1.6.10/ossutil64 && chmod +x ossutil64
- name: Configure Alibaba Cloud OSSUTIL
run: ./ossutil64 config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT} -c .ossutilconfig
- name: Upload the web folder to the chosen OSS bucket
run: ./ossutil64 --config-file .ossutilconfig cp ${{ github.workspace }}/docs/.vitepress/dist oss://${BUCKET} -r -f
+2 -1
View File
@@ -1,5 +1,6 @@
node_modules
.vscode
*.local
.idea
.parcel-cache
.vitepress
*.tsno.mjs
+1 -1
View File
@@ -10,4 +10,4 @@
}
]
}
}
}
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit ${1}
npm run commitlint ${1}
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"
npx tsx ./scripts/pre-commit.ts
+3
View File
@@ -0,0 +1,3 @@
# Ignore artifacts:
build
coverage
+23
View File
@@ -0,0 +1,23 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch dev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "dev"],
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Attach to Electron",
"type": "node",
"request": "attach",
"address": "localhost",
"restart": true,
"timeout": 10000,
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}"
}
]
}
+34
View File
@@ -0,0 +1,34 @@
FROM m.daocloud.io/docker.io/library/node:20 AS builder
WORKDIR /app
COPY ./packages/backend/dist /app
COPY ./packages/backend/package*.json ./
RUN npm install --omit=dev --registry=https://registry.npmmirror.com
RUN npm rebuild
# FROM m.daocloud.io/docker.io/library/debian:11-slim AS deb_extractor
# RUN cd /tmp && \
# apt-get update && apt-get download libicu-dev && \
# mkdir /dpkg && \
# for deb in *.deb; do dpkg --extract $deb /dpkg || exit 10; done
# FROM gcr.io/distroless/nodejs20-debian12
FROM m.daocloud.io/docker.io/library/node:20-bookworm-slim
WORKDIR /app
COPY --from=builder /app /app
# COPY --from=deb_extractor /dpkg /
RUN apt-get update && apt-get install -y libicu-dev ffmpeg
RUN npm install pm2 -g
EXPOSE 8899
CMD ["pm2-runtime", "server/index.js"]
+141
View File
@@ -0,0 +1,141 @@
<div align="center">
<h1>MediaGo</h1>
<a href="https://downloader.caorushizi.cn/en/guides.html?form=github">Quick start</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://downloader.caorushizi.cn/en?form=github">Website</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://downloader.caorushizi.cn/en/documents.html?form=github">Docs</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://github.com/caorushizi/mediago/discussions">Discussions</a>
<br>
<br>
<img alt="GitHub Downloads (all assets, all releases)" src="https://img.shields.io/github/downloads/caorushizi/mediago/total">
<img alt="GitHub Downloads (all assets, latest release)" src="https://img.shields.io/github/downloads/caorushizi/mediago/latest/total">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/caorushizi/mediago">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/caorushizi/mediago">
<br>
<br>
<a href="https://trendshift.io/repositories/11083" target="_blank">
<img src="https://trendshift.io/api/badge/repositories/11083" alt="caorushizi%2Fmediago | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
</a>
<hr />
</div>
## Intro
This project supports m3u8 video extraction tools, streaming media download, and m3u8 download.
- **✅&nbsp; No need to capture packets**: You can easily sniff video resources on web pages using the built-in browser. Choose the resource you want to download from the sniffed resource list—simple and fast.
- **📱&nbsp; Mobile playback**: Easily switch between PC and mobile devices seamlessly. Once downloaded, you can watch the video on your phone.
- **⚡️&nbsp; Batch download**: Supports downloading multiple videos and live streams simultaneously, ensuring high bandwidth is fully utilized.
- **🎉&nbsp; Docker deployment supported**: Supports Docker deployment for the web version, making it convenient and quick.
## Quickstart
To run the code, you'll need Node.js and pnpm. Node.js can be downloaded and installed from the official website, and pnpm can be installed via `npm i -g pnpm`.
## Run the code
```shell
# Code download
git clone https://github.com/caorushizi/mediago.git
# Installation dependency
pnpm i
# Development environment
pnpm dev
# Package run
pnpm release
# Build a docker image
docker buildx build -t caorushizi/mediago:latest .
# docker startup
docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago
```
## Releases
### v3.0.0 (Released on 2024.10.7)
#### Software Downloads
- [【mediago】 Windows (Installer) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-win32-x64-3.0.0.exe)
- [【mediago】 Windows (Portable) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-portable-win32-x64-3.0.0.exe)
- [【mediago】 macOS ARM64 (Apple Silicon) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-darwin-arm64-3.0.0.dmg)
- [【mediago】 macOS x64 (Intel) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-darwin-x64-3.0.0.dmg)
- [【mediago】 Linux v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-linux-amd64-3.0.0.deb)
- 【mediago】 Docker v3.0 `docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago:v3.0.0`
#### Domestic Downloads
- [【mediago】 Windows (Installer) v3.0.0](https://static.ziying.site/mediago/mediago-setup-win32-x64-3.0.0.exe)
- [【mediago】 Windows (Portable) v3.0.0](https://static.ziying.site/mediago/mediago-portable-win32-x64-3.0.0.exe)
- [【mediago】 macOS ARM64 (Apple Silicon) v3.0.0](https://static.ziying.site/mediago/mediago-setup-darwin-arm64-3.0.0.dmg)
- [【mediago】 macOS x64 (Intel) v3.0.0](https://static.ziying.site/mediago/mediago-setup-darwin-x64-3.0.0-beta.5.dmg)
- [【mediago】 Linux v3.0.0](https://static.ziying.site/mediago/mediago-setup-linux-amd64-3.0.0.deb)
- 【mediago】 Docker v3.0 `docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago:v3.0.0`
### One-click Docker Panel Deployment (Recommended)
1. Install the BT Panel by visiting [BT Panel](https://www.bt.cn/new/download.html?r=dk_mediago) and downloading the official version script.
2. After installation, log into the BT Panel, click on `Docker` in the menu bar. The first time you enter, it will prompt you to install the `Docker` service. Click to install and follow the instructions to complete the installation.
3. Once installed, find `MediaGo` in the application store, click install, configure domain names, and other basic information to complete the installation.
### Software Screenshots
![Homepage](https://static.ziying.site/images/home.png)
### Major Updates
- Support for Docker deployment on the web version
- Updated desktop UI
### Changelog
- Updated desktop UI
- Support for Docker deployment on the web version
- Added video playback, supporting both desktop and mobile playback
- Fixed issue where the macOS version couldn't display the interface
- Optimized the batch download interaction
- Added portable version for Windows (no installation required)
- Optimized the download list, supporting sniffing multiple videos on a page
- Supported manual import/export of the favorites list
- Supported export of the homepage download list
- Optimized the interaction logic for the "New Download" form
- Supported opening the app via UrlScheme and adding download tasks
- Fixed several bugs and enhanced the user experience
## Software Screenshots
![Homepage](https://static.ziying.site/images/home.png)
![Homepage-dark](https://static.ziying.site/images/home-dark.png)
![Settings Page](https://static.ziying.site/images/settings.png)
![Resource Extraction](https://static.ziying.site/images/browser.png)
## Tech Stack
- React <https://react.dev/>
- Electron <https://www.electronjs.org>
- Koa <https://koajs.com>
- Vite <https://cn.vitejs.dev>
- Ant Design <https://ant.design>
- Tailwind CSS <https://tailwindcss.com>
- Shadcn <https://ui.shadcn.com/>
- Inversify <https://inversify.io>
- TypeORM <https://typeorm.io>
## Acknowledgements
- N_m2u8DL-CLI from <https://github.com/nilaoda/N_m3u8DL-CLI>
- N_m3u8DL-RE from <https://github.com/nilaoda/N_m3u8DL-RE>
- mediago from <https://github.com/caorushizi/hls-downloader>
+143
View File
@@ -0,0 +1,143 @@
<div align="center">
<h1>MediaGo</h1>
<a href="https://downloader.caorushizi.cn/jp/guides.html?form=github">早く始めます</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://downloader.caorushizi.cn/jp?form=github">公式サイトです</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://downloader.caorushizi.cn/jp/documents.html?form=github">にやすりをかける</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://github.com/caorushizi/mediago/discussions">Discussions</a>
<br>
<br>
<img alt="GitHub Downloads (all assets, all releases)" src="https://img.shields.io/github/downloads/caorushizi/mediago/total">
<img alt="GitHub Downloads (all assets, latest release)" src="https://img.shields.io/github/downloads/caorushizi/mediago/latest/total">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/caorushizi/mediago">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/caorushizi/mediago">
<br>
<br>
<a href="https://trendshift.io/repositories/11083" target="_blank">
<img src="https://trendshift.io/api/badge/repositories/11083" alt="caorushizi%2Fmediago | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
</a>
<hr />
</div>
## Intro
本プロジェクトはm3u8ビデオ抽出ツール、ストリーミングダウンロード、m3u8ダウンロードをサポートしています。
- **✅&nbsp; パケットキャプチャ不要**: ソフトウェアに内蔵されたブラウザを使用して、ウェブページ内のビデオリソースを簡単に検出し、検出したリソースリストからダウンロードしたいリソースを選択することで、シンプルかつ迅速にダウンロードできます。
- **📱&nbsp; モバイル再生**: PCとモバイルデバイス間で簡単にシームレスに切り替えが可能で、ダウンロードが完了した後はスマートフォンでビデオを視聴できます。
- **⚡️&nbsp; バッチダウンロード**: 複数のビデオやライブストリームリソースを同時にダウンロードでき、高速帯域幅を無駄にしません。
- **🎉&nbsp; Dockerデプロイメントサポート**: WebエンドをDockerでデプロイすることができ、簡単かつ便利です。
## Quickstart
コードを実行するには、Node.jsとpnpmが必要です。Node.jsは公式ウェブサイトからダウンロードしてインストールし、pnpmは`npm i -g pnpm`コマンドでインストールできます。
## コードの実行
```shell
# コードのダウンロードです
git clone https://github.com/caorushizi/mediago.git
# インストール依存症です
pnpm i
# 開発環境です
pnpm dev
# 梱包して運行します
pnpm release
# dockerミラーリングを構築します
docker buildx build -t caorushizi/mediago:latest .
# docker启动
docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago
```
## Releases
### v3.0.0 (2024.10.7 発売)
#### ソフトウェアダウンロード
- [【mediago】 windows(インストーラー版) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-win32-x64-3.0.0.exe)
- [【mediago】 windows(ポータブル版) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-portable-win32-x64-3.0.0.exe)
- [【mediago】 macos arm64Appleチップ) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-darwin-arm64-3.0.0.dmg)
- [【mediago】 macos x64Intelチップ) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-darwin-x64-3.0.0.dmg)
- [【mediago】 linux v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-linux-amd64-3.0.0.deb)
- 【mediago】 docker v3.0 `docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago:v3.0.0`
#### 国内ダウンロード
- [【mediago】 windows(インストーラー版) v3.0.0](https://static.ziying.site/mediago/mediago-setup-win32-x64-3.0.0.exe)
- [【mediago】 windows(ポータブル版) v3.0.0](https://static.ziying.site/mediago/mediago-portable-win32-x64-3.0.0.exe)
- [【mediago】 macos arm64Appleチップ) v3.0.0](https://static.ziying.site/mediago/mediago-setup-darwin-arm64-3.0.0.dmg)
- [【mediago】 macos x64Intelチップ) v3.0.0](https://static.ziying.site/mediago/mediago-setup-darwin-x64-3.0.0-beta.5.dmg)
- [【mediago】 linux v3.0.0](https://static.ziying.site/mediago/mediago-setup-linux-amd64-3.0.0.deb)
- 【mediago】 docker v3.0 `docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago:v3.0.0`
### docker 宝塔パネルワンクリックデプロイ(推奨)
1. 宝塔パネルをインストールし、[宝塔パネル](https://www.bt.cn/new/download.html?r=dk_mediago) の公式サイトから正式版のスクリプトを選択してインストールします。
2. インストール後、宝塔パネルにログインし、メニューから `Docker` をクリックします。初めてアクセスすると、`Docker` サービスをインストールするように指示されるので、「今すぐインストール」をクリックし、指示に従ってインストールを完了します。
3. インストールが完了したら、アプリストアで「MediaGo」を見つけ、インストールをクリックし、ドメイン名などの基本情報を設定してインストールを完了します。
### ソフトウェアスクリーンショット
![ホームページ](https://static.ziying.site/images/home.png)
### 重要な更新
- Web端のdockerデプロイをサポート
- デスクトップ端のUIを更新
### 更新ログ
- デスクトップ端のUIを更新
- Web端のdockerデプロイをサポート
- 新たにビデオ再生機能を追加、デスクトップとモバイル端両方で再生可能
- Macでの画面表示ができない問題を修正
- バッチダウンロードのインタラクションを最適化
- Windowsのポータブル版(インストール不要)を追加
- ダウンロードリストの最適化、ページ内の複数のビデオリソースを嗅ぎ取る機能を追加
- 手動でお気に入りリストのインポートとエクスポートをサポート
- ホームページのダウンロードリストエクスポートをサポート
- 「新規ダウンロード」フォームのインタラクションロジックを最適化
- UrlSchemeでアプリを開き、ダウンロードタスクを追加する機能をサポート
- バグの修正とユーザー体験の向上
## ソフトウェアスクリーンショット
![ホームページ](https://static.ziying.site/images/home.png)
![ホームページ(ダークモード)](https://static.ziying.site/images/home-dark.png)
![設定ページ](https://static.ziying.site/images/settings.png)
![リソース抽出](https://static.ziying.site/images/browser.png)
## 技術スタック
- react <https://react.dev/>
- electron <https://www.electronjs.org>
- koa <https://koajs.com>
- vite <https://cn.vitejs.dev>
- antd <https://ant.design>
- tailwindcss <https://tailwindcss.com>
- shadcn <https://ui.shadcn.com/>
- inversify <https://inversify.io>
- typeorm <https://typeorm.io>
## 感謝
- N_m2u8DL-CLI は <https://github.com/nilaoda/N_m3u8DL-CLI> から来ています
- N_m3u8DL-RE は <https://github.com/nilaoda/N_m3u8DL-RE> から来ています
- mediago は <https://github.com/caorushizi/hls-downloader> から来ています
+105 -32
View File
@@ -1,64 +1,137 @@
# media-downloader
<div align="center">
<h1>MediaGo</h1>
<a href="https://downloader.caorushizi.cn/guides.html?form=github">快速开始</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://downloader.caorushizi.cn?form=github">官网</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://downloader.caorushizi.cn/documents.html?form=github">文档</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://github.com/caorushizi/mediago/discussions">Discussions</a>
<br>
m3u8 视频在线提取工具 流媒体下载 m3u8 下载 桌面客户端 windows mac。
可以直接在线获取 m3u8 链接地址,无需使用使用网络抓包,无需安装浏览器插件,可以直接带出请求标头……详情请参考[使用帮助](https://downloader.caorushizi.cn/guides.html?form=github)
<a href="https://github.com/caorushizi/mediago/blob/master/README.en.md">English</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://github.com/caorushizi/mediago/blob/master/README.jp.md">日本語</a>
<br>
## 上手指南
<img alt="GitHub Downloads (all assets, all releases)" src="https://img.shields.io/github/downloads/caorushizi/mediago/total">
<img alt="GitHub Downloads (all assets, latest release)" src="https://img.shields.io/github/downloads/caorushizi/mediago/latest/total">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/caorushizi/mediago">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/caorushizi/mediago">
<br>
以下指南将帮助你在本地机器上安装和运行该项目,进行开发和测试。关于如何将该项目部署到在线环境,请参考部署小节。
<a href="https://trendshift.io/repositories/11083" target="_blank">
<img src="https://trendshift.io/api/badge/repositories/11083" alt="caorushizi%2Fmediago | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
</a>
## 安装要求
<hr />
</div>
## Intro
本项目支持 m3u8 视频在线提取工具 流媒体下载 m3u8 下载。
- **✅&nbsp; 无需抓包**: 使用软件自带浏览器可以轻松嗅探网页中的视频资源,通过嗅探到的资源列表选择自己想要下载的资源,简单快速。
- **📱&nbsp; 移动播放**: 可以轻松无缝的在 PC 和移动设备之前切换,下载完成后即可使用手机观看视频。
- **⚡️&nbsp; 批量下载**: 支持同时下载多个视频和直播资源,高速带宽不闲置。
- **🎉&nbsp; 支持 docker 部署** 支持 docker 部署 web 端,方便快捷。
## Quickstart
运行代码需要 node 和 pnpm,node 需要在官网下载安装,pnpm 可以通过`npm i -g pnpm`安装。
## 运行代码
安装依赖 `pnpm i`
```shell
# 代码下载
git clone https://github.com/caorushizi/mediago.git
开发环境 `pnpm run dev`
# 安装依赖
pnpm i
打包运行 `pnpm run release`
# 开发环境
pnpm dev
## 下载链接
# 打包运行
pnpm release
**v2.0.12023.7.1 发布)**
# 构建 docker 镜像
docker buildx build -t caorushizi/mediago:latest .
- [windows media-downloader v2.0.1](https://github.com/caorushizi/m3u8-downloader/releases/download/v2.0.1/media-downloader-setup-2.0.1.exe)
- [macos media-downloader v2.0.1](https://github.com/caorushizi/m3u8-downloader/releases/download/v2.0.1/media-downloader-setup-2.0.1.dmg)
# docker 启动
docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago
**更新日志**
```
- 暗黑模式
- 更多下载配置
- 支持请求标头自动带入
- 支持开启广告过滤
- 支持开启沉浸式嗅探
- 支持切换手机和 PC 模式
- 支持修改同时下载数量
- 修复了一些 bug
## Releases
**v1.1.52022.2.5 发布)**
### v3.0.0 (2024.10.7 发布)
- [windows media-downloader v1.1.5](https://github.com/caorushizi/m3u8-downloader/releases/download/1.1.5/media-downloader-setup-1.1.4.exe)
#### 软件下载
**更新日志**
- [【mediago】 windows(安装版) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-win32-x64-3.0.0.exe)
- [【mediago】 windows(便携版) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-portable-win32-x64-3.0.0.exe)
- [【mediago】 macos arm64apple 芯片) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-darwin-arm64-3.0.0.dmg)
- [【mediago】 macos x64intel 芯片) v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-darwin-x64-3.0.0.dmg)
- [【mediago】 linux v3.0.0](https://github.com/caorushizi/mediago/releases/download/v3.0.0/mediago-setup-linux-amd64-3.0.0.deb)
- 【mediago】 docker v3.0 `docker run -d --name mediago -p 8899:8899 -v /root/mediago:/root/mediago registry.cn-beijing.aliyuncs.com/caorushizi/mediago:v3.0.0`
### docker 宝塔面板一键部署(推荐)
1. 安装宝塔面板,前往 [宝塔面板](https://www.bt.cn/new/download.html?r=dk_mediago) 官网,选择正式版的脚本下载安装
2. 安装后登录宝塔面板,在菜单栏中点击 `Docker`,首次进入会提示安装`Docker`服务,点击立即安装,按提示完成安装
3. 安装完成后在应用商店中找到`MediaGo`,点击安装,配置域名等基本信息即可完成安装
### 软件截图
![首页](https://static.ziying.site/images/home.png)
### 重要更新
- 支持 docker 部署 web 端
- 更新桌面端 UI
### 更新日志
- 更新桌面端 UI
- 支持 docker 部署 web 端
- 新增视频播放,支持桌面端和移动端播放
- 修复 mac 打开无法展示界面的问题
- 优化了批量下载的交互
- 添加了 windows 的便携版(免安装哦)
- 优化了下载列表,支持页面中多个视频的嗅探
- 支持收藏列表手动导入导出
- 支持首页下载列表导出
- 优化了【新建下载】表单的交互逻辑
- 支持 UrlScheme 打开应用,并添加下载任务
- 修复了一些 bug 并提升用户体验
## 软件截图
![首页](https://raw.githubusercontent.com/caorushizi/m3u8-downloader/master/screenshot/home-page.png)
![首页](https://static.ziying.site/images/home.png)
![设置页面](https://raw.githubusercontent.com/caorushizi/m3u8-downloader/master/screenshot/setting-page.png)
![首页-dark](https://static.ziying.site/images/home-dark.png)
![资源提取](https://raw.githubusercontent.com/caorushizi/m3u8-downloader/master/screenshot/browser-page.png)
![设置页面](https://static.ziying.site/images/settings.png)
![资源提取](https://static.ziying.site/images/browser.png)
## 技术栈
- react <https://react.dev/>
- electron <https://www.electronjs.org>
- koa <https://koajs.com>
- vite <https://cn.vitejs.dev>
- antd <https://ant.design>
- electron <https://www.electronjs.org>
- tailwindcss <https://tailwindcss.com>
- shadcn <https://ui.shadcn.com/>
- inversify <https://inversify.io>
- typeorm <https://typeorm.io>
## 鸣谢
N_m3u8DL-CLI 来自于 <https://github.com/nilaoda/N_m3u8DL-CLI>
mediago 来自于 <https://github.com/caorushizi/mediago>
- N_m2u8DL-CLI 来自于 <https://github.com/nilaoda/N_m3u8DL-CLI>
- N_m3u8DL-RE 来自于 <https://github.com/nilaoda/N_m3u8DL-RE>
- mediago 来自于 <https://github.com/caorushizi/hls-downloader>
+100
View File
@@ -0,0 +1,100 @@
export default {
extends: ["@commitlint/config-conventional"], // extends can be nested
parserPreset: "conventional-changelog-conventionalcommits",
prompt: {
settings: {},
messages: {
skip: ":skip",
max: "upper %d chars",
min: "%d chars at least",
emptyWarning: "can not be empty",
upperLimitWarning: "over limit",
lowerLimitWarning: "below limit",
},
types: [
{ value: "feat", name: "feat: ✨ A new feature", emoji: "✨ " },
{ value: "fix", name: "fix: 🐛 A bug fix", emoji: "🐛 " },
{
value: "docs",
name: "docs: 📝 Documentation only changes",
emoji: "📝 ",
},
{
value: "style",
name: "style: 💄 Changes that do not affect the meaning of the code",
emoji: "💄 ",
},
{
value: "refactor",
name: "refactor: 📦️ A code change that neither fixes a bug nor adds a feature",
emoji: "📦️ ",
},
{
value: "perf",
name: "perf: 🚀 A code change that improves performance",
emoji: "🚀 ",
},
{
value: "test",
name: "test: 🚨 Adding missing tests or correcting existing tests",
emoji: "🚨 ",
},
{
value: "build",
name: "build: 🛠 Changes that affect the build system or external dependencies",
emoji: "🛠 ",
},
{
value: "ci",
name: "ci: 🎡 Changes to our CI configuration files and scripts",
emoji: "🎡 ",
},
{
value: "chore",
name: "chore: 🔨 Other changes that don't modify src or test files",
emoji: "🔨 ",
},
{
value: "revert",
name: "revert: ⏪️ Reverts a previous commit",
emoji: ":rewind:",
},
],
useEmoji: true,
confirmColorize: true,
emojiAlign: "center",
questions: {
scope: {
description:
"What is the scope of this change (e.g. component or file name)",
},
subject: {
description:
"Write a short, imperative tense description of the change",
},
body: {
description: "Provide a longer description of the change",
},
isBreaking: {
description: "Are there any breaking changes?",
},
breakingBody: {
description:
"A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself",
},
breaking: {
description: "Describe the breaking changes",
},
isIssueAffected: {
description: "Does this change affect any open issues?",
},
issuesBody: {
description:
"If issues are closed, the commit requires a body. Please enter a longer description of the commit itself",
},
issues: {
description: 'Add issue references (e.g. "fix #123", "re #123".)',
},
},
},
};
+23
View File
@@ -0,0 +1,23 @@
{
"import": [
"@cspell/dict-lorem-ipsum/cspell-ext.json"
],
"caseSensitive": false,
"dictionaries": [
"custom-words"
],
"dictionaryDefinitions": [
{
"name": "custom-words",
"path": "./.cspell/custom-words.txt",
"addWords": true
}
],
"ignorePaths": [
"**/node_modules/**",
"**/dist/**",
"**/lib/**",
"**/docs/**",
"**/stats.html"
]
}
-2
View File
@@ -1,2 +0,0 @@
.vitepress/dist
.vitepress/cache
-63
View File
@@ -1,63 +0,0 @@
import { HeadConfig } from "vitepress";
import { defineConfig } from "vitepress";
const isDev = process.env.NODE_ENV === "development";
const head: HeadConfig[] = [
["link", { rel: "shortcut icon", href: "/favicon.svg" }],
];
if (!isDev) {
head.push([
"script",
{},
`var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?eefcbd14f0323044aa0ca678cd278381";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();`,
]);
}
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "media-downloader",
description: "简单易用,快速下载",
lastUpdated: true,
head,
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: "Home", link: "/" },
{ text: "教程", link: "/guides" },
],
sidebar: [
{
text: "开始",
items: [
{ text: "快速开始", link: "/guides" },
{ text: "使用说明", link: "/documents" },
],
},
{
text: "其他",
items: [
{ text: "旧版本", link: "/history" },
{ text: "意见收集", link: "/proposal" },
{ text: "支持列表", link: "/list" },
],
},
],
socialLinks: [
{ icon: "github", link: "https://github.com/caorushizi/m3u8-downloader" },
],
footer: {
message: '<a href="https://beian.miit.gov.cn">豫ICP备20012967号-2</a>',
copyright: "Copyright © 2019-present caorushizi",
},
},
});
@@ -1,50 +0,0 @@
<script setup lang="ts">
import { onMounted, watch, ref, watchEffect } from "vue";
import { init, WalineInstance } from "@waline/client";
import "@waline/client/waline.css";
import { useData, useRoute } from "vitepress";
const route = useRoute();
const { isDark } = useData();
const commentsRef = ref<WalineInstance | null>(null);
watchEffect(() => {
commentsRef.value?.update({
dark: isDark.value,
});
});
watch(
() => route.path,
() => {
commentsRef.value?.destroy();
initWaline();
}
);
function initWaline() {
commentsRef.value = init({
el: "#waline",
serverURL: "https://comments.ziying.site",
dark: isDark.value,
lang: "zh-CN",
reaction: true,
pageview: true,
});
}
onMounted(() => {
initWaline();
});
</script>
<template>
<div id="waline">hello world</div>
</template>
<style scoped>
#waline {
margin-top: 20px;
}
</style>
-13
View File
@@ -1,13 +0,0 @@
import { h } from "vue";
import Theme from "vitepress/theme";
import "./style/var.css";
import Comments from "./components/Comments.vue";
export default {
...Theme,
Layout() {
return h(Theme.Layout, null, {
"doc-after": () => h(Comments),
});
},
};
-30
View File
@@ -1,30 +0,0 @@
:root {
/* 标题 */
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(
135deg,
#5e9ef3 10%,
#2a82f6 100%
);
/* 图标背景 */
--vp-home-hero-image-background-image: linear-gradient(
135deg,
#5e9ef3 10%,
#2a82f6 100%
);
--vp-home-hero-image-filter: blur(150px);
/* brand按钮 */
--vp-button-brand-border: #5e9ef3;
--vp-button-brand-text: #f2f7fd;
--vp-button-brand-bg: #2a82f6;
--vp-button-brand-hover-border: #5e9ef3;
--vp-button-brand-hover-text: #fff;
--vp-button-brand-hover-bg: #2a82f6;
--vp-button-brand-active-border: #f6ceec;
--vp-c-brand: #2a82f6;
}
-83
View File
@@ -1,83 +0,0 @@
---
layout: doc
outline: deep
---
# 使用说明
这个页面主要讲解的是设置页面的参数的含义
![step 1](./images/documents-step1.png)
## 基础设置
::: tip
下载器全局设置
:::
1. 选择文件夹: 视频下载的路径
2. 下载器主题: 支持浅色和深色模式
3. 在新窗口中打开浏览器: 开启了之后浏览器页面会独立出一个窗口。
![step 1](./images/documents-step2.png)
4. 下载完成提示: 开启之后下载完成会出现系统提示
## 浏览器设置
::: tip
浏览器窗口相关的设置
:::
1. 代理设置: 填写自己的代理地址
2. 代理开关: 打开开关后浏览器默认会走填写的代理地址,如果代理地址这个开关是打不开的
3. 开启广告过滤: 打开开关后会过滤页面中的广告
4. 以手机模式进入: 打开后会将浏览器伪装成手机浏览器,请求移动端的站点(左侧是开启手机模式的截图)
![step 2](./images/documents-step3.png)
5. 使用浏览器插件
- 打开状态: 从浏览器中嗅探到的资源不会自动添加到下载列表,需要手动点击页面下方的下载的链接来添加视频到下载列表 **(后面会有很强大的功能哦)**
![step 3](./images/documents-step4.png)
- 关闭状态: 浏览器中嗅探到的资源会自动添加到下载列表
## 下载设置
::: tip
和下载相关的设置
:::
1. 下载完成删除分片: 开启后下载完成后会将分片文件删除
2. 最大同时下载数量: 最多同时可以下载多少视频文件,目前最大是 10,最小是 1
3. 更多操作
- 配置文件目录: 软件数据库路径、日志等等路径
- 可执行文件目录: 下载器二进制文件的路径
- 本地存储路径: 下载视频的本地路径
4. 当前版本: 当前软件版本信息
## 其他问题
**Q: 关于直播视频的下载**
A: 软件支持直播下载,软件目前没有好的办法区分直播流,所以将所有的下载控制台开启。用户自行分辨下载数据源
**Q: 关于 MacOS 版本**
A: 目前 MacOS 版本属于非稳定版本,2023 年 5 月发布。需要在 Mac 的安全设置中打开来自身份不明开发者的 Mac App
![QA1](./images/documents-qa1.png)
**Q: 关于旧版本**
A: 1.1.5 版本确实发布了很长时间,经过大量用户的验证,比较稳定。所以想要使用旧版软件的话请访问[此链接](/history.html)
**Q: 关于 Win7 用户**
A: v2.0.0 之后的版本已经放弃不支持 Win7 如果需要在 win7 上面使用同样需要下载 1.1.5 版本
-96
View File
@@ -1,96 +0,0 @@
---
layout: doc
outline: deep
---
# 快速开始
这篇文章是软件的简单说明,可以快速上手使用本本软件。
::: tip
我建了一个 QQ 群,方便大家一起沟通交流: 574209001
:::
## 下载安装
**v2.0.12023.7.1 发布)**
- [windows media-downloader v2.0.1](https://github.com/caorushizi/m3u8-downloader/releases/download/v2.0.1/media-downloader-setup-2.0.1.exe)
- [macos media-downloader v2.0.1](https://github.com/caorushizi/m3u8-downloader/releases/download/v2.0.1/media-downloader-setup-2.0.1.dmg)
**更新日志**
- 暗黑模式
- 更多下载配置
- 支持请求标头自动带入
- 支持开启广告过滤
- 支持开启沉浸式嗅探
- 支持切换手机和 PC 模式
- 支持修改同时下载数量
- 修复了一些 bug
**v1.1.52022.2.5 发布)**
- [windows media-downloader v1.1.5](https://github.com/caorushizi/m3u8-downloader/releases/download/1.1.5/media-downloader-setup-1.1.4.exe)
**更新日志**
- 支持视频下载
## 操作说明
### 视频自动嗅探
1. 选择【资源提取】
![step 1](./images/guides-step1.png)
2. 进入视频的网址
![step 2](./images/guides-step2.png)
3. 开始下载,即可下载视频
![step 3](./images/guides-step3.png)
### 手动下载
1. 点击页面右上角的【新建下载】
![step 1](./images/guides-step4.png)
2. 在新建下载弹窗中填入【视频名称】和【m3u8 地址】即可
![step 2](./images/guides-step5.png)
3. 在列表中点击下载,即可下载视频
![step 3](./images/guides-step3.png)
## 附加功能
1. 下载完成后可以在下载列表中点击转换音频按钮将视频转换为音频
![step 1](./images/addition-step1.png)
2. 下载完成后播放视频
- PC 播放
![step 2](./images/addition-step2.png)
- 移动端播放
![step 3](./images/addition-step3.png)
3. 批量下载
![step 3](./images/addition-step4.png)
## 开始你的视频下载吧
是不是很简单,快去下载你的视频吧
::: warning
本软件仅可用于学习交流
:::
-21
View File
@@ -1,21 +0,0 @@
---
layout: doc
outline: deep
---
# 旧版本
::: info
这里是旧版本的永久链接,如果有需求的话,可以在这里下载
**这个链接的软件不会自动升级, 可放心使用**
:::
**v1.1.52022.2.5 发布)**
- [windows media-downloader v1.1.5](https://github.com/caorushizi/m3u8-downloader/releases/download/1.1.5/media-downloader-setup-1.1.4.exe)
- ~~macos media-downloader v1.1.5 无~~
**更新日志**
- 支持视频下载
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

-30
View File
@@ -1,30 +0,0 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "在线视频下载"
text: "简单易用,快速下载"
tagline: 简单易学,无需抓包,不需要安装插件
image:
src: /home.png
alt: home
actions:
- theme: brand
text: 快速开始
link: /guides
- theme: alt
text: 使用说明
link: /documents
features:
- icon: ⏩
title: 无需抓包
details: 使用软件自带浏览器可以轻松嗅探网页中的视频资源,通过嗅探到的资源列表选择自己想要下载的资源,简单快速。
- icon: 📱
title: 移动播放
details: 可以轻松无缝的在PC和移动设备之前切换,下载完成后即可使用手机观看视频。
- icon: ⚡️
title: 支持批量下载
details: 支持同时最多下载10个视频和直播资源,高速带宽不闲置。
---
-22
View File
@@ -1,22 +0,0 @@
---
layout: doc
outline: deep
---
# 支持列表
::: tip
大家有什么网站想要支持的在这里提
:::
**模板**
---
- 网站首页: xxx
- 视频(直播)列表页: xxx
- 视频(直播)页: xxx
---
支持完成后我会在评论区回复
-16
View File
@@ -1,16 +0,0 @@
---
layout: doc
outline: deep
---
# 意见收集
::: info
这里手机大家使用软件的问题,或者意见建议
:::
如果软件报错,需要描述清楚在什么网站下载什么视频的时候报错
如果是建议请描述清楚你的需求
如果是意见请尽量提出来,我会尽量满足大家的需求
-40
View File
@@ -1,40 +0,0 @@
<svg t="1686326276609" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="6962" xmlns:xlink="http://www.w3.org/1999/xlink"
width="200" height="200">
<path
d="M110.933333 42.666667h716.8A68.266667 68.266667 0 0 1 896 110.933333v802.133334a68.266667 68.266667 0 0 1-68.266667 68.266666H110.933333A68.266667 68.266667 0 0 1 42.666667 913.066667V110.933333A68.266667 68.266667 0 0 1 110.933333 42.666667z"
fill="#111314" fill-opacity=".72" p-id="6963"></path>
<path
d="M853.333333 42.666667h85.333334a68.266667 68.266667 0 0 1 68.266666 68.266666v802.133334A68.266667 68.266667 0 0 1 938.666667 981.333333h-85.333334a68.266667 68.266667 0 0 0 68.266667-68.266666V110.933333A68.266667 68.266667 0 0 0 853.333333 42.666667z"
fill="#CACBCC" p-id="6964"></path>
<path
d="M162.133333 128h614.4a34.133333 34.133333 0 0 1 34.133334 34.133333v699.733334a34.133333 34.133333 0 0 1-34.133334 34.133333H162.133333a34.133333 34.133333 0 0 1-34.133333-34.133333V162.133333a34.133333 34.133333 0 0 1 34.133333-34.133333z"
fill="#FFFFFF" p-id="6965"></path>
<path
d="M187.733333 170.666667h563.2c9.386667 0 17.066667 7.68 17.066667 17.066666v221.866667a17.066667 17.066667 0 0 1-17.066667 17.066667H187.733333a17.066667 17.066667 0 0 1-17.066666-17.066667V187.733333c0-9.386667 7.68-17.066667 17.066666-17.066666z"
fill="#EDEEF0" p-id="6966"></path>
<path
d="M256 298.666667m17.066667 0l136.533333 0q17.066667 0 17.066667 17.066666l0 136.533334q0 17.066667-17.066667 17.066666l-136.533333 0q-17.066667 0-17.066667-17.066666l0-136.533334q0-17.066667 17.066667-17.066666Z"
fill="#FFC13C" p-id="6967"></path>
<path
d="M341.333333 392.533333a34.133333 34.133333 0 1 1 0-68.266666 34.133333 34.133333 0 0 1 0 68.266666z m65.109334 56.192H276.224C276.224 426.666667 276.224 401.066667 341.333333 401.066667s65.109333 25.6 65.109334 47.658666z"
fill="#FFFFFF" p-id="6968"></path>
<path
d="M469.333333 341.333333m17.066667 0l136.533333 0q17.066667 0 17.066667 17.066667l0 8.533333q0 17.066667-17.066667 17.066667l-136.533333 0q-17.066667 0-17.066667-17.066667l0-8.533333q0-17.066667 17.066667-17.066667Z"
fill="#5BADFF" p-id="6969"></path>
<path
d="M512 554.666667m17.066667 0l179.2 0q17.066667 0 17.066666 17.066666l0 51.2q0 17.066667-17.066666 17.066667l-179.2 0q-17.066667 0-17.066667-17.066667l0-51.2q0-17.066667 17.066667-17.066666Z"
fill="#EDEEF0" p-id="6970"></path>
<path
d="M512 682.666667m17.066667 0l179.2 0q17.066667 0 17.066666 17.066666l0 51.2q0 17.066667-17.066666 17.066667l-179.2 0q-17.066667 0-17.066667-17.066667l0-51.2q0-17.066667 17.066667-17.066666Z"
fill="#EDEEF0" p-id="6971"></path>
<path
d="M213.333333 554.666667m17.066667 0l221.866667 0q17.066667 0 17.066666 17.066666l0 8.533334q0 17.066667-17.066666 17.066666l-221.866667 0q-17.066667 0-17.066667-17.066666l0-8.533334q0-17.066667 17.066667-17.066666Z"
fill="#EDEEF0" p-id="6972"></path>
<path
d="M213.333333 640m17.066667 0l221.866667 0q17.066667 0 17.066666 17.066667l0 8.533333q0 17.066667-17.066666 17.066667l-221.866667 0q-17.066667 0-17.066667-17.066667l0-8.533333q0-17.066667 17.066667-17.066667Z"
fill="#EDEEF0" p-id="6973"></path>
<path
d="M213.333333 725.333333m17.066667 0l221.866667 0q17.066667 0 17.066666 17.066667l0 8.533333q0 17.066667-17.066666 17.066667l-221.866667 0q-17.066667 0-17.066667-17.066667l0-8.533333q0-17.066667 17.066667-17.066667Z"
fill="#EDEEF0" p-id="6974"></path>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

+14
View File
@@ -0,0 +1,14 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
export default [
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-explicit-any": "warn",
},
},
];
+49 -17
View File
@@ -1,31 +1,63 @@
{
"name": "electron-template",
"name": "mediago",
"version": "0.1.0",
"description": "electron-template",
"main": "index.js",
"description": "mediago",
"author": "caorushizi",
"homepage": "https://downloader.caorushizi.cn/",
"private": true,
"type": "module",
"scripts": {
"dev": "pnpm run build:mobile && pnpm --parallel -F \"./packages/*\" run dev",
"build": "pnpm run build:mobile && pnpm run build:main && pnpm run build:renderer",
"build:mobile": "pnpm -F mobile run build",
"dev": "tsx scripts/dev.ts && pnpm --parallel -F \"./packages/*\" run dev",
"dev:web": "pnpm --parallel -F \"./packages/*\" run dev:web",
"build": "tsx scripts/build.ts",
"build:plugin": "pnpm -F plugin run build",
"build:main": "pnpm -F main run build",
"build:web": "pnpm -F renderer run build:web",
"build:backend": "pnpm -F backend run build",
"build:renderer": "pnpm -F renderer run build",
"pack": "pnpm -F media-downloader run pack",
"build:mobile": "pnpm -F mobile run build",
"build:web-release": "tsx scripts/web.ts",
"rebuild:web": "pnpm -F backend rebuild",
"rebuild:electron": "pnpm -F main run rebuild",
"beta": "pnpm run build && pnpm -F mediago run pack",
"release": "pnpm run build && pnpm -F main run release",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
"types": "pnpm -F main run types",
"types:renderer": "pnpm -F renderer run types",
"types:watch": "pnpm -F main run types:watch",
"prepare": "husky",
"commit": "git-cz",
"commitlint": "commitlint --edit",
"spellcheck": "cspell \"packages/**/src/**/*.{ts,tsx}\"",
"lint-staged": "pnpm --recursive -F \"./packages/*\" run lint-staged"
},
"keywords": [],
"author": "",
"license": "MIT",
"pnpm": {
"patchedDependencies": {
"@cliqz/adblocker@1.26.6": "patches/@cliqz__adblocker@1.26.6.patch"
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
"devDependencies": {
"@waline/client": "^2.15.5",
"vitepress": "1.0.0-beta.3",
"vue": "^3.3.4"
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@commitlint/core": "^19.3.0",
"@commitlint/cz-commitlint": "^19.2.0",
"@commitlint/format": "^19.3.0",
"@eslint/js": "^8.57.0",
"commitizen": "^4.3.0",
"cross-env": "^7.0.3",
"cspell": "^8.8.3",
"cz-git": "^1.9.2",
"eslint": "^8.57.0",
"globals": "^15.3.0",
"husky": "^9.0.11",
"tsx": "^4.11.0",
"typescript-eslint": "^7.10.0",
"zx": "^8.1.1"
},
"pnpm": {
"patchedDependencies": {
"@ghostery/adblocker@2.3.1": "patches/@ghostery__adblocker@2.3.1.patch"
}
}
}
+2
View File
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
+9
View File
@@ -0,0 +1,9 @@
.bin
node_modules
build
dist
bin/Logs
release
types
log
bin
+1
View File
@@ -0,0 +1 @@
types/
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
# backend
+16
View File
@@ -0,0 +1,16 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
export default [
{
languageOptions: { globals: globals.node },
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-explicit-any": "warn",
},
},
];
+1
View File
@@ -0,0 +1 @@
export { dev, build } from "./scripts";
+5
View File
@@ -0,0 +1,5 @@
{
"watch": ["dist"],
"ext": "js",
"exec": "npx cross-env NODE_ENV=development node dist/server/index.js"
}
+83
View File
@@ -0,0 +1,83 @@
{
"name": "backend",
"version": "0.1.0",
"description": "在线视频下载器",
"type": "module",
"main": "dist/index.js",
"scripts": {
"start": "nodemon",
"dev:web": "cross-env NODE_ENV=development gulp dev",
"build": "cross-env NODE_ENV=production gulp build",
"types": "tsc",
"types:watch": "tsc -w",
"lint-staged": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": "eslint"
},
"author": "",
"license": "MIT",
"devDependencies": {
"@eslint/js": "^8.57.0",
"@types/cors": "^2.8.17",
"@types/cross-spawn": "^6.0.6",
"@types/express": "^4.17.21",
"@types/fs-extra": "^11.0.4",
"@types/glob": "^8.1.0",
"@types/gulp": "^4.0.17",
"@types/koa": "^2.15.0",
"@types/koa-bodyparser": "^4.3.12",
"@types/koa-send": "^4.1.6",
"@types/koa-static": "^4.0.4",
"@types/koa__cors": "^5.0.0",
"@types/koa__router": "^12.0.4",
"@types/lodash": "^4.17.4",
"@types/mime-types": "^2.1.4",
"@types/node": "^20.12.12",
"@types/semver": "^7.5.8",
"@types/serve-handler": "^6.1.4",
"@types/undertaker": "^1.2.11",
"consola": "^3.2.3",
"cross-env": "^7.0.3",
"cross-spawn": "^7.0.3",
"del": "^7.1.0",
"dotenv": "^16.4.5",
"esbuild": "0.21.4",
"esbuild-register": "^3.5.0",
"eslint": "^8.57.0",
"glob": "^10.4.1",
"globals": "^15.3.0",
"gulp": "^5.0.0",
"lint-staged": "^15.2.5",
"nodemon": "^3.1.4",
"semver": "^7.6.2",
"typescript": "^5.4.5",
"typescript-eslint": "^7.10.0"
},
"dependencies": {
"@koa/cors": "^5.0.0",
"@koa/router": "^12.0.1",
"axios": "^1.7.2",
"better-sqlite3": "^9.3.0",
"cheerio": "1.0.0-rc.12",
"dayjs": "^1.11.11",
"execa": "^9.1.0",
"fs-extra": "^11.2.0",
"i18next": "^23.11.5",
"inversify": "^6.0.2",
"koa": "^2.15.3",
"koa-bodyparser": "^4.4.1",
"koa-send": "^5.0.1",
"koa-static": "^5.0.0",
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
"nanoid": "^5.0.7",
"node-pty": "^1.0.0",
"reflect-metadata": "^0.2.2",
"socket.io": "^4.8.0",
"strip-ansi": "^7.1.0",
"typeorm": "0.3.20",
"winston": "^3.14.2"
},
"keywords": []
}
+30
View File
@@ -0,0 +1,30 @@
import { Env, isDev, mainResolve } from "./utils";
import esbuild from "esbuild";
export function buildOptions(): esbuild.BuildOptions {
const getDefine = (): Record<string, string> => {
const vars: Record<string, string> = {
"process.env.NODE_ENV": isDev ? '"development"' : '"production"',
};
if (isDev) {
vars.__bin__ = `"${mainResolve("bin").replace(/\\/g, "\\\\")}"`;
Object.assign(vars, Env.getInstance().loadDotEnvDefined());
}
return vars;
};
return {
entryPoints: [mainResolve("src/index.ts")],
bundle: true,
sourcemap: process.env.NODE_ENV === "development",
define: getDefine(),
outdir: mainResolve("dist/server"),
loader: { ".png": "file" },
minify: process.env.NODE_ENV === "production",
packages: "external",
format: "esm",
target: ["node20"],
platform: "node",
};
}
+86
View File
@@ -0,0 +1,86 @@
import { deleteSync } from "del";
import { mainResolve, Env, isDev } from "./utils";
import gulp from "gulp";
import * as esbuild from "esbuild";
import consola from "consola";
import { buildOptions } from "./config";
import fs from "fs";
import spawn from "cross-spawn";
const env = Env.getInstance();
env.loadDotEnvRuntime();
async function clean() {
return deleteSync([mainResolve("dist/server")]);
}
async function buildClean() {
return deleteSync([mainResolve("dist")]);
}
async function copyBin() {
const source = mainResolve(
"../main/bin",
isDev ? process.platform : "linux",
process.arch,
);
const target = mainResolve("dist/server/bin");
fs.cpSync(source, target, {
recursive: true,
filter: (src) => {
if (!isDev && src.endsWith("ffmpeg")) {
return false;
}
return true;
},
});
}
const copy = gulp.parallel(copyBin);
async function watchTask() {
const main = await esbuild.context(buildOptions());
await main.rebuild();
const watcher = gulp.watch(["./src"]);
watcher
.on("change", async () => {
await main.rebuild();
})
.on("error", (error: any) => {
consola.error(error);
});
return Promise.resolve();
}
async function startNodemon() {
const nodemon = spawn("npm", ["start"], {
stdio: "pipe",
});
nodemon.stdout?.on("data", (data) => {
consola.log(data.toString());
});
// Listen for stderr data events
nodemon.stderr?.on("data", (data) => {
consola.error(`stderr: ${data.toString()}`);
});
// Listens for closing events of the child process
nodemon.on("close", (code) => {
consola.log(`子进程退出,退出码 ${code}`);
});
return Promise.resolve();
}
async function buildTask() {
await esbuild.build(buildOptions());
}
// Development environment
export const dev = gulp.series(clean, copy, watchTask, startNodemon);
// Build packaging
export const build = gulp.series(buildClean, copy, buildTask);
+70
View File
@@ -0,0 +1,70 @@
import dotenv from "dotenv";
import { resolve } from "path";
import fs from "fs-extra";
const baseResolve = (...r: any[]) => resolve(__dirname, ...r);
export const mainResolve = (...r: string[]) => baseResolve("..", ...r);
export const rootResolve = (...r: string[]) => baseResolve("../../..", ...r);
export const isDev = process.env.NODE_ENV === "development";
export const isLinux = process.platform === "linux";
export const isMac = process.platform === "darwin";
export const isWin = process.platform === "win32";
export class Env {
env: Record<string, string> = {};
nodeEnv = "";
static instance: Env;
private constructor(nodeEnv = process.env.NODE_ENV) {
const env = this.parseEnv(rootResolve(".env"));
const modeEnv = this.parseEnv(rootResolve(`.env.${nodeEnv}`));
const localEnv = this.parseEnv(rootResolve(`.env.${nodeEnv}.local`));
this.nodeEnv = nodeEnv || "development";
this.env = { ...env, ...modeEnv, ...localEnv };
}
static getInstance() {
if (!Env.instance) {
Env.instance = new Env();
}
return Env.instance;
}
private parseEnv(path: string) {
if (!fs.existsSync(path)) {
return null;
}
const parsed = dotenv.parse(fs.readFileSync(path));
if (!parsed) {
return null;
}
return Object.keys(parsed).reduce((prev: any, curr) => {
prev[curr] = parsed[curr];
return prev;
}, {});
}
loadDotEnvRuntime() {
Object.keys(this.env).forEach((key) => {
if (process.env[key] != null || !this.env[key]) return;
process.env[key] = this.env[key];
});
}
loadDotEnvDefined() {
return Object.keys(this.env).reduce<Record<string, string>>((prev, cur) => {
prev[`process.env.${[cur]}`] = JSON.stringify(this.env[cur]);
return prev;
}, {});
}
get isDev() {
return this.nodeEnv === "development";
}
}
+83
View File
@@ -0,0 +1,83 @@
import { inject, injectable } from "inversify";
import { TYPES } from "./types.ts";
import TypeORM from "./vendor/TypeORM.ts";
import RouterHandlerService from "./core/router.ts";
import Koa from "koa";
import cors from "@koa/cors";
import bodyParser from "koa-bodyparser";
import Logger from "./vendor/Logger.ts";
import http from "http";
import SocketIO from "./vendor/SocketIO.ts";
import VideoRepository from "./repository/VideoRepository.ts";
import { DownloadStatus } from "./interfaces.ts";
import serve from "koa-static";
import { STATIC_DIR } from "./const.ts";
import send from "koa-send";
@injectable()
export default class ElectronApp extends Koa {
constructor(
@inject(TYPES.RouterHandlerService)
private readonly router: RouterHandlerService,
@inject(TYPES.TypeORM)
private readonly db: TypeORM,
@inject(TYPES.Logger)
private readonly logger: Logger,
@inject(TYPES.SocketIO)
private readonly socket: SocketIO,
@inject(TYPES.VideoRepository)
private readonly videoRepository: VideoRepository,
) {
super();
}
private async vendorInit() {
await this.db.init();
}
async init(): Promise<void> {
this.router.init();
// vendor
await this.vendorInit();
this.use(cors())
.use(bodyParser())
.use(this.router.routes())
.use(this.router.allowedMethods());
this.use(serve(STATIC_DIR));
// Middleware that handles static files and front-end routing
this.use(async (ctx, next) => {
if (!ctx.path.startsWith("/api")) {
try {
await send(ctx, ctx.path, { root: STATIC_DIR });
} catch (err: any) {
if (err.status === 404) {
await send(ctx, "index.html", { root: STATIC_DIR });
}
}
}
await next();
});
const server = http.createServer(this.callback());
this.socket.initSocketIO(server);
server.listen(8899, () => {
this.logger.info("Server running on port 8899");
});
}
// If there are still videos being downloaded after the restart, change the status to download failed
async resetDownloadStatus(): Promise<void> {
// If data in the downloading state still fails after the restart, all downloads fail
const videos = await this.videoRepository.findWattingAndDownloadingVideos();
const videoIds = videos.map((video) => video.id);
await this.videoRepository.changeVideoStatus(
videoIds,
DownloadStatus.Failed,
);
}
}
+13
View File
@@ -0,0 +1,13 @@
import os from "os";
import { dirname, resolve } from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export const API_PREFIX = "/api";
export const HOME_DIR = os.homedir();
export const DOWNLOAD_DIR = `${HOME_DIR}/mediago`;
export const STATIC_DIR = resolve(__dirname, "../app");
export const BIN_DIR = resolve(__dirname, "./bin");
export const DB_PATH = `${__dirname}/../mediago.db`;
@@ -0,0 +1,107 @@
import { inject, injectable } from "inversify";
import {
DownloadItem,
DownloadItemPagination,
type Controller,
} from "../interfaces.ts";
import { TYPES } from "../types.ts";
import { get, post } from "../helper/index.ts";
import VideoRepository from "../repository/VideoRepository.ts";
import { Context } from "koa";
import DownloaderService from "../services/DownloaderService.ts";
import DownloadService from "../services/DownloadService.ts";
import Logger from "../vendor/Logger.ts";
@injectable()
export default class DownloadController implements Controller {
constructor(
@inject(TYPES.VideoRepository)
private readonly videoRepository: VideoRepository,
@inject(TYPES.DownloaderService)
private readonly downloaderService: DownloaderService,
@inject(TYPES.DownloadService)
private readonly downloadService: DownloadService,
@inject(TYPES.Logger)
private readonly logger: Logger,
) {}
@get("/")
async getFavorites() {
return false;
}
@post("add-download-item")
async addDownloadItem(ctx: Context) {
const video = ctx.request.body as DownloadItem;
const item = await this.videoRepository.addVideo(video);
return item;
}
@post("add-download-items")
async addDownloadItems(ctx: Context) {
const videos = ctx.request.body as DownloadItem[];
return this.downloaderService.addDownloadItems(videos);
}
@post("get-download-items")
async getDownloadItems(ctx: Context) {
const pagination = ctx.request.body as DownloadItemPagination;
const videos = await this.videoRepository.findVideos(pagination);
return videos;
}
@post("start-download")
async startDownload(ctx: Context) {
const { vid } = ctx.request.body as { vid: number };
await this.downloaderService.startDownload(vid);
}
@post("delete-download-item")
async deleteDownloadItem(ctx: Context) {
const { id } = ctx.request.body as { id: number };
await this.videoRepository.deleteDownloadItem(id);
}
@post("download-now")
async downloadNow(ctx: Context) {
const video = ctx.request.body as Omit<DownloadItem, "id">;
await this.downloaderService.downloadNow(video);
}
@post("download-items-now")
async downloadItemsNow(ctx: Context) {
const videos = ctx.request.body as Omit<DownloadItem, "id">[];
// Add download
const items = await this.downloaderService.addDownloadItems(videos);
// Start downloading
items.forEach((item) => this.downloaderService.startDownload(item.id));
return items;
}
@post("edit-download-now")
async editDownloadNow(ctx: Context) {
const video = ctx.request.body as DownloadItem;
const item = await this.downloaderService.editDownloadItem(video);
await this.downloaderService.startDownload(item.id);
return item;
}
@post("edit-download-item")
async editDownloadItem(ctx: Context) {
const video = ctx.request.body as DownloadItem;
this.logger.info("editDownloadItem", video);
return this.downloaderService.editDownloadItem(video);
}
@post("stop-download")
async stopDownload(ctx: Context) {
const { id } = ctx.request.body as { id: number };
this.downloadService.stopTask(id);
}
@post("get-video-folders")
async getVideoFolders() {
return this.downloaderService.getVideoFolders();
}
}
@@ -0,0 +1,51 @@
import { inject, injectable } from "inversify";
import { type Controller } from "../interfaces.ts";
import { ConfigParams, TYPES } from "../types.ts";
import FavoriteRepository from "../repository/FavoriteRepository.ts";
import { get, post } from "../helper/index.ts";
import Logger from "../vendor/Logger.ts";
import ConfigService from "../services/ConfigService.ts";
import { Context } from "koa";
import SocketIO from "../vendor/SocketIO.ts";
@injectable()
export default class HomeController implements Controller {
constructor(
@inject(TYPES.FavoriteRepository)
private readonly favoriteRepository: FavoriteRepository,
@inject(TYPES.Logger)
private readonly logger: Logger,
@inject(TYPES.ConfigService)
private readonly config: ConfigService,
@inject(TYPES.SocketIO)
private readonly socket: SocketIO,
) {}
@get("/")
async getFavorites() {
return false;
}
@post("get-app-store")
async getAppStore() {
const store = await this.config.getConfig();
return store;
}
@post("set-app-store")
async setAppStore(ctx: Context) {
const params = ctx.request.body as ConfigParams;
this.config.setConfig(params);
this.logger.info("set app store");
return false;
}
@post("socket-test")
async socketTest(ctx: Context) {
const { message } = ctx.request.body as { message: string };
this.logger.info(message);
this.socket.emit("socket-test", message);
return message;
}
}
+72
View File
@@ -0,0 +1,72 @@
import { inject, injectable, multiInject } from "inversify";
import { Controller } from "../interfaces.ts";
import { TYPES } from "../types.ts";
import Router from "@koa/router";
import { error, success } from "../helper/utils.ts";
import { API_PREFIX } from "../const.ts";
import path from "path";
import Logger from "../vendor/Logger.ts";
@injectable()
export default class RouterHandlerService extends Router {
constructor(
@multiInject(TYPES.Controller)
private readonly controllers: Controller[],
@inject(TYPES.Logger)
private readonly logger: Logger,
) {
super();
}
private registerIpc(
controller: Controller,
propertyKey: string | symbol,
): void {
const property = controller[propertyKey];
if (typeof property !== "function") return;
const httpMethod: "get" | "post" = Reflect.getMetadata(
"http-method",
controller,
propertyKey,
);
if (!httpMethod) return;
const routerPath = Reflect.getMetadata(
"router-path",
controller,
propertyKey,
);
if (!routerPath) return;
const finalPath = path
.join(API_PREFIX, routerPath)
.replace(/\\/g, "/")
.replace(/\/$/, "");
this[httpMethod](finalPath, async (context, next) => {
try {
let res = property.call(controller, context, next);
if (res.then) {
res = await res;
}
context.body = success(res);
} catch (e: unknown) {
this.logger.error(e);
if (e instanceof Error) {
context.body = error(e.message);
} else {
context.body = error(String(e));
}
}
});
}
init(): void {
for (const controller of this.controllers) {
const Class = Object.getPrototypeOf(controller);
Object.getOwnPropertyNames(Class).forEach((propertyKey) =>
this.registerIpc(controller, propertyKey),
);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
export interface Vendor {
init(): Promise<void>;
}
+81
View File
@@ -0,0 +1,81 @@
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from "typeorm";
import { AppLanguage, AppTheme } from "../types.ts";
import { DOWNLOAD_DIR } from "../const.ts";
@Entity({
name: "config",
})
export class Config {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: "text",
nullable: false,
default: DOWNLOAD_DIR,
})
local: string;
@Column({
type: "text",
enum: AppTheme,
nullable: false,
default: AppTheme.System,
})
theme: AppTheme;
@Column({
type: "text",
enum: AppLanguage,
nullable: false,
default: AppLanguage.System,
})
language: AppLanguage;
@Column({
type: "text",
nullable: false,
default: "",
})
proxy: string;
@Column({
type: "boolean",
default: false,
nullable: false,
})
isLive: boolean;
@Column({
type: "boolean",
nullable: false,
default: false,
})
downloadProxySwitch: boolean;
@Column({
type: "boolean",
nullable: false,
default: true,
})
deleteSegments: boolean;
@Column({
type: "int",
nullable: false,
default: 2,
})
maxRunner: number;
@CreateDateColumn()
createdDate: Date;
@UpdateDateColumn()
updatedDate: Date;
}
+39
View File
@@ -0,0 +1,39 @@
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from "typeorm";
@Entity({
name: "favorite",
})
export class Favorite {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: "text",
nullable: false,
})
title: string;
@Column({
type: "text",
nullable: false,
})
url: string;
@Column({
type: "text",
nullable: true,
})
icon?: string;
@CreateDateColumn()
createdDate: Date;
@UpdateDateColumn()
updatedDate: Date;
}
+74
View File
@@ -0,0 +1,74 @@
import { DownloadStatus, DownloadType } from "../interfaces.ts";
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from "typeorm";
@Entity({
name: "video",
})
export class Video {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: "text",
nullable: false,
})
name: string;
@Column({
type: "text",
nullable: true,
})
folder?: string;
@Column({
type: "text",
nullable: false,
default: DownloadType.m3u8,
})
type: DownloadType;
@Column({
type: "text",
nullable: false,
})
url: string;
@Column({
type: "text",
nullable: true,
})
headers?: string;
@Column({
type: "boolean",
default: false,
nullable: false,
})
isLive: boolean;
@Column({
type: "text",
nullable: false,
default: DownloadStatus.Ready,
})
status: DownloadStatus;
@Column({
type: "text",
nullable: false,
default: "",
})
log: string;
@CreateDateColumn()
createdDate: Date;
@UpdateDateColumn()
updatedDate: Date;
}
+6
View File
@@ -0,0 +1,6 @@
/* eslint-disable no-var */
declare global {
var __bin__: string;
}
export {};
+13
View File
@@ -0,0 +1,13 @@
export const get = (route: string) => {
return (target: any, propertyKey: string): void => {
Reflect.defineMetadata("http-method", "get", target, propertyKey);
Reflect.defineMetadata("router-path", route, target, propertyKey);
};
};
export const post = (route: string) => {
return (target: any, propertyName: string): void => {
Reflect.defineMetadata("http-method", "post", target, propertyName);
Reflect.defineMetadata("router-path", route, target, propertyName);
};
};
+39
View File
@@ -0,0 +1,39 @@
import { spawn } from "child_process";
import { ffmpegPath } from "./variables.ts";
export const convertToAudio = async (
input: string,
output: string,
): Promise<void> => {
return new Promise((resolve, reject) => {
const ffmpeg = spawn(ffmpegPath, [
"-y",
"-v",
"error",
"-i",
input,
"-acodec",
"mp3",
"-format",
"mp3",
output,
]);
let errData = "";
ffmpeg.stderr.on("data", (data) => {
errData += String(data);
});
ffmpeg.on("error", (err) => {
reject(err);
});
ffmpeg.on("close", (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(errData));
}
});
});
};
+29
View File
@@ -0,0 +1,29 @@
import os from "os";
export function getLocalIP() {
const interfaces = os.networkInterfaces();
let localIP = "";
// Traverse the network interface
for (const key in interfaces) {
const iface = interfaces[key];
if (!iface) continue;
// IPv4 addresses that are not loopback addresses are filtered out
const filteredIface = iface.filter(
(details) => details.family === "IPv4" && !details.internal,
);
if (filteredIface.length > 0) {
localIP = filteredIface[0].address;
break;
}
}
return localIP;
}
export { sleep, formatHeaders } from "./utils.ts";
export * from "./variables.ts";
export { get, post } from "./decorator.ts";
export { convertToAudio } from "./ffmpeg.ts";
+37
View File
@@ -0,0 +1,37 @@
import EventEmitter from "events";
export async function sleep(second = 1): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, second * 1000));
}
export function formatHeaders(headers: Record<string, string>): string {
if (!headers) return "";
const formatted = Object.entries(headers)
.map(([key, value]) => `${key}:${value}`)
.join("\n");
return formatted;
}
export const event = new EventEmitter();
export interface IpcResponse {
code: number;
message: string;
data: Record<string, any> | null;
}
export function success(data: Record<string, any>): IpcResponse {
return {
code: 0,
message: "success",
data,
};
}
export function error(message = "fail"): IpcResponse {
return {
code: -1,
message,
data: null,
};
}
+35
View File
@@ -0,0 +1,35 @@
import { resolve } from "path";
import { BIN_DIR } from "../const.ts";
export enum Platform {
Windows = "win32",
MacOS = "darwin",
Linux = "linux",
}
export const isMac = process.platform === Platform.MacOS;
export const isWin = process.platform === Platform.Windows;
export const isLinux = process.platform === Platform.Linux;
export function resolveBin(path: string) {
if (isWin) {
path += ".exe";
}
return resolve(BIN_DIR, path);
}
export const appName = process.env.APP_NAME || "mediago";
export const defaultScheme = "mediago";
export const PERSIST_MEDIAGO = "persist:mediago";
export const PERSIST_WEBVIEW = "persist:webview";
export const PRIVACY_WEBVIEW = "webview";
// bin path
export const ffmpegPath = resolveBin("ffmpeg");
export const biliDownloaderBin = resolveBin("BBDown");
export const m3u8DownloaderBin = resolveBin("N_m3u8DL-RE");
// user agent
export const pcUA = "";
export const mobileUA =
"Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36";
+114
View File
@@ -0,0 +1,114 @@
import i18n from "i18next";
i18n.init({
debug: process.env.NODE_ENV === "development",
fallbackLng: "zh",
interpolation: {
escapeValue: false,
},
resources: {
en: {
translation: {
processIPC: "Processing ipc [{{channel}}] event exception: ",
open: "Open",
delete: "Delete",
noMainWindow: "No main window found",
copyLinkAddress: "Copy Link Address",
select: "Select",
download: "Download",
refresh: "Refresh",
openFolder: "Download Folder",
openFile: "Open File",
noFileFound: "No file found",
exportFavorites: "Export Favorites",
copy: "Copy",
paste: "Paste",
noTaskFound: "No task found",
urlExist: "Url already exists",
videoExistsPleaseChangeName:
"Video name already exists, please change the video name",
videoNotExists: "Video does not exist",
unknownError: "Unknown error",
unsupportedDownloadType: "Unsupported download type",
captureVideoLinkInWindow: "Capture video link in window: {{url}}",
browserViewNotFound: "Browser view not found",
currentWindowNotFound: "Current window not found",
proxyNotAllowEmpty: "[Proxy] Proxy cannot be empty",
enableProxy: "[Proxy] Enable Proxy({{proxy}})",
disableProxy: "[Proxy] Disable Proxy",
adBlockerEnableFailed: "[AdBlocker] AdBlocker enable failed",
enableADBlocker: "[AdBlocker] Enable AD Blocker",
adBlockerDisableFailed: "[AdBlocker] AdBlocker disable failed",
disableADBlocker: "[AdBlocker] Disable AD Blocker",
ua: '[UA] User-Agent: "{{ua}}"',
session: "[Session] {{mode}} Mode",
currentEnvironmentIsDevelopment:
"Current environment is development, start loading developer tools",
loadDevToolsSuccess: "Load developer tools successfully",
loadDevToolsFailed: "Failed to load developer tools",
autoUpdateSuccess: "Auto update success",
nextTimeWillAutoInstall: "Will be automatically installed next time",
downloadSuccess: "Download success",
videoDownloadSuccess: "{{name}} download success",
downloadFailed: "Download failed",
videoDownloadFailed: "{{name}} download failed",
showMainWindow: "Show main window",
exitApp: "Exit app",
updateAvailable: "Update available.",
updateNotAvailable: "No updates available.",
},
},
zh: {
translation: {
processIPC: "处理 ipc [{{channel}}] 事件时异常: ",
open: "打开",
delete: "删除",
noMainWindow: "未找到主窗口",
copyLinkAddress: "复制链接地址",
select: "选择",
download: "下载",
refresh: "刷新",
openFolder: "下载目录",
openFile: "打开文件",
noFileFound: "未找到文件",
exportFavorites: "导出收藏",
copy: "复制",
paste: "粘贴",
noTaskFound: "未找到任务",
urlExist: "链接已存在",
videoExistsPleaseChangeName: "视频名称已存在,请更改视频名称",
videoNotExists: "视频不存在",
unknownError: "未知错误",
unsupportedDownloadType: "不支持的下载类型",
captureVideoLinkInWindow: "在窗口中捕获视频链接: {{url}}",
browserViewNotFound: "未找到 BrowserView",
currentWindowNotFound: "未找到当前窗口",
proxyNotAllowEmpty: "[Proxy] 代理不能为空",
enableProxy: "[Proxy] 启用代理({{proxy}})",
disableProxy: "[Proxy] 关闭代理",
adBlockerEnableFailed: "[AdBlocker] AdBlocker 启用失败",
enableADBlocker: "[AdBlocker] 启用 AD Blocker",
adBlockerDisableFailed: "[AdBlocker] AdBlocker 关闭失败",
disableADBlocker: "[AdBlocker] 关闭 AD Blocker",
ua: '[UA] User-Agent: "{{ua}}"',
session: "[Session] {{mode}} 模式",
currentEnvironmentIsDevelopment:
"当前环境为开发环境,开始加载开发者工具",
loadDevToolsSuccess: "加载开发者工具成功",
loadDevToolsFailed: "加载开发者工具失败",
autoUpdateSuccess: "自动更新成功",
nextTimeWillAutoInstall: "下次将自动安装",
downloadSuccess: "下载成功",
videoDownloadSuccess: "{{name}} 下载成功",
downloadFailed: "下载失败",
videoDownloadFailed: "{{name}} 下载失败",
showMainWindow: "显示主窗口",
exitApp: "退出应用",
updateAvailable: "有可用更新。",
updateNotAvailable: "没有可用更新。",
},
},
},
});
export default i18n;
+7
View File
@@ -0,0 +1,7 @@
declare module "*.svg";
declare module "*.png";
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.gif";
declare module "*.bmp";
declare module "*.tiff";
+7
View File
@@ -0,0 +1,7 @@
import "reflect-metadata";
import { container } from "./inversify.config.ts";
import { TYPES } from "./types.ts";
import ElectronApp from "./app.ts";
const mediago = container.get<ElectronApp>(TYPES.ElectronApp);
mediago.init();
+73
View File
@@ -0,0 +1,73 @@
export type Controller = Record<string | symbol, any>;
export interface DownloadItem {
id: number;
type: DownloadType;
name: string;
url: string;
headers?: string;
status?: DownloadStatus;
isLive?: boolean;
folder?: string;
}
export enum DownloadFilter {
list = "list",
done = "done",
}
export interface DownloadItemPagination {
current?: number;
pageSize?: number;
filter?: DownloadFilter;
}
export interface ConversionPagination {
current?: number;
pageSize?: number;
}
export interface VideoResponse {
total: number;
list: DownloadItem[];
}
export enum DownloadStatus {
Ready = "ready",
Watting = "watting",
Downloading = "downloading",
Stopped = "stopped",
Success = "success",
Failed = "failed",
}
export type Task = {
id: number;
params: Omit<DownloadParams, "id" | "abortSignal" | "callback">;
};
export interface DownloadProgress {
id: number;
type: string;
percent: string;
speed: string;
isLive: boolean;
}
export enum DownloadType {
m3u8 = "m3u8",
bilibili = "bilibili",
}
export interface DownloadParams {
id: number;
type: DownloadType;
url: string;
local: string;
name: string;
headers?: string;
abortSignal: AbortController;
proxy?: string;
deleteSegments?: boolean;
callback: (progress: DownloadProgress) => void;
folder?: string;
}
+60
View File
@@ -0,0 +1,60 @@
import HomeController from "./controller/HomeController.ts";
import { Container } from "inversify";
import FavoriteRepository from "./repository/FavoriteRepository.ts";
import ElectronApp from "./app.ts";
import { Controller } from "./interfaces.ts";
import { TYPES } from "./types.ts";
import TypeORM from "./vendor/TypeORM.ts";
import RouterHandler from "./core/router.ts";
import HomeService from "./services/HomeService.ts";
import Logger from "./vendor/Logger.ts";
import DownloadController from "./controller/DownloadController.ts";
import VideoRepository from "./repository/VideoRepository.ts";
import ConfigRepository from "./repository/ConfigRepository.ts";
import ConfigService from "./services/ConfigService.ts";
import DownloadService from "./services/DownloadService.ts";
import SocketIO from "./vendor/SocketIO.ts";
import DownloaderService from "./services/DownloaderService.ts";
const container = new Container({
skipBaseClassChecks: true,
defaultScope: "Singleton",
autoBindInjectable: true,
});
container
.bind<ElectronApp>(TYPES.ElectronApp)
.to(ElectronApp)
.inSingletonScope();
// services
container.bind<HomeService>(TYPES.HomeService).to(HomeService);
container.bind<ConfigService>(TYPES.ConfigService).to(ConfigService);
container.bind<DownloadService>(TYPES.DownloadService).to(DownloadService);
container
.bind<DownloaderService>(TYPES.DownloaderService)
.to(DownloaderService);
// controller
container.bind<Controller>(TYPES.Controller).to(HomeController);
container.bind<Controller>(TYPES.Controller).to(DownloadController);
// repository
container
.bind<FavoriteRepository>(TYPES.FavoriteRepository)
.to(FavoriteRepository);
container.bind<VideoRepository>(TYPES.VideoRepository).to(VideoRepository);
container.bind<ConfigRepository>(TYPES.ConfigRepository).to(ConfigRepository);
// vendor
container.bind<TypeORM>(TYPES.TypeORM).to(TypeORM);
container.bind<Logger>(TYPES.Logger).to(Logger);
container.bind<SocketIO>(TYPES.SocketIO).to(SocketIO);
// core
container
.bind<RouterHandler>(TYPES.RouterHandlerService)
.to(RouterHandler)
.inSingletonScope();
export { container };
+66
View File
@@ -0,0 +1,66 @@
import { Rectangle } from "electron";
import { type DownloadType } from "interfaces";
import { AppLanguage, AppTheme } from "./types";
declare interface EnvPath {
binPath: string;
dbPath: string;
workspace: string;
platform: string;
local: string;
}
declare interface BrowserWindowInitialVal {
url?: string;
sourceList?: WebSource[];
}
declare interface WebSource {
url: string;
type: DownloadType;
name: string;
headers?: string;
}
declare interface AppStore {
// Local storage address
local: string;
// Download completion tone
promptTone: boolean;
// Proxy address
proxy: string;
// Whether to enable agent
useProxy: boolean;
// Delete the original file after downloading
deleteSegments: boolean;
// A new window opens the browser
openInNewWindow: boolean;
mainBounds?: Rectangle;
browserBounds?: Rectangle;
blockAds: boolean;
// theme
theme: AppTheme;
// Using browser plugins
useExtension: boolean;
// Whether to use mobile UA
isMobile: boolean;
// Maximum number of simultaneous downloads
maxRunner: number;
// Language
language: AppLanguage;
// Show terminal or not
showTerminal: boolean;
// Privacy mode
privacy: boolean;
// Machine id
machineId: string;
// Download proxy Settings
downloadProxySwitch: boolean;
// Automatic update
autoUpgrade: boolean;
}
declare interface BrowserStore {
url: string;
sourceList: WebSource[];
}
@@ -0,0 +1,30 @@
import { inject, injectable } from "inversify";
import { ConfigParams, TYPES } from "../types.ts";
import TypeORM from "../vendor/TypeORM.ts";
import { Repository } from "typeorm";
import { Config } from "../entity/Config.ts";
@injectable()
export default class ConfigRepository {
repository: Repository<Config>;
constructor(
@inject(TYPES.TypeORM)
private readonly db: TypeORM,
) {
this.repository = this.db.manager.getRepository(Config);
}
async getConfig(): Promise<Config> {
const config = await this.repository.findOneBy({ id: 1 });
if (!config) {
return await this.repository.save(new Config());
}
return config;
}
async setConfig({ key, val }: ConfigParams) {
const config = await this.getConfig();
this.repository.update(config.id, { [key]: val });
}
}
@@ -0,0 +1,42 @@
import { inject, injectable } from "inversify";
import { TYPES } from "../types.ts";
import { Favorite } from "../entity/Favorite.ts";
import TypeORM from "../vendor/TypeORM.ts";
@injectable()
export default class FavoriteRepository {
constructor(
@inject(TYPES.TypeORM)
private readonly db: TypeORM,
) {}
async findFavorites(): Promise<Favorite[]> {
return await this.db.manager.find(Favorite, {
order: {
createdDate: "desc",
},
});
}
async addFavorite(favorite: Favorite): Promise<Favorite> {
const exist = await this.db.manager.findOne(Favorite, {
where: {
url: favorite.url,
},
});
if (exist) {
throw new Error("网址已经存在");
}
const item = new Favorite();
item.title = favorite.title;
item.url = favorite.url;
item.icon = favorite.icon;
return await this.db.manager.save(item);
}
async removeFavorite(id: number): Promise<void> {
await this.db.manager.getRepository(Favorite).delete(id);
}
}
@@ -0,0 +1,189 @@
import { Video } from "../entity/Video.ts";
import { inject, injectable } from "inversify";
import {
DownloadFilter,
DownloadItem,
DownloadItemPagination,
DownloadStatus,
} from "../interfaces.ts";
import { TYPES } from "../types.ts";
import { In, Not } from "typeorm";
import TypeORM from "../vendor/TypeORM.ts";
import i18n from "../i18n/index.ts";
@injectable()
export default class VideoRepository {
constructor(
@inject(TYPES.TypeORM)
private readonly db: TypeORM,
) {}
async addVideo(video: Omit<DownloadItem, "id">) {
// Let's see if there's a video with the same name
const exist = await this.findVideoByName(video.name);
if (exist) {
throw new Error(i18n.t("videoExistsPleaseChangeName"));
}
const item = new Video();
item.name = video.name;
item.url = video.url;
item.type = video.type;
video.headers && (item.headers = video.headers);
video.folder && (item.folder = video.folder);
return await this.db.manager.save(item);
}
async addVideos(videos: Omit<DownloadItem, "id">[]) {
// Check for videos with the same name
const names = videos.map((item) => item.name);
const existItems = await this.db.appDataSource
.getRepository(Video)
.findBy({ name: In(names) });
if (existItems.length) {
const existNames = existItems.map((item) => item.name);
throw new Error(
i18n.t("videoExistsPleaseChangeName") +
"[" +
existNames.join(", ") +
"]",
);
}
const items = videos.map((video) => {
const item = new Video();
item.name = video.name;
item.url = video.url;
item.type = video.type;
video.headers && (item.headers = video.headers);
video.folder && (item.folder = video.folder);
return item;
});
return await this.db.manager.save(items);
}
// Edit video
async editVideo(video: DownloadItem) {
const item = await this.db.appDataSource
.getRepository(Video)
.findOneBy({ id: video.id });
if (!item) {
throw new Error(i18n.t("videoNotExists"));
}
item.name = video.name;
item.url = video.url;
video.headers && (item.headers = video.headers);
video.folder && (item.folder = video.folder);
return await this.db.manager.save(item);
}
// Find all Videos
async findAllVideos() {
return await this.db.appDataSource.getRepository(Video).find({
order: {
createdDate: "DESC",
},
});
}
async findVideos(pagination: DownloadItemPagination) {
const {
current = 0,
pageSize = 50,
filter = DownloadFilter.list,
} = pagination;
const filterCondition =
filter === DownloadFilter.done
? DownloadStatus.Success
: Not(DownloadStatus.Success);
const [items, count] = await this.db.appDataSource
.getRepository(Video)
.findAndCount({
where: {
status: filterCondition,
},
order: {
createdDate: "ASC",
},
skip: (current - 1) * pageSize,
take: pageSize,
});
return {
total: count,
list: items,
};
}
async findVideo(id: number) {
const repository = this.db.appDataSource.getRepository(Video);
const video = await repository.findOneBy({ id });
if (!video) {
throw new Error(i18n.t("videoNotExists"));
}
return video;
}
async findVideoByName(name: string) {
return this.db.appDataSource.getRepository(Video).findOneBy({
name,
});
}
async changeVideoStatus(id: number | number[], status: DownloadStatus) {
const ids = !Array.isArray(id) ? [id] : id;
const videoRepository = this.db.appDataSource.getRepository(Video);
const videos = await videoRepository.findBy({ id: In(ids) });
for (const video of videos) {
video.status = status;
}
await videoRepository.save(videos);
}
async changeVideoIsLive(id: number) {
const video = await this.findVideo(id);
video.isLive = true;
return this.db.manager.save(video);
}
async findWattingAndDownloadingVideos() {
return await this.db.appDataSource.getRepository(Video).find({
where: {
status: In([DownloadStatus.Downloading, DownloadStatus.Watting]),
},
});
}
async deleteDownloadItem(id: number) {
return await this.db.appDataSource.getRepository(Video).delete(id);
}
async findVideoByUrl(url: string) {
return this.db.appDataSource.getRepository(Video).findOneBy({
url,
});
}
async appendDownloadLog(id: number, message: string) {
const video = await this.findVideo(id);
video.log = video.log ? `${video.log}\n${message}` : message;
return await this.db.manager.save(video);
}
async getDownloadLog(id: number) {
const video = await this.findVideo(id);
return video.log;
}
async getVideoFolders() {
const videos = await this.db.appDataSource.getRepository(Video).find();
const folders = new Set<string>();
for (const video of videos) {
if (video.folder) {
folders.add(video.folder);
}
}
return Array.from(folders);
}
}
@@ -0,0 +1,19 @@
import { inject, injectable } from "inversify";
import { ConfigParams, TYPES } from "../types.ts";
import ConfigRepository from "../repository/ConfigRepository.ts";
@injectable()
export default class ConfigService {
constructor(
@inject(TYPES.ConfigRepository)
private readonly configRepository: ConfigRepository,
) {}
async getConfig() {
return await this.configRepository.getConfig();
}
async setConfig({ key, val }: ConfigParams) {
return await this.configRepository.setConfig({ key, val });
}
}
@@ -0,0 +1,422 @@
import EventEmitter from "events";
import { inject, injectable } from "inversify";
import {
DownloadParams,
DownloadProgress,
DownloadStatus,
Task,
} from "../interfaces.ts";
import { TYPES } from "../types.ts";
import Logger from "../vendor/Logger.ts";
import VideoRepository from "../repository/VideoRepository.ts";
import {
Platform,
biliDownloaderBin,
m3u8DownloaderBin,
} from "../helper/index.ts";
import * as pty from "node-pty";
import stripAnsi from "strip-ansi";
import i18n from "../i18n/index.ts";
import ConfigService from "./ConfigService.ts";
import path from "path";
interface DownloadContext {
// Whether it is live
isLive: boolean;
// Download progress
percent: string;
// Download speed
speed: string;
// Ready
ready: boolean;
}
export interface DownloadOptions {
abortSignal: AbortController;
encoding?: string;
onMessage?: (ctx: DownloadContext, message: string) => void;
id: number;
}
interface Schema {
args: Record<string, { argsName: string[] | null }>;
consoleReg: {
percent: string;
speed: string;
error: string;
start: string;
isLive: string;
};
bin: string;
platform: string[];
type: string;
}
// FIXME: Multilingual regular expressions
const processList: Schema[] = [
{
type: "m3u8",
platform: [Platform.MacOS, Platform.Linux, Platform.Windows],
bin: m3u8DownloaderBin,
args: {
url: {
argsName: null,
},
localDir: {
argsName: ["--tmp-dir", "--save-dir"],
},
name: {
argsName: ["--save-name"],
},
headers: {
argsName: ["--header"],
},
deleteSegments: {
argsName: ["--del-after-done"],
},
proxy: {
argsName: ["--custom-proxy"],
},
__common__: {
argsName: [
"--no-log",
"--auto-select",
"--ui-language",
"zh-CN",
"--live-real-time-merge",
],
},
},
consoleReg: {
percent: "([\\d.]+)%",
speed: "([\\d.]+[GMK]Bps)",
error: "ERROR",
start: "保存文件名:",
isLive: "检测到直播流",
},
},
{
type: "bilibili",
platform: [Platform.Linux, Platform.MacOS, Platform.Windows],
bin: biliDownloaderBin,
args: {
url: {
argsName: null,
},
localDir: {
argsName: ["--work-dir"],
},
name: {
argsName: ["--file-pattern"],
},
},
consoleReg: {
speed: "([\\d.]+\\s[GMK]B/s)",
percent: "([\\d.]+)%",
error: "ERROR",
start: "开始下载",
isLive: "检测到直播流",
},
},
];
@injectable()
export default class DownloadService extends EventEmitter {
private queue: Task[] = [];
private active: Task[] = [];
private limit: number = 2;
private signal: Record<number, AbortController> = {};
constructor(
@inject(TYPES.Logger)
private readonly logger: Logger,
@inject(TYPES.VideoRepository)
private readonly videoRepository: VideoRepository,
@inject(TYPES.ConfigService)
private readonly storeService: ConfigService,
) {
super();
// this.storeService.getConfig().then(({ maxRunner }) => {
// this.limit = maxRunner;
// });
}
async addTask(task: Task) {
this.queue.push(task);
this.runTask();
}
async stopTask(id: number) {
if (this.signal[id]) {
this.signal[id].abort();
}
}
async execute(task: Task) {
try {
await this.videoRepository.changeVideoStatus(
task.id,
DownloadStatus.Downloading,
);
this.emit("download-start", task.id);
this.logger.info(`taskId: ${task.id} start`);
const controller = new AbortController();
this.signal[task.id] = controller;
const callback = (progress: DownloadProgress) => {
if (progress.type === "progress") {
this.emit("download-progress", progress);
} else if (progress.type === "ready") {
this.emit("download-ready-start", progress);
if (progress.isLive) {
this.removeTask(progress.id);
}
}
};
const params: DownloadParams = {
...task.params,
id: task.id,
abortSignal: controller,
callback,
};
const { proxy, downloadProxySwitch } =
await this.storeService.getConfig();
if (downloadProxySwitch && proxy) {
params.proxy = proxy;
}
await this.process(params);
delete this.signal[task.id];
this.logger.info(`taskId: ${task.id} success`);
await this.videoRepository.changeVideoStatus(
task.id,
DownloadStatus.Success,
);
this.emit("download-success", task.id);
} catch (err: any) {
if (err.message === "AbortError") {
this.logger.info(`taskId: ${task.id} stopped`);
// Download pause
await this.videoRepository.changeVideoStatus(
task.id,
DownloadStatus.Stopped,
);
this.emit("download-stop", task.id);
} else {
this.logger.error(`taskId: ${task.id} failed`, err);
// Download failure
await this.videoRepository.changeVideoStatus(
task.id,
DownloadStatus.Failed,
);
this.emit("download-failed", task.id, err);
}
} finally {
this.removeTask(task.id);
// Transmission complete
if (this.queue.length === 0 && this.active.length === 0) {
// this.emit("download-finish");
}
}
}
removeTask(id: number) {
// Process the currently active task
const doneId = this.active.findIndex((i) => i.id === id);
this.active.splice(doneId, 1);
// Process completed tasks
if (this.active.length < this.limit) {
this.runTask();
}
}
runTask() {
while (this.active.length < this.limit && this.queue.length > 0) {
const task = this.queue.shift();
if (task) {
this.active.push(task);
this.execute(task);
}
}
}
private _execa(
binPath: string,
args: string[],
params: DownloadOptions,
): Promise<void> {
const { abortSignal, onMessage, id } = params;
return new Promise((resolve, reject) => {
const ptyProcess = pty.spawn(binPath, args, {
name: "xterm-color",
cols: 500,
rows: 500,
useConpty: false,
});
if (onMessage) {
const ctx: DownloadContext = {
ready: false,
isLive: false,
percent: "",
speed: "",
};
ptyProcess.onData((data) => {
try {
const txt = stripAnsi(data);
this.emit("download-message", id, data);
onMessage(ctx, txt);
} catch (err) {
reject(err);
}
});
}
abortSignal.signal.addEventListener("abort", () => {
ptyProcess.kill();
reject(new Error("AbortError"));
});
ptyProcess.onExit(({ exitCode }) => {
if (exitCode === 0) {
resolve();
} else {
reject(new Error(i18n.t("unknownError")));
}
});
});
}
async downloader(params: DownloadParams, schema: Schema): Promise<void> {
const {
id,
abortSignal,
url,
local,
name,
deleteSegments,
headers,
callback,
proxy,
folder,
} = params;
const spawnParams = [];
for (const key of Object.keys(schema.args)) {
const { argsName } = schema.args[key];
if (key === "url") {
argsName && spawnParams.push(...argsName);
spawnParams.push(url);
}
if (key === "localDir") {
let finalLocal = local;
if (folder) {
finalLocal = path.join(local, folder);
}
argsName && argsName.forEach((i) => spawnParams.push(i, finalLocal));
}
if (key === "name") {
argsName && argsName.forEach((i) => spawnParams.push(i, name));
}
if (key === "headers" && headers) {
const headerArr: string[] = headers?.split("\n") || [];
headerArr.forEach((headerStr) => {
spawnParams.push("--header", headerStr);
});
}
if (key === "deleteSegments" && deleteSegments) {
argsName && spawnParams.push(...argsName);
}
if (key === "proxy" && proxy) {
argsName && argsName.forEach((i) => spawnParams.push(i, proxy));
}
if (key === "__common__") {
argsName && spawnParams.push(...argsName);
}
}
const { consoleReg } = schema;
const isLiveReg = RegExp(consoleReg.isLive, "g");
const startDownloadReg = RegExp(consoleReg.start, "g");
const errorReg = RegExp(consoleReg.error, "g");
const speedReg = RegExp(consoleReg.speed, "g");
const percentReg = RegExp(consoleReg.percent, "g");
const onMessage = (ctx: DownloadContext, message: string) => {
// Resolve whether it is a live resource
if (isLiveReg.test(message)) {
ctx.isLive = true;
}
// Parse download progress
const [, percent] = percentReg.exec(message) || [];
if (percent && Number(ctx.percent || 0) < Number(percent)) {
ctx.percent = percent;
}
// Parsing download speed
const [, speed] = speedReg.exec(message) || [];
if (speed) {
ctx.speed = speed;
}
if (startDownloadReg.test(message)) {
callback({
id,
type: "ready",
isLive: ctx.isLive,
speed: "",
percent: "",
});
ctx.ready = true;
return;
}
if (errorReg.test(message)) {
throw new Error(message);
}
if (ctx.ready && (ctx.percent || ctx.speed)) {
callback({
id,
type: "progress",
percent: ctx.percent || "",
speed: ctx.speed || "",
isLive: ctx.isLive,
});
}
};
this.logger.debug("download params: ", spawnParams.join(" "));
await this._execa(schema.bin, spawnParams, {
id,
abortSignal,
onMessage,
});
}
async process(params: DownloadParams): Promise<void> {
const program = processList
.filter((i) => i.platform.includes(process.platform))
.filter((i) => i.type === params.type);
if (program.length === 0) {
return Promise.reject(new Error(i18n.t("unsupportedDownloadType")));
}
const schema = program[0];
await this.downloader(params, schema);
}
}
@@ -0,0 +1,66 @@
import { inject, injectable } from "inversify";
import VideoRepository from "../repository/VideoRepository.ts";
import { TYPES } from "../types.ts";
import ConfigRepository from "../repository/ConfigRepository.ts";
import { DownloadItem, DownloadStatus, Task } from "../interfaces.ts";
import DownloadService from "./DownloadService.ts";
@injectable()
export default class DownloaderService {
constructor(
@inject(TYPES.VideoRepository)
private readonly videoRepository: VideoRepository,
@inject(TYPES.ConfigRepository)
private readonly store: ConfigRepository,
@inject(TYPES.DownloadService)
private readonly downloadService: DownloadService,
) {}
async startDownload(vid: number) {
// Find the video you want to download
const video = await this.videoRepository.findVideo(vid);
const { name, url, headers, type, folder } = video;
const { local, deleteSegments } = await this.store.getConfig();
const task: Task = {
id: vid,
params: {
url,
type,
local,
name,
headers,
deleteSegments,
folder,
},
};
await this.videoRepository.changeVideoStatus(vid, DownloadStatus.Watting);
this.downloadService.addTask(task);
}
async downloadNow(video: Omit<DownloadItem, "id">) {
// Add download
const item = await this.addDownloadItem(video);
// Start downloading
await this.startDownload(item.id);
return item;
}
async addDownloadItem(video: Omit<DownloadItem, "id">) {
const item = await this.videoRepository.addVideo(video);
return item;
}
async addDownloadItems(videos: Omit<DownloadItem, "id">[]) {
const items = await this.videoRepository.addVideos(videos);
return items;
}
async editDownloadItem(video: DownloadItem) {
return this.videoRepository.editVideo(video);
}
async getVideoFolders() {
return this.videoRepository.getVideoFolders();
}
}
@@ -0,0 +1,9 @@
import EventEmitter from "events";
import { injectable } from "inversify";
@injectable()
export default class HomeService extends EventEmitter {
constructor() {
super();
}
}
+46
View File
@@ -0,0 +1,46 @@
import { Config } from "./entity/Config.ts";
export const TYPES = {
ElectronApp: Symbol.for("ElectronApp"),
RouterHandlerService: Symbol.for("RouterHandlerService"),
Controller: Symbol.for("Controller"),
// repository
VideoRepository: Symbol.for("VideoRepository"),
FavoriteRepository: Symbol.for("FavoriteRepository"),
ConversionRepository: Symbol.for("ConversionRepository"),
ConfigRepository: Symbol.for("ConfigRepository"),
// windows
BrowserWindow: Symbol.for("BrowserWindow"),
MainWindow: Symbol.for("MainWindow"),
PlayerWindow: Symbol.for("PlayerWindow"),
// services
HomeService: Symbol.for("HomeService"),
DownloadService: Symbol.for("DownloadService"),
SessionService: Symbol.for("SessionService"),
ProtocolService: Symbol.for("ProtocolService"),
VideoService: Symbol.for("VideoService"),
SniffingHelper: Symbol.for("SniffingHelper"),
ConfigService: Symbol.for("ConfigService"),
DownloaderService: Symbol.for("DownloaderService"),
// vendor
TypeORM: Symbol.for("TypeORM"),
Logger: Symbol.for("Logger"),
SocketIO: Symbol.for("SocketIO"),
};
export enum AppTheme {
System = "system",
Light = "light",
Dark = "dark",
}
export enum AppLanguage {
System = "system",
ZH = "zh",
EN = "en",
}
export interface ConfigParams {
key: keyof Config;
val: Config[keyof Config];
}
+57
View File
@@ -0,0 +1,57 @@
import { injectable } from "inversify";
import { Vendor } from "../core/vendor.ts";
import winston from "winston";
@injectable()
export default class Logger implements Vendor {
logger: winston.Logger;
constructor() {
this.logger = winston.createLogger({
level: "info",
format: winston.format.json(),
defaultMeta: { service: "user-service" },
transports: [
//
// - Write all logs with importance level of `error` or less to `error.log`
// - Write all logs with importance level of `info` or less to `combined.log`
//
new winston.transports.File({
filename: "./log/error.log",
level: "error",
}),
new winston.transports.File({ filename: "./log/combined.log" }),
],
});
//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (process.env.NODE_ENV !== "production") {
this.logger.add(
new winston.transports.Console({
format: winston.format.simple(),
}),
);
}
}
info(...args: unknown[]) {
return this.logger.info(args);
}
warn(...args: unknown[]) {
return this.logger.warn(args);
}
error(...args: unknown[]) {
return this.logger.error(args);
}
debug(...args: unknown[]) {
return this.logger.debug(args);
}
async init() {}
}
+88
View File
@@ -0,0 +1,88 @@
import { inject, injectable } from "inversify";
import { Vendor } from "../core/vendor.ts";
import http from "http";
import { Server } from "socket.io";
import { TYPES } from "../types.ts";
import DownloadService from "../services/DownloadService.ts";
import { DownloadProgress } from "../interfaces.ts";
import VideoRepository from "../repository/VideoRepository.ts";
import Logger from "./Logger.ts";
import ConfigService from "../services/ConfigService.ts";
@injectable()
export default class SocketIO implements Vendor {
io: Server;
constructor(
@inject(TYPES.DownloadService)
private readonly downloadService: DownloadService,
@inject(TYPES.VideoRepository)
private readonly videoRepository: VideoRepository,
@inject(TYPES.Logger)
private readonly logger: Logger,
@inject(TYPES.ConfigService)
private readonly store: ConfigService,
) {}
async init() {}
async initSocketIO(server: http.Server) {
this.io = new Server(server, {
/* options */
cors: {
origin: "*",
},
});
this.io.engine.on("headers", (headers) => {
headers["Access-Control-Allow-Private-Network"] = true;
});
this.io.on("connection", () => {});
this.downloadService.on("download-ready-start", this.onDownloadReadyStart);
this.downloadService.on("download-progress", this.onDownloadProgress);
this.downloadService.on("download-success", this.onDownloadSuccess);
this.downloadService.on("download-failed", this.onDownloadFailed);
this.downloadService.on("download-start", this.onDownloadStart);
this.downloadService.on("download-stop", this.onDownloadStop);
this.downloadService.on("download-message", this.receiveMessage);
}
async emit(event: string, ...data: any[]) {
this.io.emit(event, {}, ...data);
}
onDownloadReadyStart = async ({ id, isLive }: DownloadProgress) => {
if (isLive) {
await this.videoRepository.changeVideoIsLive(id);
this.emit("change-video-is-live", { id });
}
};
onDownloadProgress = (progress: DownloadProgress) => {
this.emit("download-progress", progress);
};
onDownloadSuccess = async (id: number) => {
this.emit("download-success", id);
};
onDownloadFailed = async (id: number, err: unknown) => {
this.logger.error("download failed: ", err);
this.emit("download-failed", id);
};
onDownloadStart = async (id: number) => {
this.emit("download-start", id);
};
onDownloadStop = async (id: number) => {
this.emit("download-stop", id);
};
receiveMessage = async (id: number, message: string) => {
// Write the log to the database
await this.videoRepository.appendDownloadLog(id, message);
};
}
+32
View File
@@ -0,0 +1,32 @@
import { injectable } from "inversify";
import { DataSource, EntityManager } from "typeorm";
import { Favorite } from "../entity/Favorite.ts";
import { Vendor } from "../core/vendor.ts";
import { Video } from "../entity/Video.ts";
import { Config } from "../entity/Config.ts";
import { DB_PATH } from "../const.ts";
@injectable()
export default class DatabaseService implements Vendor {
appDataSource: DataSource;
constructor() {
this.appDataSource = new DataSource({
type: "better-sqlite3",
database: DB_PATH,
synchronize: true,
logging: false,
entities: [Favorite, Video, Config],
migrations: [],
subscribers: [],
});
}
async init() {
await this.appDataSource.initialize();
}
get manager(): EntityManager {
return this.appDataSource.manager;
}
}
+27
View File
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2015",
"module": "NodeNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "NodeNext",
"strictPropertyInitialization": false,
"typeRoots": ["node_modules/@types"],
"declaration": true,
"emitDeclarationOnly": true,
"declarationDir": "./types",
"outDir": "app/output/build/main",
"allowImportingTsExtensions": true
},
"include": ["src"],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
+15
View File
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"strict": true,
"composite": true,
"forceConsistentCasingInFileNames": true,
"module": "ES2015",
"lib": ["ES2015"],
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"typeRoots": ["node_modules/@types"]
},
"include": ["gulpfile.ts", "scripts"]
}
View File
-21
View File
@@ -1,21 +0,0 @@
module.exports = {
env: {
node: true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
],
overrides: [],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["@typescript-eslint", "prettier"],
rules: {
"prettier/prettier": "warn",
},
};
+1
View File
@@ -4,3 +4,4 @@ build
dist
bin/Logs
release
types
+1
View File
@@ -0,0 +1 @@
types/

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