├── LICENSE ├── README.md ├── contract.html ├── document ├── authentication-v8.png ├── authentication.png ├── clientID.png ├── icon.fw.png └── permission.png ├── icon.png ├── images ├── Image 29.png ├── Image 30.png ├── Image 31.png ├── Image 32.png ├── cloud-white-18dp.svg ├── share-1.webp ├── share-2.webp ├── share-3.webp ├── share-4-2.webp ├── share-4.webp ├── share-5.webp ├── share-6.webp └── share-white-18dp.svg ├── index.html ├── privacy.html ├── script.js ├── scripts └── auth.js └── style.css /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 获取OneDrive直链 2 | =========== 3 | 本应用的目的是为了**批量**获取 OneDrive 直链,方便在其他站点外链。前身为[提取OneDrive直链地址工具](http://bbs.comicdd.com/thread-354826-1-1.html)的网页版,因为原来的工具失效了,软件版也不是那么好用了,因此决定使用 OneDrive 官方 SDK 来进行获取,确保不失效。 4 | 5 | 2024年7月8日 以前的 SDK v7.2 好像用不了了,切换 SDK 到 v8 版本,只能获取到基本信息了。找了很久也不知道怎么获取更多的文件信息,就这样将就着用吧。 6 | 7 | # 马上使用 8 | https://mapaler.github.io/GetOneDriveDirectLink/ 9 | 10 | > 因为使用官方 API 直接访问 onedrive.live.com 选择文件,因此可能需要翻墙。 11 | 12 | # 隐私声明 13 | 14 | 使用微软官方 [文件选取器 v8](https://learn.microsoft.com/zh-cn/onedrive/developer/controls/file-pickers/),本应用不会得到你的账号密码和其他用户资料。 15 | 目前仅申请了 `Files.Read`、`Files.Read.Selected` 两个权限,SDK 只会返回用户选择的文件的信息,不会获得未授权的其他内容。 16 | 17 | # 如何自行搭建 18 | 19 | ## 文件选取器 v8 教程 20 | 21 | 我不想注册收费的 Azure,所以只提到在原有 v7.2 上的变化。注册 Azure 的流程区别请自己想办法了。 22 | 23 | 1. 身份验证不能用 Web ,得改成单页应用程序,不然会报错:[The provided request must include a 'client_secret' input parameter in the sample project](https://github.com/Azure-Samples/ms-identity-javascript-react-spa-dotnetcore-webapi-obo/issues/30) 24 | ![身份验证](document/authentication-v8.png) 25 | 2. 应用 ID,替换本程序 `scripts/auth.js` 内的 `msalParams.auth.clientId`。 26 | 27 | ## JavaScript SDK v7.2 教程 28 | 29 | 2024年7月8日 目前时间点登录会显示以下警告,也就是需要迁移到收费的 Azure,我不想搞,所以以下自行搭建教程已不适用于目前的内容,就这样将就着用吧。 30 | 31 | > 自 2020 年 6 月 30 日起,我们将不再向 Azure Active Directory 身份验证库(ADAL)和 Azure Active Directory Graph 添加任何新功能。我们将继续提供技术支持和安全更新程序,但将不再提供功能更新。应用程序将需要升级到 Microsoft 身份验证库(MSAL)和 Microsoft Graph。[了解更多信息](https://go.microsoft.com/fwlink/?linkid=2132805) 32 | 33 | > 这些应用程序与帐户 xxxx@outlook.com 关联,但不包含在任何目录中。在目录外部创建应用程序的功能已被弃用。你可通过加入 [M365 开发人员计划](https://aka.ms/joinM365DeveloperProgram)或[注册 Azure](https://aka.ms/signUpForAzure) 来获取新目录。[了解详细信息](https://aka.ms/MsaDeprecateInfo) 34 | 35 | ### 原内容 36 | 37 | >按照[OneDrive file picker SDK](https://docs.microsoft.com/onedrive/developer/controls/file-pickers/js-v72/)内的说明进行,由于旧有的*Microsoft 应用注册门户*已经迁移到*Azure门户*,特此做出更新,此版本更新于2020年2月6日。 38 | 39 | 1. 应用注册 40 | 在 [Azure 门户](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) 创建应用,自己申请一个应用 ID,然后替换本程序 `script.js` 内底部的 `clientId`。 41 | ![客户端ID](document/clientID.png) 42 | 其中 `odOptions.advanced.queryParameters` 内容参见 [DriveItem 资源类型](https://docs.microsoft.com/onedrive/developer/rest-api/resources/driveitem?view=odsp-graph-online),若不设定,将只返回基本信息。 43 | 1. 设置**身份验证** 44 | 将网页的各种东西上传到你申请 ID 时设置的 重定向 URL 即可,页面 URL 不在重定向内会发生错误。注:这个页面必须为 https(仅 localhost 可为 http,且 localhost 也需添加到 重定向 URL) 45 | 需要勾选**隐式授权**的**访问令牌**、**ID 令牌**。*讨论见[#9](//github.com/Mapaler/GetOneDriveDirectLink/issues/9)* 46 | ![身份验证](document/authentication.png) 47 | 1. 设置**API 权限** 48 | 添加 `Microsoft Graph` ▶ `委托的权限` ▶ `Files.Read`、`Files.Read.Selected` 49 | ![需求的权限](document/permission.png) 50 | 51 | ## 原理 52 | `http://storage.live.com/items/文件ID` 是很早之前就流传的 SkyDrive 官方的真实直链重定向地址,出处不可考。 53 | 开始一般是用`http://storage.live.com/items/文件ID?filename=xxx.jpg`来外链图片,后面的文件名用来欺骗DiscuzX论坛系统,但是浏览器下载该文件还是没有正确文件名。 54 | 后来有高手发现的`http://storage.live.com/items/文件ID:/xxx.jpg`这个地址格式不会影响 SkyDrive 识别ID,还同时可以欺骗浏览器为普通文件地址,识别出文件的文件名与扩展名。 55 | 访问 `onedrive.live.com` 域名需要翻墙,但是生成的 `storage.live.com` 链接不需要。 56 | 57 | ### 1drv.ws 原理 58 | 59 | > 由于 *1drv.ws* 项目自身停止运行,已删除对此功能的支持 60 | 61 | **1drv.ws** 是 *[The OneDrive Direct Download Link Helper](//github.com/aploium/OneDrive-Direct-Link)* 项目的实现。 62 | 原理为 63 | 1. 获取OneDrive的分享链接 `https://1drv.ms/u/分享ID` 64 | 2. 重定向到 `https://onedrive.live.com/redir?resid=文件ID&authkey=通行证` 65 | 3. 将访问网页的地址修改为下载地址 `https://onedrive.live.com/download?resid=文件ID&authkey=通行证` 66 | 4. 再次重定向到真实CDN地址 `https://public.ch.files.1drv.com/很长一串字符/文件名?download&psid=1` 67 | 68 | 其中,对 `onedrive.live.com` 的重定向需要墙外后端支持。 69 | 70 | 在 OneDrive SDK 中,使用 `share` 操作才能新增并获取到分享链接,因此添加了“额外创建分享链接”按钮。 71 | 掩码将获取到的分享链接中的 1drv.**m**s 修改为 1drv.**w**s ,即可得到下载链接。但是这种方式的 http header `content-Dispositong` 值为 `attachemen` 会弹出下载窗口,而不是内部预览。 -------------------------------------------------------------------------------- /contract.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 服务条款 6 | 7 | 8 | 9 |

获取OneDrive直链 服务条款

10 |

你怎么用不关我事哈

11 | 12 | 13 | -------------------------------------------------------------------------------- /document/authentication-v8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/document/authentication-v8.png -------------------------------------------------------------------------------- /document/authentication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/document/authentication.png -------------------------------------------------------------------------------- /document/clientID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/document/clientID.png -------------------------------------------------------------------------------- /document/icon.fw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/document/icon.fw.png -------------------------------------------------------------------------------- /document/permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/document/permission.png -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/icon.png -------------------------------------------------------------------------------- /images/Image 29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/Image 29.png -------------------------------------------------------------------------------- /images/Image 30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/Image 30.png -------------------------------------------------------------------------------- /images/Image 31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/Image 31.png -------------------------------------------------------------------------------- /images/Image 32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/Image 32.png -------------------------------------------------------------------------------- /images/cloud-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/share-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-1.webp -------------------------------------------------------------------------------- /images/share-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-2.webp -------------------------------------------------------------------------------- /images/share-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-3.webp -------------------------------------------------------------------------------- /images/share-4-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-4-2.webp -------------------------------------------------------------------------------- /images/share-4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-4.webp -------------------------------------------------------------------------------- /images/share-5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-5.webp -------------------------------------------------------------------------------- /images/share-6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mapaler/GetOneDriveDirectLink/9f7632e693b18f04f184bad1ec85476b83e3a4bf/images/share-6.webp -------------------------------------------------------------------------------- /images/share-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 获取OneDrive直链 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | 19 | 20 |

获取OneDrive直链

21 |

本应用的目的是为了批量获取OneDrive直链,方便在其他站点外链。前身为提取OneDrive直链地址工具的网页版,因为原来的工具失效了,软件版也不是那么好用了,因此决定使用OneDrive官方API来进行获取,确保不失效。 22 |

23 |

隐私声明

24 |

使用微软官方API,这里不会得到你的账号密码和其他用户资料。
25 | 目前仅申请了Files.Read、Files.Read.Selected两个权限,API只会返回用户选择的文件的信息,不会获得其他内容。 26 |

27 |

使用方法

28 |
    29 |
  1. 点击从OneDrive选择文件按钮,等待打开新窗口。
  2. 30 |
  3. 第一次可能被浏览器广告拦截阻断,需要手动允许浏览器打开新窗口。
  4. 31 |
  5. 在新窗口中登陆 OneDrive 对应的账户并授予需要的权限。
  6. 32 |
  7. 进入 OneDrive “公开”文件夹内选择需要获取直链的文件(同一文件夹内可多选),点击打开。没有“公开”怎么办
  8. 33 |
  9. 选择需要输出的掩码格式,输出面板内会自动生成对应的格式。
  10. 34 |
35 |
36 |
37 |

控制面板

38 | 39 | 40 |
输出字符串模板
41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 |
▲以上掩码设置保存在浏览器本地
49 |
50 |
51 |

输出面板

52 |
53 | 54 |
55 |
56 | 57 |

F&Q

58 |
59 |
如何书写掩码?
60 |
使用 ES6 原生模板字符串 ${表达式} 书写方式。 61 | “file”表示该文件信息,“index”表示在获取列表中的序号,具体的JSON对象会在获取数据后发送到控制台(或查看全局变量 redata ),需要更多信息的的自己去看吧。
62 |
为什么要把文件放在“公开”文件夹?
63 |
新版OneDrive只有“公开”文件夹(含子文件夹)的权限才是“所有人”,其他文件夹分享必须登录才能看到,无法成功外链。
64 |
没有“公开”文件夹怎么办?
65 |
好像现在的新账号已经没有公开文件夹了。就需要麻烦点,添加访问通行证。
66 |
67 | 嵌入相册按钮 68 | 选中需要共享的文件夹,点击嵌入
69 | 点击嵌入
70 | 在右方复制authkey及其值。将来这个文件夹内的文件及子文件夹都只需要这同一个通行码。
71 | 复制authkey
72 | 如果忘记,可以点击右上角信息符号,查看共享链接
73 | 查看信息 74 |
75 |
76 | 通过共享连接获取 77 | 选中需要共享的文件夹,点击共享
78 | 点击共享
79 | 因为不希望被其他人编辑,修改权限。
80 | 编辑权限
81 | 设定为与任何人共享,仅查看,点击应用
82 | 设定权限
83 | 复制生成的共享连接
84 | 复制链接
85 | 如果忘记了复制,可以在文件夹详细信息-管理访问权限-链接可以重新获得之前生成的链接
86 | 重新找回链接
87 | 直接在地址栏访问链接
88 | 访问链接
89 | 在跳转到的新地址里复制 authkey
90 | 复制authkey
91 |
92 | 把authkey及其值加入到x外链地址掩码最后面,作为链接的参数,格式为“?authkey=xxxxxxx”
93 | 修改掩码
94 |
95 |
OneDrive窗口里如何全选?
96 |
磁贴模式下:选中第一个,拉到底下,按住Shift点击最后一个,中间的就会自动选上了。
97 |
列表模式下:点左上角那个选中全部的复选框就行了。
98 |
如何收回我授予的权限?
99 |
访问微软账户你已授予访问权限的应用和服务删除即可。
100 |
101 |

102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /privacy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 隐私声明 6 | 7 | 8 | 9 |

获取OneDrive直链 隐私声明

10 |

使用微软官方API,我这里不会得到你的账号密码和其他用户信息。
11 | 目前仅要求Files.Read、Files.Read.Selected权限,API只会返回选择的文件的信息。

12 | 13 | 14 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const curMaskVersion = 3; //当前的掩码设置版本,用于检测是否更新 2 | 3 | //↓Code from https://github.com/OneDrive/samples/tree/master/samples/file-picking/javascript-basic-consumer 4 | const baseUrl = "https://onedrive.live.com/picker"; 5 | 6 | // the options we pass to the picker page through the querystring 7 | const params = { 8 | sdk: "8.0", 9 | entry: { 10 | oneDrive: { 11 | files: {}, 12 | } 13 | }, 14 | authentication: {}, 15 | messaging: { 16 | origin: location.toString(), 17 | channelId: "27" 18 | }, 19 | typesAndSources: { 20 | mode: "files", 21 | pivots: { 22 | oneDrive: true, 23 | recent: true, 24 | }, 25 | }, 26 | selection: { 27 | mode: "multiple", 28 | enablePersistence: true, 29 | }, 30 | }; 31 | 32 | let win = null; 33 | let port = null; 34 | 35 | async function launchPicker(e) { 36 | 37 | e.preventDefault(); 38 | 39 | win = window.open("", "Picker", "width=800,height=600") 40 | 41 | const authToken = await getToken(); 42 | 43 | const queryString = new URLSearchParams({ 44 | filePicker: JSON.stringify(params), 45 | }); 46 | 47 | const url = `${baseUrl}?${queryString}`; 48 | 49 | const form = win.document.createElement("form"); 50 | form.setAttribute("action", url); 51 | form.setAttribute("method", "POST"); 52 | win.document.body.append(form); 53 | 54 | const input = win.document.createElement("input"); 55 | input.setAttribute("type", "hidden") 56 | input.setAttribute("name", "access_token"); 57 | input.setAttribute("value", authToken); 58 | form.appendChild(input); 59 | 60 | form.submit(); 61 | 62 | window.addEventListener("message", (event) => { 63 | 64 | if (event.source && event.source === win) { 65 | 66 | const message = event.data; 67 | 68 | if (message.type === "initialize" && message.channelId === params.messaging.channelId) { 69 | 70 | port = event.ports[0]; 71 | 72 | port.addEventListener("message", messageListener); 73 | 74 | port.start(); 75 | 76 | port.postMessage({ 77 | type: "activate", 78 | }); 79 | } 80 | } 81 | }); 82 | } 83 | 84 | async function messageListener(message) { 85 | switch (message.data.type) { 86 | 87 | case "notification": 88 | console.log(`notification: %o`, message.data); 89 | break; 90 | 91 | case "command": 92 | 93 | port.postMessage({ 94 | type: "acknowledge", 95 | id: message.data.id, 96 | }); 97 | 98 | const command = message.data.data; 99 | 100 | switch (command.command) { 101 | 102 | case "authenticate": 103 | 104 | // getToken is from scripts/auth.js 105 | const token = await getToken(); 106 | 107 | if (typeof token !== "undefined" && token !== null) { 108 | 109 | port.postMessage({ 110 | type: "result", 111 | id: message.data.id, 112 | data: { 113 | result: "token", 114 | token, 115 | } 116 | }); 117 | 118 | } else { 119 | console.error(`Could not get auth token for command: ${JSON.stringify(command)}`); 120 | } 121 | 122 | break; 123 | 124 | case "close": 125 | 126 | win.close(); 127 | break; 128 | 129 | case "pick": 130 | 131 | console.log(`Picked: %o`, command); 132 | 133 | redata = command.items; //存入全局数组 134 | console.log("本次返回 %d 个文件,数据为 %o", 135 | redata.length, 136 | redata 137 | ); 138 | generate_output(redata); 139 | 140 | port.postMessage({ 141 | type: "result", 142 | id: message.data.id, 143 | data: { 144 | result: "success", 145 | }, 146 | }); 147 | 148 | win.close(); 149 | 150 | break; 151 | 152 | default: 153 | 154 | console.warn(`Unsupported command: ${JSON.stringify(command)}`, 2); 155 | 156 | port.postMessage({ 157 | result: "error", 158 | error: { 159 | code: "unsupportedCommand", 160 | message: command.command 161 | }, 162 | isExpected: true, 163 | }); 164 | break; 165 | } 166 | 167 | break; 168 | } 169 | } 170 | //↑Code from OneDrive/samples 171 | 172 | class maskObj 173 | { 174 | name = ''; 175 | content = ''; 176 | constructor(name,content) //一个掩码对象 177 | { 178 | this.name = name; 179 | this.content = content; 180 | }; 181 | } 182 | 183 | const masks = []; //储存掩码数组 184 | let mask_list = null; //掩码列表框 185 | let mask_name = null; 186 | let mask_content = null; 187 | let outinfo = null; 188 | let outcontent = null; 189 | 190 | function mask_add() 191 | { 192 | if (mask_name.value.length>0 && mask_content.value.length>0) 193 | { 194 | addNewMask(mask_name.value,mask_content.value); 195 | mask_name.value = ""; 196 | mask_content.value = ""; 197 | }else 198 | { 199 | alert("掩码名或内容为空"); 200 | } 201 | mask_list.selectedIndex = mask_list.options.length - 1; 202 | save_mask_local(); 203 | } 204 | //从文本添加一个新的掩码 205 | function addNewMask(name,content) 206 | { 207 | const mask = new maskObj(name,content); 208 | masks.push(mask); 209 | const opt = new Option(name + " : " + content, content); 210 | mask_list.options.add(opt); 211 | } 212 | function mask_remove() 213 | { 214 | if(mask_list.selectedIndex>=0) 215 | { 216 | let lastSelectedIndex = mask_list.selectedIndex; 217 | masks.splice(mask_list.selectedIndex, 1); 218 | mask_list.remove(mask_list.selectedIndex); 219 | mask_list.selectedIndex = (lastSelectedIndex{ 244 | try { 245 | return JSON.parse(maskStr); 246 | } catch (e) { 247 | return null; 248 | } 249 | })(localStorage.getItem("godl-masks")); 250 | 251 | if (!Array.isArray(masksCfg) || 252 | ((parseInt(localStorage.getItem("new-mask-version"),10) || 1) < curMaskVersion) 253 | ) //没有掩码数据,初始化默认配置。 254 | { 255 | addNewMask("普通外链","http://storage.live.com/items/${file.id}:/${file.name}"); 256 | addNewMask("最短链接","http://storage.live.com/items/${file.id}"); 257 | addNewMask("UBB代码外链图片","[img]http://storage.live.com/items/${file.id}:/${file.name}[/img]"); 258 | addNewMask("模板字符串基本使用示例","在OneDrive里查看 ${file.name} 的地址是:${file.webUrl}"); 259 | addNewMask("表达式使用示例","${index+1}号文件的尺寸是:${file.size>1024?Math.round(file.size/1024)+\"K\":file.size}B"); 260 | addNewMask("自动选择img/mp3 UBB代码","[${file.image?\"img\":(file.audio?\"mp3\":\"file\")}]http://storage.live.com/items/${file.id}:/${file.name}[/${file.image?\"img\":(file.audio?\"mp3\":\"file\")}]"); 261 | addNewMask("ES6完整文件尺寸换算示例","${index+1}号文件的尺寸是:${(size=>{const bArr = [\"B\",\"KiB\",\"MiB\",\"GiB\",\"TiB\"];for(let idx=0;idx1)continue;else return (size/Math.pow(1024,idx)).toFixed(2) + \" \" + bArr[idx];}})(file.size)}"); 262 | 263 | if (Array.isArray(masksCfg)) 264 | {addNewMask("▲以上为版本更新,重新添加的掩码示例","");} 265 | localStorage.setItem("new-mask-version",curMaskVersion); 266 | }else 267 | { 268 | masksCfg.forEach(function(item){ 269 | addNewMask(item.name,item.content); 270 | }); 271 | } 272 | 273 | mask_list.selectedIndex = parseInt(localStorage.getItem("godl-mask-index"), 10) || 0; 274 | } 275 | 276 | function generate_output(files) 277 | { 278 | const mask = masks[mask_list.selectedIndex] || masks[0]; 279 | 280 | outinfo.innerHTML = "共选择 " + files.length + " 个文件。" 281 | 282 | const outStrArr = files.map((item,index)=> 283 | showMask(mask.content,item,index) 284 | ); 285 | outcontent.value = outStrArr.join("\n"); 286 | } 287 | 288 | //显示掩码用 289 | function showMask(str,file,index) { 290 | const newTxt = eval("`" + str +"`"); 291 | return newTxt; 292 | } 293 | 294 | let redata = null;//储存返回的数据 295 | 296 | window.onload = function() //网页加载初始化 297 | { 298 | mask_list = document.querySelector(".mask-list"); 299 | mask_name = document.querySelector(".mask-name"); 300 | mask_content = document.querySelector(".mask-content"); 301 | outinfo = document.querySelector(".outinfo"); 302 | outcontent = document.querySelector(".outcontent"); 303 | 304 | // if (location.protocol !="https:" && (location.hostname !="localhost" && location.hostname !="127.0.0.1") && location.hostname != "") 305 | // { 306 | // const goto = confirm("检测到你正在使用http模式,本应用要求使用https模式。\n是否自动跳转?"); 307 | // if (goto) { 308 | // location.protocol = "https:"; 309 | // } 310 | // } 311 | 312 | load_mask_local(); 313 | 314 | document.getElementById("launchPicker").onclick = launchPicker; 315 | } -------------------------------------------------------------------------------- /scripts/auth.js: -------------------------------------------------------------------------------- 1 | const msalParams = { 2 | auth: { 3 | authority: "https://login.microsoftonline.com/consumers", 4 | clientId: "d7b41a52-5bb3-43df-a20c-6259cb6a1886", 5 | redirectUri: location.toString() 6 | }, 7 | } 8 | 9 | const app = new msal.PublicClientApplication(msalParams); 10 | 11 | async function getToken() { 12 | 13 | let accessToken = ""; 14 | 15 | authParams = { scopes: ["OneDrive.ReadOnly"] }; 16 | 17 | try { 18 | 19 | // see if we have already the idtoken saved 20 | const resp = await app.acquireTokenSilent(authParams); 21 | accessToken = resp.accessToken; 22 | 23 | } catch (e) { 24 | 25 | // per examples we fall back to popup 26 | const resp = await app.loginPopup(authParams); 27 | app.setActiveAccount(resp.account); 28 | 29 | if (resp.idToken) { 30 | 31 | const resp2 = await app.acquireTokenSilent(authParams); 32 | accessToken = resp2.accessToken; 33 | 34 | } 35 | } 36 | 37 | return accessToken; 38 | } 39 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | img { 3 | border-width: 1px; 4 | border-color: black; 5 | border-style: solid; 6 | } 7 | details>summary { 8 | cursor: pointer; 9 | } 10 | details>summary:hover { 11 | background-color: #bbb; 12 | } 13 | h1 { 14 | text-align: center; 15 | } 16 | dt { 17 | font-weight: bold; 18 | background-color: rgba(0,0,0,0.2); 19 | } 20 | .splitContainer { 21 | display: grid; 22 | grid-template-columns: 1fr 2fr; 23 | } 24 | .picker 25 | { 26 | padding: 10px; 27 | padding-top: 0; 28 | background-color: rgba(200,200,200,0.5); 29 | font-size: 0.9em; 30 | } 31 | .openbtn 32 | { 33 | font-weight: bold; 34 | color: white; 35 | border: 1px solid rgb(9, 74, 178); 36 | height: 24px; 37 | padding-left: 4px; 38 | padding-right: 4px; 39 | padding-bottom: 2px; 40 | text-align: center; 41 | cursor: pointer; 42 | background-color: rgb(9, 74, 178); 43 | } 44 | .openbtn::before { 45 | content: ""; 46 | display: inline-block; 47 | width: 1em; 48 | height: 1em; 49 | background-image: url("images/cloud-white-18dp.svg"); 50 | background-size: contain; 51 | } 52 | .mask-list 53 | { 54 | width: 100%; 55 | height: 300px; 56 | margin-bottom: 5px; 57 | } 58 | .mask-bar { 59 | display: grid; 60 | grid-template-columns: 100px auto 30px 30px; 61 | gap: 3px; 62 | } 63 | .mask-add,.mask-remove 64 | { 65 | margin: 0; 66 | } 67 | .tip 68 | { 69 | font-style: italic; 70 | color: #666; 71 | } 72 | .output 73 | { 74 | padding: 10px; 75 | padding-top: 0; 76 | background-color: rgba(253,224,180,0.5); 77 | } 78 | .outinfo 79 | { 80 | height: 25px; 81 | line-height: 25px; 82 | background-color:lightblue; 83 | margin-bottom: 10px; 84 | } 85 | .outcontent 86 | { 87 | box-sizing: border-box; 88 | width: 100%; 89 | resize: vertical; 90 | height: 340px; 91 | min-height:300px; 92 | } 93 | .copyright 94 | { 95 | width: 100%; 96 | text-align: center; 97 | } --------------------------------------------------------------------------------