mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-10-10 21:13:10 +08:00
Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a295e7024a | |||
| b36eaf08f0 | |||
| bb6e520ab5 | |||
| 9b64e2e045 | |||
| ee7c12c30f | |||
| 96d6d58910 | |||
| 2bf235a5ac | |||
| 236f9969c0 | |||
| 09e63027d9 | |||
| a15dae291e | |||
| efaaeedfb8 | |||
| 190c8001a5 | |||
| b8698700ef | |||
| 985b81826f | |||
| 74d8fa3919 | |||
| 43e4928bb9 | |||
| 03580fd76c | |||
| 6e8d551420 | |||
| 28998d6f8c | |||
| 1779617cb9 | |||
| 7dfe48339c | |||
| 9c5627a382 | |||
| 809850321a | |||
| bdc1f68746 | |||
| 9aaef6c3a3 | |||
| bb50c52d0e | |||
| 6041e5a0fa | |||
| 308a86c36e | |||
| ba7c4fc230 | |||
| d81ec0637d | |||
| 1d7d37e642 | |||
| b62a716267 | |||
| 944941db10 | |||
| bd91acc5d0 | |||
| cd50227835 | |||
| 50226f66e3 | |||
| 9dcaa9b07a | |||
| fa6c0f78bc | |||
| 7f35dc6ade | |||
| 5d6463b75a | |||
| 733b38b435 | |||
| 50a02a7af7 | |||
| 71b1517de7 | |||
| ffdd88ec66 | |||
| 4ff2756572 | |||
| d955038ebc | |||
| 72d5e4e691 | |||
| b1e662cd34 | |||
| 0f0e1104a4 | |||
| 3041da35ab | |||
| 9eab54a7c8 | |||
| 0b8d3a0a2c | |||
| f9945a14a8 | |||
| c39752ceb4 | |||
| 53b383d2cf | |||
| e76fc3e616 | |||
| eb21b87020 | |||
| f577d82242 | |||
| 98691b2aa8 | |||
| 4fe6ed6c3e | |||
| fe73ece57d | |||
| 59b8f1084a | |||
| 2f669ac45c | |||
| d03d91d518 | |||
| fe981f67ec | |||
| 8cfabfd0f5 | |||
| 163ee1159e | |||
| e31402e94f | |||
| 5500980d63 | |||
| b1695445e0 | |||
| 5db1ad4adf | |||
| 725f5b0c55 | |||
| 87a74394b3 | |||
| a41c820525 | |||
| cd53dc6d24 | |||
| cfe16b5ed2 | |||
| 3d9746485d | |||
| 0b7f2fee7d | |||
| 36d52e0b75 | |||
| e4d254e4b0 | |||
| e8d27a30b4 | |||
| 69514668cc | |||
| e5f8f59c87 | |||
| f87ee1ed9e | |||
| 07155cfd01 | |||
| 5e982980dc | |||
| 8987958e26 | |||
| 4466cb19a5 | |||
| da74e29b26 | |||
| 82272fcbf5 | |||
| 74d86f8cc4 | |||
| c03646dedf | |||
| c0d1888e25 | |||
| f4942e89bd | |||
| 27e61c9eb8 | |||
| aeb72320ca | |||
| caddba05e9 |
@@ -0,0 +1,39 @@
|
||||
name: "Bug report"
|
||||
description: Bug report
|
||||
labels: [pending triage]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Alist Version / Alist 版本
|
||||
description: What version of our software are you running?
|
||||
placeholder: v2.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: Describe the bug / 问题描述
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction / 复现链接
|
||||
description: |
|
||||
Please provide a link to a repo that can reproduce the problem you ran into.
|
||||
请提供能复现此问题的链接
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: 日志 / Logs
|
||||
description: |
|
||||
Please copy and paste any relevant log output.
|
||||
请复制粘贴错误日志,或者截图
|
||||
render: shell
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions & Discussions & Feature request
|
||||
url: https://github.com/Xhofe/alist/discussions
|
||||
about: Use GitHub discussions for message-board style questions and discussions or feature request.
|
||||
@@ -45,4 +45,4 @@ jobs:
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/ppc64le,linux/s390x
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/s390x
|
||||
+1
-1
@@ -21,7 +21,7 @@ dist/
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
bin/*
|
||||
alist
|
||||
/alist
|
||||
*.json
|
||||
public/index.html
|
||||
public/assets/
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Xhofe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,43 +1,61 @@
|
||||
<h2 align="center">Alist</h2>
|
||||
<p align="center">
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/release/Xhofe/alist?style=flat-square" alt="Release version"></a>
|
||||
<div align="center">
|
||||
<h3><a href="https://alist.nn.ci">Alist</a></h3>
|
||||
<p><em>A file list program that supports multiple storage, powered by gin and React.</em></p>
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/release/Xhofe/alist?style=flat-square" alt="latest version"></a>
|
||||
<a href="https://github.com/Xhofe/alist/discussions"><img src="https://img.shields.io/github/discussions/Xhofe/alist?color=%23ED8936&style=flat-square" alt="discussions"></a>
|
||||
<a href="https://github.com/Xhofe/alist/actions?query=workflow%3ABuild"><img src="https://img.shields.io/github/workflow/status/Xhofe/alist/build?style=flat-square" alt="Build status"></a>
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/downloads/Xhofe/alist/total?style=flat-square" alt="Downloads"></a>
|
||||
<a href="https://github.com/Xhofe/alist/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Xhofe/alist?style=flat-square" alt="License"></a>
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/downloads/Xhofe/alist/total?style=flat-square&color=%239F7AEA" alt="Downloads"></a>
|
||||
<a href="https://github.com/Xhofe/alist/blob/v2/LICENSE"><img src="https://img.shields.io/github/license/Xhofe/alist?style=flat-square" alt="License"></a>
|
||||
<a href="https://pay.xhofe.top">
|
||||
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat-square" alt="donate">
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 这是什么?
|
||||
English | [中文](./README_cn.md)
|
||||
|
||||
一款支持多种存储的目录文件列表程序,后端基于`gin`,前端使用`react`。
|
||||
## Features
|
||||
|
||||
### 前端项目地址
|
||||
- [x] multiple storage
|
||||
- [x] Local storage
|
||||
- [x] [aliyundrive](https://www.aliyundrive.com/)
|
||||
- [x] OneDrive / Sharepoint ([global](https://www.office.com/), [cn](https://portal.partner.microsoftonline.cn),de,us)
|
||||
- [x] [189cloud](https://cloud.189.cn)
|
||||
- [x] [GoogleDrive](https://drive.google.com/)
|
||||
- [x] [123pan](https://www.123pan.com/)
|
||||
- [x] [lanzou](https://pc.woozooo.com/)
|
||||
- [x] File preview (PDF, markdown, code, plain text, ...)
|
||||
- [x] Image preview in gallery mode
|
||||
- [x] Video and audio preview (mp4, mp3, ...)
|
||||
- [x] Office documents preview (docx, pptx, xlsx, ...)
|
||||
- [x] `README.md` preview rendering
|
||||
- [x] File permalink copy and direct file download
|
||||
- [x] Dark mode
|
||||
- [x] I18n
|
||||
- [x] Protected routes (password protection and authentication)
|
||||
- [x] WebDav (readonly)
|
||||
- [x] [Docker Deploy](https://hub.docker.com/r/xhofe/alist)
|
||||
|
||||
- https://github.com/Xhofe/alist-web
|
||||
## Discussion
|
||||
|
||||
### 演示地址
|
||||
Please go to our [discussion forum](https://github.com/Xhofe/alist/discussions) for general questions, **issues are for bug reports only.**
|
||||
|
||||
- https://alist.nn.ci
|
||||
## Demo
|
||||
|
||||
### 预览
|
||||
Available at: <https://alist.nn.ci>.
|
||||
|
||||
<a href="https://alist.nn.ci/"><img src="https://store.heytapimage.com/cdo-portal/feedback/202111/03/695ef77854a144e928518efde38db97a.png"></a>
|
||||

|
||||
|
||||
### 支持的存储
|
||||
## Document
|
||||
|
||||
- 本地存储
|
||||
- 阿里云盘
|
||||
- Onedrive/世纪互联
|
||||
- ...
|
||||
<https://alist-doc.nn.ci/en/>
|
||||
|
||||
### 如何使用
|
||||
## License
|
||||
|
||||
- https://www.nn.ci/archives/alist.html
|
||||
The `AList` is open-source software licensed under the MIT license.
|
||||
|
||||
### License
|
||||
---
|
||||
|
||||
The `AList` is open-source software licensed under the MIT license.
|
||||
> [@Blog](https://www.nn.ci/) · [@GitHub](https://github.com/Xhofe)
|
||||
@@ -0,0 +1,60 @@
|
||||
<div align="center">
|
||||
<h3><a href="https://alist.nn.ci">Alist</a></h3>
|
||||
<p><em>一个支持多存储的文件列表程序,使用 gin 和 React 。</em></p>
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/release/Xhofe/alist?style=flat-square" alt="latest version"></a>
|
||||
<a href="https://github.com/Xhofe/alist/discussions"><img src="https://img.shields.io/github/discussions/Xhofe/alist?color=%23ED8936&style=flat-square" alt="discussions"></a>
|
||||
<a href="https://github.com/Xhofe/alist/actions?query=workflow%3ABuild"><img src="https://img.shields.io/github/workflow/status/Xhofe/alist/build?style=flat-square" alt="Build status"></a>
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/downloads/Xhofe/alist/total?style=flat-square&color=%239F7AEA" alt="Downloads"></a>
|
||||
<a href="https://github.com/Xhofe/alist/blob/v2/LICENSE"><img src="https://img.shields.io/github/license/Xhofe/alist?style=flat-square" alt="License"></a>
|
||||
<a href="https://pay.xhofe.top">
|
||||
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat-square" alt="donate">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[English](./README.md) | 中文
|
||||
|
||||
## 支持
|
||||
|
||||
- [x] 多种存储
|
||||
- [x] 本地存储
|
||||
- [x] [阿里云盘](https://www.aliyundrive.com/)
|
||||
- [x] OneDrive / Sharepoint([国际版](https://www.office.com/), [世纪互联](https://portal.partner.microsoftonline.cn),de,us)
|
||||
- [x] [天翼云盘](https://cloud.189.cn)
|
||||
- [x] [GoogleDrive](https://drive.google.com/)
|
||||
- [x] [123云盘](https://www.123pan.com/)
|
||||
- [x] [蓝奏云](https://pc.woozooo.com/)
|
||||
- [x] 文件预览(PDF、markdown、代码、纯文本……)
|
||||
- [x] 画廊模式下的图像预览
|
||||
- [x] 视频和音频预览(mp4、mp3 等)
|
||||
- [x] Office 文档预览(docx、pptx、xlsx、...)
|
||||
- [x] `README.md` 预览渲染
|
||||
- [x] 文件永久链接复制和直接文件下载
|
||||
- [x] 黑暗模式
|
||||
- [x] 国际化
|
||||
- [x] 受保护的路由(密码保护和身份验证)
|
||||
- [x] WebDav(只读)
|
||||
- [x] [Docker 部署](https://hub.docker.com/r/xhofe/alist)
|
||||
|
||||
## 讨论
|
||||
|
||||
一般问题请到[讨论论坛](https://github.com/Xhofe/alist/discussions) ,**issue仅针对错误报告。**
|
||||
|
||||
## 演示
|
||||
|
||||
<https://alist.nn.ci>。
|
||||
|
||||

|
||||
|
||||
## 文档
|
||||
|
||||
<https://alist-doc.nn.ci/>
|
||||
|
||||
## 许可
|
||||
|
||||
`AList` 是在 MIT 许可下许可的开源软件。
|
||||
|
||||
---
|
||||
|
||||
> [@Blog](https://www.nn.ci/) · [@GitHub](https://github.com/Xhofe)
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
const HOST = "YOUR_HOST";
|
||||
const TOKEN = "YOUR_TOKEN";
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
};
|
||||
|
||||
!function(a){"use strict";function b(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c}function c(a,b){return a<<b|a>>>32-b}function d(a,d,e,f,g,h){return b(c(b(b(d,a),b(f,h)),g),e)}function e(a,b,c,e,f,g,h){return d(b&c|~b&e,a,b,f,g,h)}function f(a,b,c,e,f,g,h){return d(b&e|c&~e,a,b,f,g,h)}function g(a,b,c,e,f,g,h){return d(b^c^e,a,b,f,g,h)}function h(a,b,c,e,f,g,h){return d(c^(b|~e),a,b,f,g,h)}function i(a,c){a[c>>5]|=128<<c%32,a[(c+64>>>9<<4)+14]=c;var d,i,j,k,l,m=1732584193,n=-271733879,o=-1732584194,p=271733878;for(d=0;d<a.length;d+=16)i=m,j=n,k=o,l=p,m=e(m,n,o,p,a[d],7,-680876936),p=e(p,m,n,o,a[d+1],12,-389564586),o=e(o,p,m,n,a[d+2],17,606105819),n=e(n,o,p,m,a[d+3],22,-1044525330),m=e(m,n,o,p,a[d+4],7,-176418897),p=e(p,m,n,o,a[d+5],12,1200080426),o=e(o,p,m,n,a[d+6],17,-1473231341),n=e(n,o,p,m,a[d+7],22,-45705983),m=e(m,n,o,p,a[d+8],7,1770035416),p=e(p,m,n,o,a[d+9],12,-1958414417),o=e(o,p,m,n,a[d+10],17,-42063),n=e(n,o,p,m,a[d+11],22,-1990404162),m=e(m,n,o,p,a[d+12],7,1804603682),p=e(p,m,n,o,a[d+13],12,-40341101),o=e(o,p,m,n,a[d+14],17,-1502002290),n=e(n,o,p,m,a[d+15],22,1236535329),m=f(m,n,o,p,a[d+1],5,-165796510),p=f(p,m,n,o,a[d+6],9,-1069501632),o=f(o,p,m,n,a[d+11],14,643717713),n=f(n,o,p,m,a[d],20,-373897302),m=f(m,n,o,p,a[d+5],5,-701558691),p=f(p,m,n,o,a[d+10],9,38016083),o=f(o,p,m,n,a[d+15],14,-660478335),n=f(n,o,p,m,a[d+4],20,-405537848),m=f(m,n,o,p,a[d+9],5,568446438),p=f(p,m,n,o,a[d+14],9,-1019803690),o=f(o,p,m,n,a[d+3],14,-187363961),n=f(n,o,p,m,a[d+8],20,1163531501),m=f(m,n,o,p,a[d+13],5,-1444681467),p=f(p,m,n,o,a[d+2],9,-51403784),o=f(o,p,m,n,a[d+7],14,1735328473),n=f(n,o,p,m,a[d+12],20,-1926607734),m=g(m,n,o,p,a[d+5],4,-378558),p=g(p,m,n,o,a[d+8],11,-2022574463),o=g(o,p,m,n,a[d+11],16,1839030562),n=g(n,o,p,m,a[d+14],23,-35309556),m=g(m,n,o,p,a[d+1],4,-1530992060),p=g(p,m,n,o,a[d+4],11,1272893353),o=g(o,p,m,n,a[d+7],16,-155497632),n=g(n,o,p,m,a[d+10],23,-1094730640),m=g(m,n,o,p,a[d+13],4,681279174),p=g(p,m,n,o,a[d],11,-358537222),o=g(o,p,m,n,a[d+3],16,-722521979),n=g(n,o,p,m,a[d+6],23,76029189),m=g(m,n,o,p,a[d+9],4,-640364487),p=g(p,m,n,o,a[d+12],11,-421815835),o=g(o,p,m,n,a[d+15],16,530742520),n=g(n,o,p,m,a[d+2],23,-995338651),m=h(m,n,o,p,a[d],6,-198630844),p=h(p,m,n,o,a[d+7],10,1126891415),o=h(o,p,m,n,a[d+14],15,-1416354905),n=h(n,o,p,m,a[d+5],21,-57434055),m=h(m,n,o,p,a[d+12],6,1700485571),p=h(p,m,n,o,a[d+3],10,-1894986606),o=h(o,p,m,n,a[d+10],15,-1051523),n=h(n,o,p,m,a[d+1],21,-2054922799),m=h(m,n,o,p,a[d+8],6,1873313359),p=h(p,m,n,o,a[d+15],10,-30611744),o=h(o,p,m,n,a[d+6],15,-1560198380),n=h(n,o,p,m,a[d+13],21,1309151649),m=h(m,n,o,p,a[d+4],6,-145523070),p=h(p,m,n,o,a[d+11],10,-1120210379),o=h(o,p,m,n,a[d+2],15,718787259),n=h(n,o,p,m,a[d+9],21,-343485551),m=b(m,i),n=b(n,j),o=b(o,k),p=b(p,l);return[m,n,o,p]}function j(a){var b,c="";for(b=0;b<32*a.length;b+=8)c+=String.fromCharCode(a[b>>5]>>>b%32&255);return c}function k(a){var b,c=[];for(c[(a.length>>2)-1]=void 0,b=0;b<c.length;b+=1)c[b]=0;for(b=0;b<8*a.length;b+=8)c[b>>5]|=(255&a.charCodeAt(b/8))<<b%32;return c}function l(a){return j(i(k(a),8*a.length))}function m(a,b){var c,d,e=k(a),f=[],g=[];for(f[15]=g[15]=void 0,e.length>16&&(e=i(e,8*a.length)),c=0;16>c;c+=1)f[c]=909522486^e[c],g[c]=1549556828^e[c];return d=i(f.concat(k(b)),512+8*b.length),j(i(g.concat(d),640))}function n(a){var b,c,d="0123456789abcdef",e="";for(c=0;c<a.length;c+=1)b=a.charCodeAt(c),e+=d.charAt(b>>>4&15)+d.charAt(15&b);return e}function o(a){return unescape(encodeURIComponent(a))}function p(a){return l(o(a))}function q(a){return n(p(a))}function r(a,b){return m(o(a),o(b))}function s(a,b){return n(r(a,b))}function t(a,b,c){return b?c?r(b,a):s(b,a):c?p(a):q(a)}"function"==typeof define&&define.amd?define(function(){return t}):a.md5=t}(this);
|
||||
|
||||
async function handleRequest(request) {
|
||||
const origin = request.headers.get("origin");
|
||||
const url = new URL(request.url);
|
||||
const path = url.pathname;
|
||||
const sign = url.searchParams.get("sign");
|
||||
const name = path.split("/").pop();
|
||||
const right = md5(`alist-${TOKEN}-${name}`).slice(8, 24);
|
||||
if (sign !== right){
|
||||
const resp = new Response(
|
||||
JSON.stringify({
|
||||
code: 401,
|
||||
message: `sign mismatch`,
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/json;charset=UTF-8",
|
||||
},
|
||||
}
|
||||
);
|
||||
resp.headers.set("Access-Control-Allow-Origin", origin);
|
||||
return resp;
|
||||
}
|
||||
|
||||
let resp = await fetch(`${HOST}/api/admin/link`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json;charset=UTF-8",
|
||||
Authorization: TOKEN,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
path: decodeURI(path),
|
||||
}),
|
||||
});
|
||||
let res = await resp.json();
|
||||
if (res.code !== 200) {
|
||||
return new Response(JSON.stringify(res));
|
||||
}
|
||||
request = new Request(res.data.url, request);
|
||||
if (res.data.headers) {
|
||||
for(const header of res.data.headers){
|
||||
request.headers.set(header.name, header.value);
|
||||
}
|
||||
}
|
||||
let response = await fetch(request);
|
||||
|
||||
// Recreate the response so we can modify the headers
|
||||
response = new Response(response.body, response);
|
||||
|
||||
// Set CORS headers
|
||||
response.headers.set("Access-Control-Allow-Origin", origin);
|
||||
|
||||
// Append to/Add Vary header so browser will cache response correctly
|
||||
response.headers.append("Vary", "Origin");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
function handleOptions(request) {
|
||||
// Make sure the necessary headers are present
|
||||
// for this to be a valid pre-flight request
|
||||
let headers = request.headers;
|
||||
if (
|
||||
headers.get("Origin") !== null &&
|
||||
headers.get("Access-Control-Request-Method") !== null
|
||||
// && headers.get("Access-Control-Request-Headers") !== null
|
||||
) {
|
||||
// Handle CORS pre-flight request.
|
||||
// If you want to check or reject the requested method + headers
|
||||
// you can do that here.
|
||||
let respHeaders = {
|
||||
...corsHeaders,
|
||||
// Allow all future content Request headers to go back to browser
|
||||
// such as Authorization (Bearer) or X-Client-Name-Version
|
||||
"Access-Control-Allow-Headers": request.headers.get(
|
||||
"Access-Control-Request-Headers"
|
||||
),
|
||||
};
|
||||
|
||||
return new Response(null, {
|
||||
headers: respHeaders,
|
||||
});
|
||||
} else {
|
||||
// Handle standard OPTIONS request.
|
||||
// If you want to allow other HTTP Methods, you can do that here.
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
Allow: "GET, HEAD, POST, OPTIONS",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("fetch", (event) => {
|
||||
const request = event.request;
|
||||
// const url = new URL(request.url)
|
||||
if (request.method === "OPTIONS") {
|
||||
// Handle CORS preflight requests
|
||||
event.respondWith(handleOptions(request));
|
||||
} else if (
|
||||
request.method === "GET" ||
|
||||
request.method === "HEAD" ||
|
||||
request.method === "POST"
|
||||
) {
|
||||
// Handle requests to the API server
|
||||
event.respondWith(handleRequest(request));
|
||||
} else {
|
||||
event.respondWith(
|
||||
new Response(null, {
|
||||
status: 405,
|
||||
statusText: "Method Not Allowed",
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1,28 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/bootstrap"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
_ "github.com/Xhofe/alist/drivers"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/server"
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&conf.ConfigFile, "conf", "data/config.json", "config file")
|
||||
flag.BoolVar(&conf.Debug, "debug", false, "start with debug mode")
|
||||
flag.BoolVar(&conf.Version, "version", false, "print version info")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func Init() {
|
||||
bootstrap.InitLog()
|
||||
func Init() bool {
|
||||
//bootstrap.InitLog()
|
||||
bootstrap.InitConf()
|
||||
bootstrap.InitCron()
|
||||
bootstrap.InitModel()
|
||||
if conf.Password {
|
||||
pass, err := model.GetSettingByKey("password")
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return false
|
||||
}
|
||||
log.Infof("current password: %s", pass.Value)
|
||||
return false
|
||||
}
|
||||
bootstrap.InitSettings()
|
||||
bootstrap.InitAccounts()
|
||||
bootstrap.InitCache()
|
||||
return true
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -30,15 +36,22 @@ func main() {
|
||||
fmt.Printf("Built At: %s\nGo Version: %s\nAuthor: %s\nCommit ID: %s\nVersion: %s\n", conf.BuiltAt, conf.GoVersion, conf.GitAuthor, conf.GitCommit, conf.GitTag)
|
||||
return
|
||||
}
|
||||
Init()
|
||||
if !Init() {
|
||||
return
|
||||
}
|
||||
if !conf.Debug {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
r := gin.Default()
|
||||
server.InitApiRouter(r)
|
||||
|
||||
log.Info("starting server")
|
||||
err := r.Run(fmt.Sprintf("%s:%d", conf.Conf.Address, conf.Conf.Port))
|
||||
base := fmt.Sprintf("%s:%d", conf.Conf.Address, conf.Conf.Port)
|
||||
log.Infof("start server @ %s", base)
|
||||
var err error
|
||||
if conf.Conf.Https {
|
||||
err = r.RunTLS(base, conf.Conf.CertFile, conf.Conf.KeyFile)
|
||||
} else {
|
||||
err = r.Run(base)
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("failed to start: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/drivers/base"
|
||||
"github.com/Xhofe/alist/model"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func InitAccounts() {
|
||||
log.Infof("init accounts...")
|
||||
var accounts []model.Account
|
||||
if err := conf.DB.Find(&accounts).Error; err != nil {
|
||||
log.Fatalf("failed sync init accounts")
|
||||
}
|
||||
for i, account := range accounts {
|
||||
model.RegisterAccount(account)
|
||||
driver, ok := base.GetDriver(account.Type)
|
||||
if !ok {
|
||||
log.Errorf("no [%s] driver", account.Type)
|
||||
} else {
|
||||
err := driver.Save(&accounts[i], nil)
|
||||
if err != nil {
|
||||
log.Errorf("init account [%s] error:[%s]", account.Name, err.Error())
|
||||
} else {
|
||||
log.Infof("success init account: %s, type: %s", account.Name, account.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -1,11 +1,12 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// initLog init log
|
||||
// InitLog init log
|
||||
func InitLog() {
|
||||
if conf.Debug {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
@@ -18,4 +19,14 @@ func InitLog() {
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
FullTimestamp: true,
|
||||
})
|
||||
log.Infof("init log...")
|
||||
}
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&conf.ConfigFile, "conf", "data/config.json", "config file")
|
||||
flag.BoolVar(&conf.Debug, "debug", false, "start with debug mode")
|
||||
flag.BoolVar(&conf.Version, "version", false, "print version info")
|
||||
flag.BoolVar(&conf.Password, "password", false, "print current password")
|
||||
flag.Parse()
|
||||
InitLog()
|
||||
}
|
||||
+1
-153
@@ -3,7 +3,6 @@ package bootstrap
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/drivers"
|
||||
"github.com/Xhofe/alist/model"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/driver/mysql"
|
||||
@@ -72,161 +71,10 @@ func InitModel() {
|
||||
default:
|
||||
log.Fatalf("not supported database type: %s", databaseConfig.Type)
|
||||
}
|
||||
log.Infof("auto migrate model")
|
||||
log.Infof("auto migrate model...")
|
||||
err := conf.DB.AutoMigrate(&model.SettingItem{}, &model.Account{}, &model.Meta{})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to auto migrate")
|
||||
}
|
||||
|
||||
// TODO init filetype
|
||||
initAccounts()
|
||||
initSettings()
|
||||
}
|
||||
|
||||
func initAccounts() {
|
||||
log.Infof("init accounts...")
|
||||
var accounts []model.Account
|
||||
if err := conf.DB.Find(&accounts).Error; err != nil {
|
||||
log.Fatalf("failed sync init accounts")
|
||||
}
|
||||
for _, account := range accounts {
|
||||
model.RegisterAccount(account)
|
||||
driver, ok := drivers.GetDriver(account.Type)
|
||||
if !ok {
|
||||
log.Errorf("no [%s] driver", driver)
|
||||
} else {
|
||||
err := driver.Save(&account, nil)
|
||||
if err != nil {
|
||||
log.Errorf("init account [%s] error:[%s]", account.Name, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initSettings() {
|
||||
log.Infof("init settings...")
|
||||
version := model.SettingItem{
|
||||
Key: "version",
|
||||
Value: conf.GitTag,
|
||||
Description: "version",
|
||||
Type: "string",
|
||||
Group: model.CONST,
|
||||
}
|
||||
|
||||
_ = model.SaveSetting(version)
|
||||
|
||||
settings := []model.SettingItem{
|
||||
{
|
||||
Key: "title",
|
||||
Value: "Alist",
|
||||
Description: "title",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "password",
|
||||
Value: "alist",
|
||||
Description: "password",
|
||||
Type: "string",
|
||||
Group: model.PRIVATE,
|
||||
},
|
||||
{
|
||||
Key: "logo",
|
||||
Value: "https://store.heytapimage.com/cdo-portal/feedback/202110/30/d43c41c5d257c9bc36366e310374fb19.png",
|
||||
Description: "logo",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "favicon",
|
||||
Value: "https://store.heytapimage.com/cdo-portal/feedback/202110/30/d43c41c5d257c9bc36366e310374fb19.png",
|
||||
Description: "favicon",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "icon color",
|
||||
Value: "teal.300",
|
||||
Description: "icon's color",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "text types",
|
||||
Value: "txt,htm,html,xml,java,properties,sql,js,md,json,conf,ini,vue,php,py,bat,gitignore,yml,go,sh,c,cpp,h,hpp",
|
||||
Type: "string",
|
||||
Description: "text type extensions",
|
||||
},
|
||||
{
|
||||
Key: "hide readme file",
|
||||
Value: "true",
|
||||
Type: "bool",
|
||||
Description: "hide readme file? ",
|
||||
},
|
||||
{
|
||||
Key: "music cover",
|
||||
Value: "https://store.heytapimage.com/cdo-portal/feedback/202110/30/d43c41c5d257c9bc36366e310374fb19.png",
|
||||
Description: "music cover image",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "site beian",
|
||||
Description: "chinese beian info",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "home readme url",
|
||||
Description: "when have multiple, the readme file to show",
|
||||
Type: "string",
|
||||
Group: model.PUBLIC,
|
||||
},
|
||||
{
|
||||
Key: "markdown theme",
|
||||
Value: "vuepress",
|
||||
Description: "default | github | vuepress",
|
||||
Group: model.PUBLIC,
|
||||
Type: "select",
|
||||
Values: "default,github,vuepress",
|
||||
},
|
||||
{
|
||||
Key: "autoplay video",
|
||||
Value: "false",
|
||||
Type: "bool",
|
||||
},
|
||||
{
|
||||
Key: "autoplay audio",
|
||||
Value: "false",
|
||||
Type: "bool",
|
||||
},
|
||||
{
|
||||
Key: "check parent folder",
|
||||
Value: "false",
|
||||
Type: "bool",
|
||||
Description: "check parent folder password",
|
||||
},
|
||||
{
|
||||
Key: "customize style",
|
||||
Value: "",
|
||||
Type: "text",
|
||||
Description: "customize style, don't need add <style></style>",
|
||||
},
|
||||
{
|
||||
Key: "customize script",
|
||||
Value: "",
|
||||
Type: "text",
|
||||
Description: "customize script, don't need add <script></script>",
|
||||
},
|
||||
}
|
||||
for _, v := range settings {
|
||||
_, err := model.GetSettingByKey(v.Key)
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
err = model.SaveSetting(v)
|
||||
if err != nil {
|
||||
log.Fatalf("failed write setting: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
model.LoadSettings()
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+3
-4
@@ -14,6 +14,9 @@ type Config struct {
|
||||
Address string `json:"address"`
|
||||
Port int `json:"port"`
|
||||
Database Database `json:"database"`
|
||||
Https bool `json:"https"`
|
||||
CertFile string `json:"cert_file"`
|
||||
KeyFile string `json:"key_file"`
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
@@ -22,11 +25,7 @@ func DefaultConfig() *Config {
|
||||
Port: 5244,
|
||||
Database: Database{
|
||||
Type: "sqlite3",
|
||||
User: "",
|
||||
Password: "",
|
||||
Host: "",
|
||||
Port: 0,
|
||||
Name: "",
|
||||
TablePrefix: "x_",
|
||||
DBFile: "data/data.db",
|
||||
},
|
||||
|
||||
+11
-8
@@ -12,7 +12,7 @@ var (
|
||||
GoVersion string
|
||||
GitAuthor string
|
||||
GitCommit string
|
||||
GitTag string
|
||||
GitTag string = "dev"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,6 +20,7 @@ var (
|
||||
Conf *Config
|
||||
Debug bool
|
||||
Version bool
|
||||
Password bool
|
||||
|
||||
DB *gorm.DB
|
||||
Cache *cache.Cache
|
||||
@@ -30,17 +31,19 @@ var (
|
||||
var (
|
||||
TextTypes = []string{"txt", "go", "md"}
|
||||
OfficeTypes = []string{"doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"}
|
||||
VideoTypes = []string{"mp4", "mkv", "avi", "mov", "rmvb"}
|
||||
VideoTypes = []string{"mp4", "mkv", "avi", "mov", "rmvb", "webm"}
|
||||
AudioTypes = []string{"mp3", "flac", "ogg", "m4a"}
|
||||
ImageTypes = []string{"jpg", "tiff", "jpeg", "png", "gif", "bmp", "svg"}
|
||||
)
|
||||
|
||||
// settings
|
||||
var (
|
||||
RawIndexHtml string
|
||||
IndexHtml string
|
||||
CheckParent bool
|
||||
//CustomizeStyle string
|
||||
//CustomizeScript string
|
||||
//Favicon string
|
||||
RawIndexHtml string
|
||||
IndexHtml string
|
||||
CheckParent bool
|
||||
CheckDown bool
|
||||
|
||||
Token string
|
||||
DavUsername string
|
||||
DavPassword string
|
||||
)
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package _23
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/drivers/base"
|
||||
"github.com/Xhofe/alist/model"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var pan123Client = resty.New()
|
||||
|
||||
type Pan123TokenResp struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Token string `json:"token"`
|
||||
} `json:"data"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type Pan123File struct {
|
||||
FileName string `json:"FileName"`
|
||||
Size int64 `json:"Size"`
|
||||
UpdateAt *time.Time `json:"UpdateAt"`
|
||||
FileId int64 `json:"FileId"`
|
||||
Type int `json:"Type"`
|
||||
Etag string `json:"Etag"`
|
||||
S3KeyFlag string `json:"S3KeyFlag"`
|
||||
}
|
||||
|
||||
type Pan123Files struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
InfoList []Pan123File `json:"InfoList"`
|
||||
Next string `json:"Next"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type Pan123DownResp struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
DownloadUrl string `json:"DownloadUrl"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (driver Pan123) Login(account *model.Account) error {
|
||||
var resp Pan123TokenResp
|
||||
_, err := pan123Client.R().
|
||||
SetResult(&resp).
|
||||
SetBody(base.Json{
|
||||
"passport": account.Username,
|
||||
"password": account.Password,
|
||||
}).Post("https://www.123pan.com/api/user/sign_in")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Code != 200 {
|
||||
err = fmt.Errorf(resp.Message)
|
||||
account.Status = resp.Message
|
||||
} else {
|
||||
account.Status = "work"
|
||||
account.AccessToken = resp.Data.Token
|
||||
}
|
||||
_ = model.SaveAccount(account)
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver Pan123) FormatFile(file *Pan123File) *model.File {
|
||||
f := &model.File{
|
||||
Id: strconv.FormatInt(file.FileId, 10),
|
||||
Name: file.FileName,
|
||||
Size: file.Size,
|
||||
Driver: driver.Config().Name,
|
||||
UpdatedAt: file.UpdateAt,
|
||||
}
|
||||
if file.Type == 1 {
|
||||
f.Type = conf.FOLDER
|
||||
} else {
|
||||
f.Type = utils.GetFileType(filepath.Ext(file.FileName))
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func (driver Pan123) GetFiles(parentId string, account *model.Account) ([]Pan123File, error) {
|
||||
next := "0"
|
||||
res := make([]Pan123File, 0)
|
||||
for next != "-1" {
|
||||
var resp Pan123Files
|
||||
_, err := pan123Client.R().SetResult(&resp).
|
||||
SetHeader("authorization", "Bearer "+account.AccessToken).
|
||||
SetQueryParams(map[string]string{
|
||||
"driveId": "0",
|
||||
"limit": "100",
|
||||
"next": next,
|
||||
"orderBy": account.OrderBy,
|
||||
"orderDirection": account.OrderDirection,
|
||||
"parentFileId": parentId,
|
||||
"trashed": "false",
|
||||
}).Get("https://www.123pan.com/api/file/list")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Code != 0 {
|
||||
if resp.Code == 401 {
|
||||
err := driver.Login(account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return driver.GetFiles(parentId, account)
|
||||
}
|
||||
return nil, fmt.Errorf(resp.Message)
|
||||
}
|
||||
next = resp.Data.Next
|
||||
res = append(res, resp.Data.InfoList...)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (driver Pan123) GetFile(path string, account *model.Account) (*Pan123File, error) {
|
||||
dir, name := filepath.Split(path)
|
||||
dir = utils.ParsePath(dir)
|
||||
_, err := driver.Files(dir, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parentFiles_, _ := base.GetCache(dir, account)
|
||||
parentFiles, _ := parentFiles_.([]Pan123File)
|
||||
for _, file := range parentFiles {
|
||||
if file.FileName == name {
|
||||
if file.Type != conf.FOLDER {
|
||||
return &file, err
|
||||
} else {
|
||||
return nil, base.ErrNotFile
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, base.ErrPathNotFound
|
||||
}
|
||||
|
||||
func init() {
|
||||
base.RegisterDriver(&Pan123{})
|
||||
pan123Client.SetRetryCount(3)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user