Compare commits
160 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8472e767b | ||
|
|
8700cb30ff | ||
|
|
93c4b2e03c | ||
|
|
2d1a82b73f | ||
|
|
5a07291306 | ||
|
|
09f679fae4 | ||
|
|
9e273cd947 | ||
|
|
77d266bc00 | ||
|
|
8861933cf8 | ||
|
|
a5ea2a266b | ||
|
|
f5e531c8ae | ||
|
|
6072540c3e | ||
|
|
464b644adf | ||
|
|
089255997a | ||
|
|
5331969163 | ||
|
|
f32f27383d | ||
|
|
0acd69c537 | ||
|
|
ae4fb0ea25 | ||
|
|
8230eb7ab5 | ||
|
|
8b8fb3343f | ||
|
|
1d494ff315 | ||
|
|
da03728cd7 | ||
|
|
e735491c57 | ||
|
|
4d830f707f | ||
|
|
f84a6db680 | ||
|
|
a430eb2e60 | ||
|
|
c232d41f90 | ||
|
|
c1e4fd648b | ||
|
|
d5b39a14fd | ||
|
|
e2e1e49130 | ||
|
|
b0f92dd2d7 | ||
|
|
21b0827808 | ||
|
|
d6d84e2b48 | ||
|
|
ca86f91621 | ||
|
|
4bfbf33249 | ||
|
|
f19943a42e | ||
|
|
e74c958862 | ||
|
|
221451a517 | ||
|
|
f46641b038 | ||
|
|
23bd8f6715 | ||
|
|
506fc08577 | ||
|
|
f33076462a | ||
|
|
6c29fabdc8 | ||
|
|
0268506f80 | ||
|
|
ad864a97e9 | ||
|
|
f714e71a35 | ||
|
|
dbdbbab4d7 | ||
|
|
7c0c7820ef | ||
|
|
2741616473 | ||
|
|
ffb858e4ef | ||
|
|
0ca8059d8d | ||
|
|
8ca080422f | ||
|
|
cbb712484d | ||
|
|
8a14018861 | ||
|
|
a493ec90ff | ||
|
|
33113036cd | ||
|
|
a02b2972eb | ||
|
|
e9bb3dc243 | ||
|
|
2e26393a02 | ||
|
|
04a13f086f | ||
|
|
1cc539eb8a | ||
|
|
6ebfdcceaa | ||
|
|
db671c227b | ||
|
|
4aee14de44 | ||
|
|
0cca7d8dc0 | ||
|
|
c34c0afecf | ||
|
|
56a0f9244b | ||
|
|
56b80b6d9b | ||
|
|
d9ebd65ffc | ||
|
|
a882fb6c85 | ||
|
|
5daae69a6d | ||
|
|
54a1ae0fa0 | ||
|
|
b6b4fb5da7 | ||
|
|
6d82a27f9a | ||
|
|
31a326606d | ||
|
|
abbf203bdd | ||
|
|
e82e2392a4 | ||
|
|
f4a8420bf3 | ||
|
|
71a8f5662c | ||
|
|
48f894740f | ||
|
|
b883e287a0 | ||
|
|
5d9f0977d6 | ||
|
|
c606a01a2d | ||
|
|
54b91b8ff0 | ||
|
|
a46acba5f9 | ||
|
|
1d14798653 | ||
|
|
6d55cc59f7 | ||
|
|
495e731ee7 | ||
|
|
ff1579b950 | ||
|
|
7a48fd0c3e | ||
|
|
cfea84fd5e | ||
|
|
0ba9505a19 | ||
|
|
5355629fd1 | ||
|
|
f8a16a6aca | ||
|
|
35d1c09243 | ||
|
|
99c64c12ed | ||
|
|
3d6c5152fe | ||
|
|
ba797cda31 | ||
|
|
5300d00d2e | ||
|
|
bbdd313705 | ||
|
|
045064f8b8 | ||
|
|
252f0a7533 | ||
|
|
1194cfe009 | ||
|
|
0201f9c5c4 | ||
|
|
cc331383fb | ||
|
|
d1c84a8412 | ||
|
|
e92dbb4bb8 | ||
|
|
209acf2429 | ||
|
|
25372edb5c | ||
|
|
d51a343820 | ||
|
|
065959451d | ||
|
|
2fdea73430 | ||
|
|
129a4fd39d | ||
|
|
64400ffda8 | ||
|
|
03d74ee758 | ||
|
|
2b37e696c9 | ||
|
|
21d5ee1b97 | ||
|
|
ec7b643e8e | ||
|
|
d729701bd4 | ||
|
|
406d4f7884 | ||
|
|
1e7c41505f | ||
|
|
bb5d192095 | ||
|
|
121d9abecd | ||
|
|
7de6bc4a91 | ||
|
|
2369e5c0ed | ||
|
|
056cfa8fac | ||
|
|
e7d77106ab | ||
|
|
a6347c8858 | ||
|
|
b596567c61 | ||
|
|
364fdaaf0c | ||
|
|
8b75aefb1c | ||
|
|
b0f4604f44 | ||
|
|
f6f7e5fea3 | ||
|
|
043cdbf402 | ||
|
|
8e67a12f26 | ||
|
|
83898d616f | ||
|
|
090272e3b7 | ||
|
|
10bf3cffbf | ||
|
|
99a6382b32 | ||
|
|
a53aac1c30 | ||
|
|
21783ed91a | ||
|
|
7be5644952 | ||
|
|
30a8ddf113 | ||
|
|
c3465f9913 | ||
|
|
e8589be640 | ||
|
|
eb3978ea55 | ||
|
|
d6cdf0e435 | ||
|
|
1fccc5d649 | ||
|
|
a8388689f3 | ||
|
|
2a90cdfdaf | ||
|
|
6ca3d5a573 | ||
|
|
3b48f75301 | ||
|
|
4c5b612cb2 | ||
|
|
e336a25ad2 | ||
|
|
c9e05f98c4 | ||
|
|
be62f56782 | ||
|
|
2e47a038d6 | ||
|
|
a9c327cc06 | ||
|
|
782375b1cb | ||
|
|
5d5e8ed422 |
@@ -1,5 +1,7 @@
|
||||
*
|
||||
!docker/*
|
||||
!healthcheck.sh
|
||||
!docker_config.json
|
||||
!filebrowser
|
||||
.venv
|
||||
dist
|
||||
.idea
|
||||
frontend/node_modules
|
||||
frontend/dist
|
||||
filebrowser.db
|
||||
docs/index.md
|
||||
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -2,4 +2,4 @@
|
||||
# Unless a later match takes precedence, @o1egl will be requested for
|
||||
# review when someone opens a pull request.
|
||||
|
||||
* @o1egl
|
||||
* @o1egl @hacdias
|
||||
|
||||
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
---
|
||||
|
||||
**Description**
|
||||
<!-- A clear and concise description of what the issue is about. What are you trying to do? -->
|
||||
|
||||
**Expected behaviour**
|
||||
<!-- What did you expect to happen? -->
|
||||
|
||||
**What is happening instead?**
|
||||
<!-- Please, give full error messages and/or log. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**How to reproduce?**
|
||||
<!-- Tell us how to reproduce this issue. How can someone who is starting from scratch reproduce this behaviour as minimally as possible? -->
|
||||
|
||||
**Files**
|
||||
<!-- A list of relevant files for this issue. Large files can be uploaded one-by-one or in a tarball/zipfile. -->
|
||||
43
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
43
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Bug Report
|
||||
description: Report a bug in FileBrowser.
|
||||
labels: [bug, triage]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please verify that you've followed these steps
|
||||
options:
|
||||
- label: This is a bug report, not a question.
|
||||
required: true
|
||||
- label: I have searched on the [issue tracker](https://github.com/filebrowser/filebrowser/issues?q=is%3Aissue) for my bug.
|
||||
required: true
|
||||
- label: I am running the latest [FileBrowser version](https://github.com/filebrowser/filebrowser/releases) or have an issue updating.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
render: Text
|
||||
description: |
|
||||
Enter the version of FileBrowser you are using.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
A clear and concise description of what the issue is about. What are you trying to do?
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What did you expect to happen?
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What actually happened?
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: |
|
||||
Tell us how to reproduce this issue. How can someone who is starting from scratch reproduce this behavior as minimally as possible?
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Files
|
||||
description: |
|
||||
A list of relevant files for this issue. Large files can be uploaded one-by-one or in a tarball/zipfile.
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: GitHub Discussions
|
||||
url: https://github.com/filebrowser/filebrowser/discussions
|
||||
about: Please ask questions and discuss features here.
|
||||
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,16 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
<!-- Add a clear and concise description of what the problem is. E.g. *I'm always frustrated when [...]* -->
|
||||
|
||||
**Describe the solution you'd like**
|
||||
<!-- Add a clear and concise description of what you want to happen. -->
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
<!-- Add a clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
27
.github/PULL_REQUEST_TEMPLATE.md
vendored
27
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,19 +1,16 @@
|
||||
**Description**
|
||||
<!--
|
||||
Please explain the changes you made here.
|
||||
If the feature changes current behaviour, explain why your solution is better.
|
||||
-->
|
||||
## Description
|
||||
|
||||
:rotating_light: Before submitting your PR, please indicate which issues are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
|
||||
<!-- Please explain the changes you made here. -->
|
||||
|
||||
- [ ] DO make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your master!
|
||||
- [ ] DO make sure you are making a pull request against the **master branch** (left side). Also you should start *your branch* off *our master*.
|
||||
- [ ] DO make sure that File Browser can be successfully built. See [builds](https://github.com/filebrowser/community/blob/master/builds.md) and [development](https://github.com/filebrowser/community/blob/master/development.md).
|
||||
- [ ] AVOID breaking the continuous integration build.
|
||||
## Additional Information
|
||||
|
||||
**Further comments**
|
||||
<!--
|
||||
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did, what alternatives you considered, etc.
|
||||
<!-- If it is a relatively large or complex change, please add more information to explain what you did, how you did it, if you considered any alternatives, etc. -->
|
||||
|
||||
:heart: Thank you!
|
||||
-->
|
||||
## Checklist
|
||||
|
||||
Before submitting your PR, please indicate which issues are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
|
||||
|
||||
- [ ] I am aware the project is currently in maintenance-only mode. See [README](https://github.com/filebrowser/community/blob/master/README.md)
|
||||
- [ ] I am aware that translations MUST be made through [Transifex](https://app.transifex.com/file-browser/file-browser/) and that this PR is NOT a translation update
|
||||
- [ ] I am making a PR against the `master` branch.
|
||||
- [ ] I am sure File Browser can be successfully built. See [builds](https://github.com/filebrowser/community/blob/master/builds.md) and [development](https://github.com/filebrowser/community/blob/master/development.md).
|
||||
|
||||
37
.github/workflows/main.yaml
vendored
37
.github/workflows/main.yaml
vendored
@@ -3,20 +3,25 @@ name: main
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
# linters
|
||||
# linters
|
||||
lint-frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
package_json_file: "frontend/package.json"
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: "22.x"
|
||||
cache: "pnpm"
|
||||
cache-dependency-path: "frontend/pnpm-lock.yaml"
|
||||
- run: make lint-frontend
|
||||
lint-backend:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -24,7 +29,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.22.2
|
||||
go-version: 1.23.0
|
||||
- run: make lint-backend
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -32,14 +37,19 @@ jobs:
|
||||
steps:
|
||||
- run: echo "done"
|
||||
|
||||
# tests
|
||||
# tests
|
||||
test-frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
package_json_file: "frontend/package.json"
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: "22.x"
|
||||
cache: "pnpm"
|
||||
cache-dependency-path: "frontend/pnpm-lock.yaml"
|
||||
- run: make test-frontend
|
||||
test-backend:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -47,7 +57,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.22.2
|
||||
go-version: 1.23.0
|
||||
- run: make test-backend
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,7 +65,7 @@ jobs:
|
||||
steps:
|
||||
- run: echo "done"
|
||||
|
||||
# release
|
||||
# release
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, test]
|
||||
@@ -66,10 +76,15 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.22.2
|
||||
go-version: 1.23.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
package_json_file: "frontend/package.json"
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: "22.x"
|
||||
cache: "pnpm"
|
||||
cache-dependency-path: "frontend/pnpm-lock.yaml"
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
|
||||
20
.github/workflows/site-pr.yml
vendored
Normal file
20
.github/workflows/site-pr.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Build Site
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'www'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build site
|
||||
run: make site
|
||||
32
.github/workflows/site-publish.yml
vendored
Normal file
32
.github/workflows/site-publish.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Build and Deploy Site
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build site
|
||||
run: make site
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
command: pages deploy www/public --project-name=${{ secrets.CLOUDFLARE_PROJECT_NAME }}
|
||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
24
.github/workflows/stale.yml
vendored
24
.github/workflows/stale.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
||||
close-pr-message: 'This PR was closed because it has been stalled for 5 days with no activity.'
|
||||
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
exempt-issue-labels: 'feature ☘,enhancement ⚙,bug 🐞'
|
||||
exempt-pr-labels: 'need-help,wip'
|
||||
operations-per-run: 100
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@ rice-box.go
|
||||
/filebrowser
|
||||
/filebrowser.exe
|
||||
/dist
|
||||
.venv
|
||||
|
||||
.DS_Store
|
||||
node_modules
|
||||
|
||||
187
.golangci.yml
187
.golangci.yml
@@ -1,121 +1,132 @@
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 100
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: false
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- experimental
|
||||
- opinionated
|
||||
- performance
|
||||
- style
|
||||
disabled-checks:
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- whyNoLint
|
||||
- wrapperFunc
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
goimports:
|
||||
local-prefixes: github.com/filebrowser/filebrowser
|
||||
gomnd:
|
||||
# don't include the "operation" and "assign"
|
||||
checks:
|
||||
- argument
|
||||
- case
|
||||
- condition
|
||||
- return
|
||||
ignored-numbers:
|
||||
- '0'
|
||||
- '1'
|
||||
- '2'
|
||||
- '3'
|
||||
ignored-functions:
|
||||
- strings.SplitN
|
||||
govet:
|
||||
enable:
|
||||
- nilness
|
||||
- shadow
|
||||
lll:
|
||||
line-length: 140
|
||||
misspell:
|
||||
locale: US
|
||||
nolintlint:
|
||||
allow-unused: false # report any unused nolint directives
|
||||
require-explanation: false # require an explanation for nolint directives
|
||||
require-specific: true # require nolint directives to be specific about which linter is being skipped
|
||||
version: "2"
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
# inverted configuration with `default: all` and `disable` is not scalable during updates of golangci-lint
|
||||
default: none
|
||||
enable:
|
||||
- bodyclose
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- errorlint
|
||||
- exportloopref
|
||||
- exhaustive
|
||||
- funlen
|
||||
- gocheckcompilerdirectives
|
||||
- gochecknoinits
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godox
|
||||
- goimports
|
||||
- gomnd
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell
|
||||
- mnd
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- staticcheck
|
||||
- stylecheck
|
||||
- testifylint
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- whitespace
|
||||
settings:
|
||||
dupl:
|
||||
threshold: 100
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: false
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- whyNoLint
|
||||
- wrapperFunc
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- experimental
|
||||
- opinionated
|
||||
- performance
|
||||
- style
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
govet:
|
||||
enable:
|
||||
- nilness
|
||||
- shadow
|
||||
lll:
|
||||
line-length: 140
|
||||
misspell:
|
||||
locale: US
|
||||
mnd:
|
||||
# don't include the "operation" and "assign"
|
||||
checks:
|
||||
- argument
|
||||
- case
|
||||
- condition
|
||||
- return
|
||||
ignored-numbers:
|
||||
- "0"
|
||||
- "1"
|
||||
- "2"
|
||||
- "3"
|
||||
- "0666"
|
||||
- "0700"
|
||||
- "0700"
|
||||
ignored-functions:
|
||||
- strings.SplitN
|
||||
- make
|
||||
nolintlint:
|
||||
allow-unused: false # report any unused nolint directives
|
||||
require-explanation: false # require an explanation for nolint directives
|
||||
require-specific: true # require nolint directives to be specific about which linter is being skipped
|
||||
staticcheck:
|
||||
checks:
|
||||
- "all"
|
||||
- "-QF*"
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
rules:
|
||||
- linters:
|
||||
- gochecknoinits
|
||||
path: cmd/.*.go
|
||||
- linters:
|
||||
- dupl
|
||||
- funlen
|
||||
- gochecknoinits
|
||||
- gocyclo
|
||||
- lll
|
||||
- scopelint
|
||||
path: .*_test.go
|
||||
- linters:
|
||||
- misspell
|
||||
text: "[aA]uther"
|
||||
- linters:
|
||||
- mnd
|
||||
text: strconv.Parse
|
||||
paths:
|
||||
- frontend/
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- frontend/
|
||||
exclude-rules:
|
||||
- path: cmd/.*.go
|
||||
linters:
|
||||
- gochecknoinits
|
||||
- path: .*_test.go
|
||||
linters:
|
||||
- lll
|
||||
- gochecknoinits
|
||||
- gocyclo
|
||||
- funlen
|
||||
- dupl
|
||||
- scopelint
|
||||
- text: "Auther"
|
||||
linters:
|
||||
- misspell
|
||||
- text: "strconv.Parse"
|
||||
linters:
|
||||
- gomnd
|
||||
|
||||
run:
|
||||
timeout: 5m
|
||||
formatters:
|
||||
enable:
|
||||
- goimports
|
||||
settings:
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- github.com/filebrowser/filebrowser
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- frontend/
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
version: 2
|
||||
|
||||
project_name: filebrowser
|
||||
|
||||
env:
|
||||
@@ -17,31 +19,30 @@ builds:
|
||||
- freebsd
|
||||
goarch:
|
||||
- amd64
|
||||
- 386
|
||||
- "386"
|
||||
- arm
|
||||
- arm64
|
||||
- riscv64
|
||||
goarm:
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- "5"
|
||||
- "6"
|
||||
- "7"
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: 386
|
||||
goarch: "386"
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
|
||||
archives:
|
||||
-
|
||||
name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
|
||||
format: tar.gz
|
||||
- name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
|
||||
formats: ["tar.gz"]
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
formats: ["zip"]
|
||||
|
||||
dockers:
|
||||
-
|
||||
dockerfile: Dockerfile
|
||||
# Alpine docker images
|
||||
- dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--pull"
|
||||
@@ -57,10 +58,8 @@ dockers:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
|
||||
extra_files:
|
||||
- docker_config.json
|
||||
- healthcheck.sh
|
||||
-
|
||||
dockerfile: Dockerfile
|
||||
- docker
|
||||
- dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--pull"
|
||||
@@ -76,10 +75,8 @@ dockers:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
|
||||
extra_files:
|
||||
- docker_config.json
|
||||
- healthcheck.sh
|
||||
-
|
||||
dockerfile: Dockerfile
|
||||
- docker
|
||||
- dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--pull"
|
||||
@@ -91,15 +88,13 @@ dockers:
|
||||
- "--platform=linux/arm/v6"
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: '6'
|
||||
goarm: "6"
|
||||
image_templates:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-armv6"
|
||||
extra_files:
|
||||
- docker_config.json
|
||||
- healthcheck.sh
|
||||
-
|
||||
dockerfile: Dockerfile
|
||||
- docker
|
||||
- dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--pull"
|
||||
@@ -111,16 +106,15 @@ dockers:
|
||||
- "--platform=linux/arm/v7"
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: '7'
|
||||
goarm: "7"
|
||||
image_templates:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
|
||||
extra_files:
|
||||
- docker_config.json
|
||||
- healthcheck.sh
|
||||
## s6 based docker images
|
||||
-
|
||||
dockerfile: Dockerfile.s6
|
||||
- docker
|
||||
|
||||
## s6-overlay docker images
|
||||
- dockerfile: Dockerfile.s6
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--pull"
|
||||
@@ -136,9 +130,8 @@ dockers:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
|
||||
extra_files:
|
||||
- docker/root
|
||||
-
|
||||
dockerfile: Dockerfile.s6.aarch64
|
||||
- docker
|
||||
- dockerfile: Dockerfile.s6.aarch64
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--pull"
|
||||
@@ -154,7 +147,8 @@ dockers:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
|
||||
extra_files:
|
||||
- docker/root
|
||||
- docker
|
||||
|
||||
docker_manifests:
|
||||
- name_template: "filebrowser/filebrowser:latest"
|
||||
image_templates:
|
||||
@@ -171,7 +165,7 @@ docker_manifests:
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
|
||||
## s6 image manifests
|
||||
## s6 image manifests
|
||||
- name_template: "filebrowser/filebrowser:s6"
|
||||
image_templates:
|
||||
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
|
||||
@@ -184,15 +178,20 @@ docker_manifests:
|
||||
image_templates:
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
|
||||
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
|
||||
brews:
|
||||
|
||||
homebrew_casks:
|
||||
- name: filebrowser
|
||||
repository:
|
||||
owner: filebrowser
|
||||
name: homebrew-tap
|
||||
folder: Formula
|
||||
homepage: https://filebrowser.org
|
||||
commit_author:
|
||||
name: FileBrowser Robot
|
||||
email: robot@filebrowser.org
|
||||
homepage: https://github.com/filebrowser/filebrowser
|
||||
description: File Browser is a create-your-own-cloud-kind of software where you can install it on a server, direct it to a path and then access your files through a nice web interface
|
||||
license: "MIT"
|
||||
hooks:
|
||||
post:
|
||||
install: |
|
||||
if system_command("/usr/bin/xattr", args: ["-h"]).exit_status == 0
|
||||
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/filebrowser"]
|
||||
end
|
||||
|
||||
10
.tx/config
10
.tx/config
@@ -1,10 +0,0 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = pt_BR: pt-br, zh_CN: zh-cn, zh_HK: zh-hk, zh_TW: zh-tw, nl_BE: nl-be, sv_SE: sv-se
|
||||
|
||||
[file-browser.file-browser]
|
||||
file_filter = frontend/src/i18n/<lang>.json
|
||||
minimum_perc = 50
|
||||
source_file = frontend/src/i18n/en.json
|
||||
source_lang = en
|
||||
type = KEYVALUEJSON
|
||||
262
CHANGELOG.md
262
CHANGELOG.md
@@ -2,6 +2,266 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [2.34.0](https://github.com/filebrowser/filebrowser/compare/v2.33.10...v2.34.0) (2025-06-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Translate frontend/src/i18n/en.json in fa ([0acd69c](https://github.com/filebrowser/filebrowser/commit/0acd69c537ce2909ff62c4bb6980982524ece221))
|
||||
* Translate frontend/src/i18n/en.json in fa ([#5233](https://github.com/filebrowser/filebrowser/issues/5233)) ([09f679f](https://github.com/filebrowser/filebrowser/commit/09f679fae43398f5b87d21acc9d974d4d053392f))
|
||||
* update translations for project File Browser ([#5226](https://github.com/filebrowser/filebrowser/issues/5226)) ([a5ea2a2](https://github.com/filebrowser/filebrowser/commit/a5ea2a266bef619d1c4322266d1aa7d397d2c856))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* abort ongoing requests when changing pages ([#3927](https://github.com/filebrowser/filebrowser/issues/3927)) ([93c4b2e](https://github.com/filebrowser/filebrowser/commit/93c4b2e03c5176da01a7e00a03c03ffcce279bc8))
|
||||
* add configurable minimum password length ([#5225](https://github.com/filebrowser/filebrowser/issues/5225)) ([464b644](https://github.com/filebrowser/filebrowser/commit/464b644adf22a2178414a6f1e4fa286276de81d2))
|
||||
* do not expose the name of the root directory ([#5224](https://github.com/filebrowser/filebrowser/issues/5224)) ([0892559](https://github.com/filebrowser/filebrowser/commit/089255997a653c284cd4249990b58bed00086c61))
|
||||
* Graceful shutdown ([8230eb7](https://github.com/filebrowser/filebrowser/commit/8230eb7ab51ccbd00b03f5b9d6964fa4aae331d4))
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "docs: change cloudflare environment (#5231)" (#5232) ([9e273cd](https://github.com/filebrowser/filebrowser/commit/9e273cd9475d57b9500034e8b341ff8b620bcab8)), closes [#5231](https://github.com/filebrowser/filebrowser/issues/5231) [#5232](https://github.com/filebrowser/filebrowser/issues/5232)
|
||||
|
||||
|
||||
### Build
|
||||
|
||||
* add an arm64 target for the site image ([#5229](https://github.com/filebrowser/filebrowser/issues/5229)) ([f5e531c](https://github.com/filebrowser/filebrowser/commit/f5e531c8ae0b9b18717e184856ace0ce19beef82))
|
||||
* bump golangci-lint to 2.1.6 ([1d494ff](https://github.com/filebrowser/filebrowser/commit/1d494ff3159ef939cfb4980ccde6f27df3e738b5))
|
||||
* **deps:** bump brace-expansion from 1.1.11 to 1.1.12 in /tools ([#5228](https://github.com/filebrowser/filebrowser/issues/5228)) ([5a07291](https://github.com/filebrowser/filebrowser/commit/5a072913062a6b2b0e5c74a02ca7710218ed3e5e))
|
||||
* **deps:** bump github.com/go-viper/mapstructure/v2 ([f32f273](https://github.com/filebrowser/filebrowser/commit/f32f27383d1fafa074f038cc873bd37b7f20ee27))
|
||||
* **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([5331969](https://github.com/filebrowser/filebrowser/commit/5331969163f5ae1fd2389f665059fc9e4a98db15))
|
||||
* publish docs to cloudflare pages ([#5230](https://github.com/filebrowser/filebrowser/issues/5230)) ([8861933](https://github.com/filebrowser/filebrowser/commit/8861933cf845b104e072f35e5f37d7c26097c9dc))
|
||||
|
||||
### [2.33.10](https://github.com/filebrowser/filebrowser/compare/v2.33.9...v2.33.10) (2025-06-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correctly check if command is allowed when using shell ([4d830f7](https://github.com/filebrowser/filebrowser/commit/4d830f707fc4314741fd431e70c2ce50cd5a3108))
|
||||
* correctly split shell ([f84a6db](https://github.com/filebrowser/filebrowser/commit/f84a6db680b6df1c7c8f06f1816f7e4c9e963668))
|
||||
* ignore linting error ([e735491](https://github.com/filebrowser/filebrowser/commit/e735491c57b12c3b19dd2e4b570723df78f4eb44))
|
||||
|
||||
### [2.33.9](https://github.com/filebrowser/filebrowser/compare/v2.33.8...v2.33.9) (2025-06-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check exact match on command allow list ([e2e1e49](https://github.com/filebrowser/filebrowser/commit/e2e1e4913085cca8917e0f69171dc28d3c6af1b6))
|
||||
* remove auth token from /api/command ([d5b39a1](https://github.com/filebrowser/filebrowser/commit/d5b39a14fd3fc0d1c364116b41289484df7c27b2))
|
||||
* remove unused import ([c232d41](https://github.com/filebrowser/filebrowser/commit/c232d41f903d3026ec290bbe819b6c59a933048e))
|
||||
|
||||
### [2.33.8](https://github.com/filebrowser/filebrowser/compare/v2.33.7...v2.33.8) (2025-06-25)
|
||||
|
||||
### [2.33.7](https://github.com/filebrowser/filebrowser/compare/v2.33.6...v2.33.7) (2025-06-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correctly parse negative boolean flags ([221451a](https://github.com/filebrowser/filebrowser/commit/221451a5179c8f139819a315b80d0ecb0e7220c3))
|
||||
* linting issues ([4bfbf33](https://github.com/filebrowser/filebrowser/commit/4bfbf332499fc8aea5f6df6aae1efa0de918d1ae))
|
||||
* linting issues ([e74c958](https://github.com/filebrowser/filebrowser/commit/e74c95886226c0ee429af1860eed21dd1f8601aa))
|
||||
|
||||
### [2.33.6](https://github.com/filebrowser/filebrowser/compare/v2.33.5...v2.33.6) (2025-06-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove incorrect default for password flag ([23bd8f6](https://github.com/filebrowser/filebrowser/commit/23bd8f67155081d707d4799393d3b1e2bebeaa34))
|
||||
|
||||
### [2.33.5](https://github.com/filebrowser/filebrowser/compare/v2.33.4...v2.33.5) (2025-06-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update languages for project File Browser ([#5190](https://github.com/filebrowser/filebrowser/issues/5190)) ([f330764](https://github.com/filebrowser/filebrowser/commit/f33076462a133935ca97fb6c7345303fe350e167))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* actually register the czech language ([#5189](https://github.com/filebrowser/filebrowser/issues/5189)) ([0268506](https://github.com/filebrowser/filebrowser/commit/0268506f80d33d2d31e38055e12530241d27a11b))
|
||||
|
||||
### [2.33.4](https://github.com/filebrowser/filebrowser/compare/v2.33.3...v2.33.4) (2025-06-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* translation updates for project File Browser ([#5179](https://github.com/filebrowser/filebrowser/issues/5179)) ([f714e71](https://github.com/filebrowser/filebrowser/commit/f714e71a356c2301f394d651c9b6c467440508e3))
|
||||
|
||||
### [2.33.3](https://github.com/filebrowser/filebrowser/compare/v2.33.2...v2.33.3) (2025-06-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* keep command behavior in Dockerfile ([7c0c782](https://github.com/filebrowser/filebrowser/commit/7c0c7820efbbed2f0499353cc76ecb85d00ff7c3))
|
||||
* update search hotkey in help prompt ([#5178](https://github.com/filebrowser/filebrowser/issues/5178)) ([2741616](https://github.com/filebrowser/filebrowser/commit/2741616473636d40b7e9f14c9906ada08d328c3c))
|
||||
|
||||
### [2.33.2](https://github.com/filebrowser/filebrowser/compare/v2.33.1...v2.33.2) (2025-06-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* create user dir on signup ([0ca8059](https://github.com/filebrowser/filebrowser/commit/0ca8059d8dea4fe079146471ce4f24acc96021f2))
|
||||
|
||||
### [2.33.1](https://github.com/filebrowser/filebrowser/compare/v2.33.0...v2.33.1) (2025-06-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* downloadUrl of file preview ([#3728](https://github.com/filebrowser/filebrowser/issues/3728)) ([8a14018](https://github.com/filebrowser/filebrowser/commit/8a14018861fe581672bbd27cdc3ae5691f70a108))
|
||||
* remove auth query parameter from download and preview links ([cbb7124](https://github.com/filebrowser/filebrowser/commit/cbb712484d3bdabc033acaf3b696ef4f5865813d))
|
||||
* search uses ctrl+shift+f instead of hijacking browser's ctrl+f ([#4638](https://github.com/filebrowser/filebrowser/issues/4638)) ([a02b297](https://github.com/filebrowser/filebrowser/commit/a02b2972ebde2a58806ad1377bad46e748b63166))
|
||||
|
||||
## [2.33.0](https://github.com/filebrowser/filebrowser/compare/v2.32.3...v2.33.0) (2025-06-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* improved docker image volumes and permissions ([#5160](https://github.com/filebrowser/filebrowser/issues/5160)) ([2e26393](https://github.com/filebrowser/filebrowser/commit/2e26393a022df0eaa9e08727407aba8b997aa728))
|
||||
|
||||
### [2.32.3](https://github.com/filebrowser/filebrowser/compare/v2.32.2...v2.32.3) (2025-06-17)
|
||||
|
||||
### [2.32.2](https://github.com/filebrowser/filebrowser/compare/v2.32.1...v2.32.2) (2025-06-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* updated for project File Browser ([#5159](https://github.com/filebrowser/filebrowser/issues/5159)) ([c34c0af](https://github.com/filebrowser/filebrowser/commit/c34c0afecf3242b16ad5d5584cd90a6ad323361c))
|
||||
|
||||
### [2.32.1](https://github.com/filebrowser/filebrowser/compare/v2.32.0...v2.32.1) (2025-06-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Vietnamese translation ([#3840](https://github.com/filebrowser/filebrowser/issues/3840)) ([56b80b6](https://github.com/filebrowser/filebrowser/commit/56b80b6d9b4710538765ba7df5da1f03898f6b81))
|
||||
* improve pt-br translations with new keys and refinements ([#4903](https://github.com/filebrowser/filebrowser/issues/4903)) ([a882fb6](https://github.com/filebrowser/filebrowser/commit/a882fb6c85ab6ccc845ed0bf3908d8e5e60ce346))
|
||||
* update translation ko.json ([#3852](https://github.com/filebrowser/filebrowser/issues/3852)) ([d9ebd65](https://github.com/filebrowser/filebrowser/commit/d9ebd65ffcf9b2166fec708d51849796d12b16e0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* err shadowing lint ([c606a01](https://github.com/filebrowser/filebrowser/commit/c606a01a2d20932fb32ee896234d57631f8c47e4))
|
||||
* generate random admin password on quick setup ([a46acba](https://github.com/filebrowser/filebrowser/commit/a46acba5f92ee044661880d6ae349e289d984328)), closes [#3646](https://github.com/filebrowser/filebrowser/issues/3646)
|
||||
* imports lint ([54b91b8](https://github.com/filebrowser/filebrowser/commit/54b91b8ff0b8ee1f02f72425ab97d27a5d942fc3))
|
||||
* set videojs locale ([#3742](https://github.com/filebrowser/filebrowser/issues/3742)) ([71a8f56](https://github.com/filebrowser/filebrowser/commit/71a8f5662c207e3cd4ee714a5b5a961121f510cd))
|
||||
|
||||
|
||||
### Build
|
||||
|
||||
* **deps-dev:** bump vite from 6.0.11 to 6.1.6 in /frontend ([#3886](https://github.com/filebrowser/filebrowser/issues/3886)) ([5355629](https://github.com/filebrowser/filebrowser/commit/5355629fd1e7bd85ee3222fca22da899ba23ea95))
|
||||
* **deps:** bump golang.org/x/crypto from 0.31.0 to 0.35.0 ([#3865](https://github.com/filebrowser/filebrowser/issues/3865)) ([0ba9505](https://github.com/filebrowser/filebrowser/commit/0ba9505a19cb369653fc9f8260dc02fcc6587629))
|
||||
* **deps:** bump golang.org/x/net from 0.33.0 to 0.38.0 ([#3869](https://github.com/filebrowser/filebrowser/issues/3869)) ([cfea84f](https://github.com/filebrowser/filebrowser/commit/cfea84fd5e7ec9c1d2366293e5db12baaa4e3a81))
|
||||
* **deps:** bump vue-i18n from 11.0.1 to 11.1.2 in /frontend ([#3786](https://github.com/filebrowser/filebrowser/issues/3786)) ([35d1c09](https://github.com/filebrowser/filebrowser/commit/35d1c092434b80b22c89a614a02122e9f5965b39))
|
||||
|
||||
## [2.32.0](https://github.com/filebrowser/filebrowser/compare/v2.31.2...v2.32.0) (2025-01-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* create user on proxy authentication if user does not exist ([#3569](https://github.com/filebrowser/filebrowser/issues/3569)) ([209acf2](https://github.com/filebrowser/filebrowser/commit/209acf2429b06e2e8d78218937c59fd7e7edd1be))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add proper healthcheck for S6 containers ([#3691](https://github.com/filebrowser/filebrowser/issues/3691)) ([045064f](https://github.com/filebrowser/filebrowser/commit/045064f8b8bf9f86058e877448085e38da8b3f2e))
|
||||
* disk usage refreshing ([#3692](https://github.com/filebrowser/filebrowser/issues/3692)) ([bbdd313](https://github.com/filebrowser/filebrowser/commit/bbdd313705b8d253f0c47ad717a6e47b2f46e719))
|
||||
* Fix user creation on proxy auth ([#3666](https://github.com/filebrowser/filebrowser/issues/3666)) ([5300d00](https://github.com/filebrowser/filebrowser/commit/5300d00d2e7dbb80a252aff57e100113f02506c3))
|
||||
* prompts disappearing on copy / move / upload ([#3537](https://github.com/filebrowser/filebrowser/issues/3537)) ([d1c84a8](https://github.com/filebrowser/filebrowser/commit/d1c84a84123c77dede05c023b3697a432b56122c))
|
||||
|
||||
|
||||
### Refactorings
|
||||
|
||||
* Fix eslint warnings ([#3698](https://github.com/filebrowser/filebrowser/issues/3698)) ([0201f9c](https://github.com/filebrowser/filebrowser/commit/0201f9c5c4dd2a4d5a3503e59cdb8045e8d3a91f)), closes [#3407](https://github.com/filebrowser/filebrowser/issues/3407)
|
||||
|
||||
|
||||
### Build
|
||||
|
||||
* **deps:** bump cross-spawn from 7.0.3 to 7.0.6 in /tools ([#3601](https://github.com/filebrowser/filebrowser/issues/3601)) ([25372ed](https://github.com/filebrowser/filebrowser/commit/25372edb5c0e616e82b76b5f523633af57d347e0))
|
||||
* **deps:** bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 ([#3574](https://github.com/filebrowser/filebrowser/issues/3574)) ([2fdea73](https://github.com/filebrowser/filebrowser/commit/2fdea73430011846276a1cda52458f1d670f5ea7))
|
||||
* **deps:** bump golang.org/x/crypto from 0.26.0 to 0.31.0 ([#3634](https://github.com/filebrowser/filebrowser/issues/3634)) ([e92dbb4](https://github.com/filebrowser/filebrowser/commit/e92dbb4bb8b7894264fbf0a48a641712c3b68766))
|
||||
* **deps:** bump golang.org/x/net from 0.23.0 to 0.33.0 ([#3712](https://github.com/filebrowser/filebrowser/issues/3712)) ([1194cfe](https://github.com/filebrowser/filebrowser/commit/1194cfe0097a70399c1f06cf0f514b9d70fa463c))
|
||||
* **deps:** bump vue-i18n from 9.10.2 to 9.14.2 in /frontend ([#3618](https://github.com/filebrowser/filebrowser/issues/3618)) ([0659594](https://github.com/filebrowser/filebrowser/commit/065959451d3ba12019c6151274aa4e6904cdca99))
|
||||
* fix go releaser ([ba797cd](https://github.com/filebrowser/filebrowser/commit/ba797cda3135eddb9b7165dc5ceb932399cb54df))
|
||||
* update to node 22 and pnpm ([#3616](https://github.com/filebrowser/filebrowser/issues/3616)) ([d51a343](https://github.com/filebrowser/filebrowser/commit/d51a3438201274a1b826be1b775ca1035ade20c5))
|
||||
|
||||
### [2.31.2](https://github.com/filebrowser/filebrowser/compare/v2.31.1...v2.31.2) (2024-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* added whitespace before version ([#3510](https://github.com/filebrowser/filebrowser/issues/3510)) ([2b37e69](https://github.com/filebrowser/filebrowser/commit/2b37e696c9bde4d0c453de236a3555d982346bbb))
|
||||
* change location of custom init scripts ([#3493](https://github.com/filebrowser/filebrowser/issues/3493)) ([406d4f7](https://github.com/filebrowser/filebrowser/commit/406d4f78845a1684df7c9c457b208f4dd9b2a930))
|
||||
* files list alignment ([#3494](https://github.com/filebrowser/filebrowser/issues/3494)) ([64400ff](https://github.com/filebrowser/filebrowser/commit/64400ffda8b09f66b8662a3c9400235139800a4d))
|
||||
* german translation spelling typos ([#3469](https://github.com/filebrowser/filebrowser/issues/3469)) ([1e7c415](https://github.com/filebrowser/filebrowser/commit/1e7c41505fb6a3b9baa1534787492a186e09bcfb))
|
||||
|
||||
|
||||
### Build
|
||||
|
||||
* **deps-dev:** bump vite from 5.2.7 to 5.4.6 in /frontend ([#3496](https://github.com/filebrowser/filebrowser/issues/3496)) ([ec7b643](https://github.com/filebrowser/filebrowser/commit/ec7b643e8e9499f7ff226ec7f8e63a9df9890352))
|
||||
* **deps:** bump rollup from 4.21.3 to 4.22.4 in /frontend ([#3504](https://github.com/filebrowser/filebrowser/issues/3504)) ([03d74ee](https://github.com/filebrowser/filebrowser/commit/03d74ee7582196c09720f8d488056339f06c446c))
|
||||
|
||||
### [2.31.1](https://github.com/filebrowser/filebrowser/compare/v2.31.0...v2.31.1) (2024-08-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* command not found in shell ([#3438](https://github.com/filebrowser/filebrowser/issues/3438)) ([121d9ab](https://github.com/filebrowser/filebrowser/commit/121d9abecdc7d4e923cfc5023519995938a6ccae))
|
||||
|
||||
|
||||
### Build
|
||||
|
||||
* update to alpine 3.20 ([#3447](https://github.com/filebrowser/filebrowser/issues/3447)) ([7de6bc4](https://github.com/filebrowser/filebrowser/commit/7de6bc4a912b5734dd0df02ed8391e78619e2615))
|
||||
|
||||
## [2.31.0](https://github.com/filebrowser/filebrowser/compare/v2.30.0...v2.31.0) (2024-08-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Czech translation ([#3416](https://github.com/filebrowser/filebrowser/issues/3416)) ([8e67a12](https://github.com/filebrowser/filebrowser/commit/8e67a12f260caefcbe419c2281025b9b15f02bf3))
|
||||
* Added epub preview. Resolves [#3375](https://github.com/filebrowser/filebrowser/issues/3375) ([#3376](https://github.com/filebrowser/filebrowser/issues/3376)) ([99a6382](https://github.com/filebrowser/filebrowser/commit/99a6382b320874e94f9bd74708f46dd9a7485d3c))
|
||||
* implement markdown file preview in Ace editor ([#3431](https://github.com/filebrowser/filebrowser/issues/3431)) ([b0f4604](https://github.com/filebrowser/filebrowser/commit/b0f4604f44e6a35e07df3000f106f523cd942cfc))
|
||||
* support mime type for epub extension ([#3425](https://github.com/filebrowser/filebrowser/issues/3425)) ([f6f7e5f](https://github.com/filebrowser/filebrowser/commit/f6f7e5fea3ff7073ee652008a51cb5445a6f3d5d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clipboard copy in safari ([#3261](https://github.com/filebrowser/filebrowser/issues/3261)) ([1fccc5d](https://github.com/filebrowser/filebrowser/commit/1fccc5d649add2a56c55e75cf9dec4851e6d7cbf))
|
||||
* CSS selectors for listing icons ([#3277](https://github.com/filebrowser/filebrowser/issues/3277)) ([2a90cdf](https://github.com/filebrowser/filebrowser/commit/2a90cdfdaff8655c7cb1167c01994a0978dece8f))
|
||||
* fix catalan i18n file ([090272e](https://github.com/filebrowser/filebrowser/commit/090272e3b7c56a940c4aa2d28f860c574aa17d53))
|
||||
* fixing an issue where the upload indicator would "jump" around in the UI ([#3354](https://github.com/filebrowser/filebrowser/issues/3354)) ([7be5644](https://github.com/filebrowser/filebrowser/commit/7be564495226bc6846289a56edb8893511036c6e))
|
||||
* **frontend:** N files selected hint use i18n ([#3390](https://github.com/filebrowser/filebrowser/issues/3390)) ([10bf3cf](https://github.com/filebrowser/filebrowser/commit/10bf3cffbf8eb7d95fe4e1cc6acf1012329744b9))
|
||||
* pdf preview header ([#3274](https://github.com/filebrowser/filebrowser/issues/3274)) ([a838868](https://github.com/filebrowser/filebrowser/commit/a8388689f3019083f263845900f683ddc13884dc))
|
||||
* pull down to refresh within editor ([#3378](https://github.com/filebrowser/filebrowser/issues/3378)) ([21783ed](https://github.com/filebrowser/filebrowser/commit/21783ed91a13ad52afdb411e43faf14fb6ef6e42))
|
||||
|
||||
|
||||
### Build
|
||||
|
||||
* bump go libs ([b596567](https://github.com/filebrowser/filebrowser/commit/b596567c6163d57eaefbf3e30d84cfca65c24cdf))
|
||||
* bump go version to 1.23.0 ([364fdaa](https://github.com/filebrowser/filebrowser/commit/364fdaaf0c1eace82ff8637d337cc1b32e5e9972))
|
||||
* bump golangci-lint to 1.60.3 ([a6347c8](https://github.com/filebrowser/filebrowser/commit/a6347c88586e584b4565277b0010fa9ff2576b1f))
|
||||
* **deps-dev:** bump braces from 3.0.2 to 3.0.3 in /frontend ([#3316](https://github.com/filebrowser/filebrowser/issues/3316)) ([e8589be](https://github.com/filebrowser/filebrowser/commit/e8589be6409a2b29edd44ee2edd3fbf6b2d72724))
|
||||
* **deps-dev:** bump ws from 8.16.0 to 8.17.1 in /frontend ([#3321](https://github.com/filebrowser/filebrowser/issues/3321)) ([c3465f9](https://github.com/filebrowser/filebrowser/commit/c3465f99136506d51b813be4f31b289e708da0ce))
|
||||
* **deps:** bump golang.org/x/image from 0.15.0 to 0.18.0 ([#3335](https://github.com/filebrowser/filebrowser/issues/3335)) ([30a8ddf](https://github.com/filebrowser/filebrowser/commit/30a8ddf113862e3de2c09547662b7f2af8a30dfe))
|
||||
* fix goreleaser file ([056cfa8](https://github.com/filebrowser/filebrowser/commit/056cfa8facdca4c397a6b245028d4c9d3f0ca518))
|
||||
|
||||
## [2.30.0](https://github.com/filebrowser/filebrowser/compare/v2.29.0...v2.30.0) (2024-05-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow multi-select with SHIFT key in singleClick mode ([#3185](https://github.com/filebrowser/filebrowser/issues/3185)) ([2e47a03](https://github.com/filebrowser/filebrowser/commit/2e47a038d63de8f848b070578c1d71f765438a24))
|
||||
* Enhance MIME Type Detection for Additional File Extensions ([#3183](https://github.com/filebrowser/filebrowser/issues/3183)) ([be62f56](https://github.com/filebrowser/filebrowser/commit/be62f56782551e17d6d5dc23bc29cc56ef961a66))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add overlay for sidebar on mobile ([#3197](https://github.com/filebrowser/filebrowser/issues/3197)) ([3b48f75](https://github.com/filebrowser/filebrowser/commit/3b48f75301287fe94cbbacff184b4db03f37f7ea))
|
||||
* current folder name in page title ([#3200](https://github.com/filebrowser/filebrowser/issues/3200)) ([e336a25](https://github.com/filebrowser/filebrowser/commit/e336a25ad29ed8b956169d426992860a877ee551))
|
||||
* Fixing the inability to play MKV video files online and enhancing the auxiliary features of the VideoPlayer. ([#3181](https://github.com/filebrowser/filebrowser/issues/3181)) ([782375b](https://github.com/filebrowser/filebrowser/commit/782375b1cb4c4f954468c30ec277ce021c82b40d))
|
||||
* shell window size ([#3198](https://github.com/filebrowser/filebrowser/issues/3198)) ([4c5b612](https://github.com/filebrowser/filebrowser/commit/4c5b612cb2563817f9da50413c7cf9e89b4c4d4a))
|
||||
* The file type icon in the file list is sensitive to the case of the suffix name ([#3187](https://github.com/filebrowser/filebrowser/issues/3187)) ([a9c327c](https://github.com/filebrowser/filebrowser/commit/a9c327cc0687796a3c7bfafd4ddabf4342859e31))
|
||||
|
||||
## [2.29.0](https://github.com/filebrowser/filebrowser/compare/v2.28.0...v2.29.0) (2024-04-30)
|
||||
|
||||
|
||||
@@ -38,7 +298,7 @@ All notable changes to this project will be documented in this file. See [standa
|
||||
* close editor when click escape key ([#2947](https://github.com/filebrowser/filebrowser/issues/2947)) ([70c8261](https://github.com/filebrowser/filebrowser/commit/70c826133b8578b8712e6db8f762a15a076cd9a9))
|
||||
* enable preview in shared folder ([#3055](https://github.com/filebrowser/filebrowser/issues/3055)) ([4c233c3](https://github.com/filebrowser/filebrowser/commit/4c233c3db39ea5a00d6e602ec0ecbddecb590877))
|
||||
* focus editor when opened ([#2946](https://github.com/filebrowser/filebrowser/issues/2946)) ([b19710e](https://github.com/filebrowser/filebrowser/commit/b19710efca6daa7af56dc211d0051d500d2eea22))
|
||||
* freezing the list in the backgroud while previewing a file ([#3004](https://github.com/filebrowser/filebrowser/issues/3004)) ([e167c3e](https://github.com/filebrowser/filebrowser/commit/e167c3e1efed8b16be45d994a8d443fda1d8cf49))
|
||||
* freezing the list in the background while previewing a file ([#3004](https://github.com/filebrowser/filebrowser/issues/3004)) ([e167c3e](https://github.com/filebrowser/filebrowser/commit/e167c3e1efed8b16be45d994a8d443fda1d8cf49))
|
||||
* prompt to confirm discard editor changes ([#2948](https://github.com/filebrowser/filebrowser/issues/2948)) ([fb1a09c](https://github.com/filebrowser/filebrowser/commit/fb1a09c7c172b913c12b30975ca545e505df0c05))
|
||||
* select multiple files with ctrl even with singleClick option ([#2953](https://github.com/filebrowser/filebrowser/issues/2953)) ([d49c3df](https://github.com/filebrowser/filebrowser/commit/d49c3dfacfc0ff07e620b3ad2700e64927b06235))
|
||||
|
||||
|
||||
46
CODE-OF-CONDUCT.md
Normal file
46
CODE-OF-CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Code of Conduct
|
||||
|
||||
## Contributor Covenant Code of Conduct
|
||||
|
||||
### Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
### Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
### Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
### Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
### Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hacdias@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
### Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [https://contributor-covenant.org/version/1/4](https://contributor-covenant.org/version/1/4).
|
||||
|
||||
91
CONTRIBUTING.md
Normal file
91
CONTRIBUTING.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Contributing
|
||||
|
||||
If you're interested in contributing to this project, this is the best place to start. Before contributing to this project, please take a bit of time to read our [Code of Conduct](code-of-conduct.md). Also, note that this project is open-source and licensed under [Apache License 2.0](LICENSE).
|
||||
|
||||
## Project Structure
|
||||
|
||||
The backend side of the application is written in [Go](https://golang.org/), while the frontend (located on a subdirectory of the same name) is written in [Vue.js](https://vuejs.org/). Due to the tight coupling required by some features, basic knowledge of both Go and Vue.js is recommended.
|
||||
|
||||
* Learn Go: [https://github.com/golang/go/wiki/Learn](https://github.com/golang/go/wiki/Learn)
|
||||
* Learn Vue.js: [https://vuejs.org/guide/introduction.html](https://vuejs.org/guide/introduction.html)
|
||||
|
||||
We encourage you to use git to manage your fork. To clone the main repository, just run:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/filebrowser/filebrowser
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
### Frontend
|
||||
|
||||
We are using [Node.js](https://nodejs.org/en/) on the frontend to manage the build process. The steps to build it are:
|
||||
|
||||
```bash
|
||||
# From the root of the repo, go to frontend/
|
||||
cd frontend
|
||||
|
||||
# Install the dependencies
|
||||
pnpm install
|
||||
|
||||
# Build the frontend
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
This will install the dependencies and build the frontend so you can then embed it into the Go app. Although, if you want to play with it, you'll get bored of building it after every change you do. So, you can run the command below to watch for changes:
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
### Backend
|
||||
|
||||
First of all, you need to download the required dependencies. We are using the built-in `go mod` tool for dependency management. To get the modules, run:
|
||||
|
||||
```bash
|
||||
go mod download
|
||||
```
|
||||
|
||||
The magic of File Browser is that the static assets are bundled into the final binary. For that, we use [Go embed.FS](https://golang.org/pkg/embed/). The files from `frontend/dist` will be embedded during the build process.
|
||||
|
||||
To build File Browser is just like any other Go program:
|
||||
|
||||
```bash
|
||||
go build
|
||||
```
|
||||
|
||||
To create a development build use the "dev" tag, this way the content inside the frontend folder will not be embedded in the binary but will be reloaded at every change:
|
||||
|
||||
```bash
|
||||
go build -tags dev
|
||||
```
|
||||
|
||||
## Translations
|
||||
|
||||
Translations are managed on Transifex, which is an online website where everyone can contribute and translate strings for our project. It automatically syncs with the main language file \(in English\) and,, for you to contribute, you just need to:
|
||||
|
||||
1. Go to our Transifex web page: [app.transifex.com/file-browser/file-browser](https://app.transifex.com/file-browser/file-browser/)
|
||||
2. Click on **Join the project** and pick your language. We'll accept you as soon as possible. If you're language is not on the list, please request it via the interface.
|
||||
|
||||
Translations are automatically pushed to GitHub via an integration.
|
||||
|
||||
## Authentication Provider
|
||||
|
||||
To build a new authentication provider, you need to implement the [Auther interface](https://github.com/filebrowser/filebrowser/blob/master/auth/auth.go), whose method will be called on the login page after the user has submitted their login data.
|
||||
|
||||
```go
|
||||
// Auther is the authentication interface.
|
||||
type Auther interface {
|
||||
// Auth is called to authenticate a request.
|
||||
Auth(r *http.Request, s *users.Storage, root string) (*users.User, error)
|
||||
}
|
||||
```
|
||||
|
||||
After implementing the interface you should:
|
||||
|
||||
1. Add it to [`auth` directory](https://github.com/filebrowser/filebrowser/blob/master/auth).
|
||||
2. Add it to the [configuration parser](https://github.com/filebrowser/filebrowser/blob/master/cmd/config.go) for the CLI.
|
||||
3. Add it to the [`authBackend.Get`](https://github.com/filebrowser/filebrowser/blob/master/storage/bolt/auth.go).
|
||||
|
||||
If you need to add more flags, please update the function `addConfigFlags`.
|
||||
|
||||
41
Dockerfile
41
Dockerfile
@@ -1,19 +1,32 @@
|
||||
FROM alpine:latest
|
||||
RUN apk --update add ca-certificates \
|
||||
mailcap \
|
||||
curl \
|
||||
jq
|
||||
FROM alpine:3.22
|
||||
|
||||
COPY healthcheck.sh /healthcheck.sh
|
||||
RUN chmod +x /healthcheck.sh # Make the script executable
|
||||
RUN apk update && \
|
||||
apk --no-cache add ca-certificates mailcap curl jq tini
|
||||
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
||||
CMD /healthcheck.sh || exit 1
|
||||
# Make user and create necessary directories
|
||||
ENV UID=1000
|
||||
ENV GID=1000
|
||||
|
||||
RUN addgroup -g $GID user && \
|
||||
adduser -D -u $UID -G user user && \
|
||||
mkdir -p /config /database /srv && \
|
||||
chown -R user:user /config /database /srv
|
||||
|
||||
# Copy files and set permissions
|
||||
COPY filebrowser /bin/filebrowser
|
||||
COPY docker/common/ /
|
||||
COPY docker/alpine/ /
|
||||
|
||||
RUN chown -R user:user /bin/filebrowser /defaults healthcheck.sh init.sh
|
||||
|
||||
# Define healthcheck script
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
|
||||
|
||||
# Set the user, volumes and exposed ports
|
||||
USER user
|
||||
|
||||
VOLUME /srv /config /database
|
||||
|
||||
VOLUME /srv
|
||||
EXPOSE 80
|
||||
|
||||
COPY docker_config.json /.filebrowser.json
|
||||
COPY filebrowser /filebrowser
|
||||
|
||||
ENTRYPOINT [ "/filebrowser" ]
|
||||
ENTRYPOINT [ "tini", "--", "/init.sh", "filebrowser", "--config", "/config/settings.json" ]
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
FROM ghcr.io/linuxserver/baseimage-alpine:3.17
|
||||
FROM ghcr.io/linuxserver/baseimage-alpine:3.22
|
||||
|
||||
RUN apk --update add ca-certificates \
|
||||
mailcap \
|
||||
curl
|
||||
RUN apk update && \
|
||||
apk --no-cache add ca-certificates mailcap curl jq
|
||||
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
||||
CMD curl -f http://localhost/health || exit 1
|
||||
# Make user and create necessary directories
|
||||
RUN mkdir -p /config /database /srv && \
|
||||
chown -R abc:abc /config /database /srv
|
||||
|
||||
# copy local files
|
||||
COPY docker/root/ /
|
||||
COPY filebrowser /usr/bin/filebrowser
|
||||
# Copy files and set permissions
|
||||
COPY filebrowser /bin/filebrowser
|
||||
COPY docker/common/ /
|
||||
COPY docker/s6/ /
|
||||
|
||||
# ports and volumes
|
||||
RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh
|
||||
|
||||
# Define healthcheck script
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
|
||||
|
||||
# Set the volumes and exposed ports
|
||||
VOLUME /srv /config /database
|
||||
EXPOSE 80
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.17
|
||||
FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.22
|
||||
|
||||
RUN apk --update add ca-certificates \
|
||||
mailcap \
|
||||
curl
|
||||
RUN apk update && \
|
||||
apk --no-cache add ca-certificates mailcap curl jq
|
||||
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
||||
CMD curl -f http://localhost/health || exit 1
|
||||
# Make user and create necessary directories
|
||||
RUN mkdir -p /config /database /srv && \
|
||||
chown -R abc:abc /config /database /srv
|
||||
|
||||
# copy local files
|
||||
COPY docker/root/ /
|
||||
COPY filebrowser /usr/bin/filebrowser
|
||||
# Copy files and set permissions
|
||||
COPY filebrowser /bin/filebrowser
|
||||
COPY docker/common/ /
|
||||
COPY docker/s6/ /
|
||||
|
||||
# ports and volumes
|
||||
RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh
|
||||
|
||||
# Define healthcheck script
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
|
||||
|
||||
# Set the volumes and exposed ports
|
||||
VOLUME /srv /config /database
|
||||
EXPOSE 80
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
FROM ghcr.io/linuxserver/baseimage-alpine:arm32v7-3.17
|
||||
|
||||
RUN apk --update add ca-certificates \
|
||||
mailcap \
|
||||
curl
|
||||
|
||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
||||
CMD curl -f http://localhost/health || exit 1
|
||||
|
||||
# copy local files
|
||||
COPY docker/root/ /
|
||||
COPY filebrowser /usr/bin/filebrowser
|
||||
|
||||
# ports and volumes
|
||||
VOLUME /srv /config /database
|
||||
EXPOSE 80
|
||||
26
Makefile
26
Makefile
@@ -3,6 +3,14 @@ include tools.mk
|
||||
|
||||
LDFLAGS += -X "$(MODULE)/version.Version=$(VERSION)" -X "$(MODULE)/version.CommitSHA=$(VERSION_HASH)"
|
||||
|
||||
SITE_DOCKER_FLAGS = \
|
||||
-v $(CURDIR)/www:/docs \
|
||||
-v $(CURDIR)/LICENSE:/docs/docs/LICENSE \
|
||||
-v $(CURDIR)/SECURITY.md:/docs/docs/security.md \
|
||||
-v $(CURDIR)/CHANGELOG.md:/docs/docs/changelog.md \
|
||||
-v $(CURDIR)/CODE-OF-CONDUCT.md:/docs/docs/code-of-conduct.md \
|
||||
-v $(CURDIR)/CONTRIBUTING.md:/docs/docs/contributing.md
|
||||
|
||||
## Build:
|
||||
|
||||
.PHONY: build
|
||||
@@ -10,7 +18,7 @@ build: | build-frontend build-backend ## Build binary
|
||||
|
||||
.PHONY: build-frontend
|
||||
build-frontend: ## Build frontend
|
||||
$Q cd frontend && npm ci && npm run build
|
||||
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run build
|
||||
|
||||
.PHONY: build-backend
|
||||
build-backend: ## Build backend
|
||||
@@ -21,6 +29,7 @@ test: | test-frontend test-backend ## Run all tests
|
||||
|
||||
.PHONY: test-frontend
|
||||
test-frontend: ## Run frontend tests
|
||||
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run typecheck
|
||||
|
||||
.PHONY: test-backend
|
||||
test-backend: ## Run backend tests
|
||||
@@ -31,7 +40,7 @@ lint: lint-frontend lint-backend ## Run all linters
|
||||
|
||||
.PHONY: lint-frontend
|
||||
lint-frontend: ## Run frontend linters
|
||||
$Q cd frontend && npm ci && npm run lint
|
||||
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run lint
|
||||
|
||||
.PHONY: lint-backend
|
||||
lint-backend: | $(golangci-lint) ## Run backend linters
|
||||
@@ -52,6 +61,17 @@ clean: clean-tools ## Clean
|
||||
bump-version: $(standard-version) ## Bump app version
|
||||
$Q ./scripts/bump_version.sh
|
||||
|
||||
.PHONY: site
|
||||
site: ## Build site
|
||||
@rm -rf www/public
|
||||
docker build -f www/Dockerfile --progress=plain -t filebrowser.site www
|
||||
docker run --rm $(SITE_DOCKER_FLAGS) filebrowser.site build -d "public"
|
||||
|
||||
.PHONY: site-serve
|
||||
site-serve: ## Serve site for development
|
||||
docker build -f www/Dockerfile --progress=plain -t filebrowser.site www
|
||||
docker run --rm -it -p 8000:8000 $(SITE_DOCKER_FLAGS) filebrowser.site
|
||||
|
||||
## Help:
|
||||
help: ## Show this help
|
||||
@echo ''
|
||||
@@ -65,4 +85,4 @@ help: ## Show this help
|
||||
@awk 'BEGIN {FS = ":.*?## "} { \
|
||||
if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \
|
||||
else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \
|
||||
}' $(MAKEFILE_LIST)
|
||||
}' $(MAKEFILE_LIST)
|
||||
|
||||
47
README.md
47
README.md
@@ -2,38 +2,29 @@
|
||||
<img src="https://raw.githubusercontent.com/filebrowser/logo/master/banner.png" width="550"/>
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
[](https://github.com/filebrowser/filebrowser/actions/workflows/main.yaml)
|
||||
[](https://goreportcard.com/report/github.com/filebrowser/filebrowser)
|
||||
[](http://godoc.org/github.com/filebrowser/filebrowser)
|
||||
[](https://github.com/filebrowser/filebrowser/releases/latest)
|
||||
[](http://webchat.freenode.net/?channels=%23filebrowser)
|
||||
[](https://goreportcard.com/report/github.com/filebrowser/filebrowser)
|
||||
[](http://godoc.org/github.com/filebrowser/filebrowser)
|
||||
[](https://github.com/filebrowser/filebrowser/releases/latest)
|
||||
[](http://webchat.freenode.net/?channels=%23filebrowser)
|
||||
|
||||
filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app.
|
||||
File Browser provides a file managing interface within a specified directory and it can be used to upload, delete, preview and edit your files. It is a **create-your-own-cloud**-kind of software where you can just install it on your server, direct it to a path and access your files through a nice web interface.
|
||||
|
||||
## Demo
|
||||
## Documentation
|
||||
|
||||
url: https://demo.filebrowser.org/
|
||||
Documentation on how to install, configure, and contribute to this project is hosted at [filebrowser.org](https://filebrowser.org).
|
||||
|
||||
credentials: `demo`/`demo`
|
||||
## Project Status
|
||||
|
||||
## Features
|
||||
> [!WARNING]
|
||||
>
|
||||
> This project is currently on **maintenance-only** mode, and is looking for new maintainers. For more information, please read the [discussion #4906](https://github.com/filebrowser/filebrowser/discussions/4906). Therefore, please note the following:
|
||||
>
|
||||
> - It can take a while until someone gets back to you. Please be patient.
|
||||
> - [Issues][issues] are only being used to track bugs. Any unrelated issues will be converted into a [discussion][discussions].
|
||||
> - No new features will be implemented until further notice. The priority is on triaging issues and merge bug fixes.
|
||||
>
|
||||
> If you're interested in maintaining this project, please reach out via the discussion above.
|
||||
|
||||
Please refer to our docs at [https://filebrowser.org/features](https://filebrowser.org/features)
|
||||
|
||||
## Install
|
||||
|
||||
For installation instructions please refer to our docs at [https://filebrowser.org/installation](https://filebrowser.org/installation).
|
||||
|
||||
## Configuration
|
||||
|
||||
[Authentication Method](https://filebrowser.org/configuration/authentication-method) - You can change the way the user authenticates with the filebrowser server
|
||||
|
||||
[Command Runner](https://filebrowser.org/configuration/command-runner) - The command runner is a feature that enables you to execute any shell command you want before or after a certain event.
|
||||
|
||||
[Custom Branding](https://filebrowser.org/configuration/custom-branding) - You can customize your File Browser installation by change its name to any other you want, by adding a global custom style sheet and by using your own logotype if you want.
|
||||
|
||||
## Contributing
|
||||
|
||||
If you're interested in contributing to this project, our docs are best places to start [https://filebrowser.org/contributing](https://filebrowser.org/contributing).
|
||||
[issues]: https://github.com/filebrowser/filebrowser/issues
|
||||
[discussions]: https://github.com/filebrowser/filebrowser/discussions
|
||||
|
||||
@@ -12,7 +12,9 @@ currently being supported with security updates.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Vulnerabilities should be reported to filebrowser@googlegroups.com - which is a private, maintainer-only group. Maintainers will attempt to respond to/confirm reports within 2-3 days, but if you believe your report to be "critical" to user safety and security, please note as such in the subject. We have tens of thousands of users using our software, and take security vulnerabilities seriously.
|
||||
Vulnerabilities with critical impact should be reported on the [Security](https://github.com/filebrowser/filebrowser/security) page of this repository, which is a private way of communicating vulnerabilities to maintainers. This project is in maintenance-only mode and it can take a while until someone gets back to you.
|
||||
|
||||
If it is not a critical vulnerability, please open an issue and we will categorize it as a security issue. By giving visibility, we can get more help from the community at fixing such issues.
|
||||
|
||||
When reporting an issue, where possible, please provide at least:
|
||||
|
||||
@@ -21,6 +23,4 @@ When reporting an issue, where possible, please provide at least:
|
||||
* Steps to reproduce
|
||||
* Your recommended remediation(s), if any.
|
||||
|
||||
The FileBrowser team is a volunteer-only effort, and may reach back out for clarification.
|
||||
|
||||
> Note: Please do not open public issues for security issues, as GitHub does not provide facility for private issues, and deleting the issue makes it hard to triage/respond back to the reporter.
|
||||
The File Browser team is a volunteer-only effort, and may reach back out for clarification.
|
||||
|
||||
@@ -150,7 +150,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
}
|
||||
|
||||
if u == nil {
|
||||
pass, err := users.HashPwd(a.Cred.Password)
|
||||
pass, err := users.HashAndValidatePwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -186,7 +186,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
|
||||
// update the password when it doesn't match the current
|
||||
if p {
|
||||
pass, err := users.HashPwd(a.Cred.Password)
|
||||
pass, err := users.HashAndValidatePwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package auth
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
@@ -19,14 +18,48 @@ type ProxyAuth struct {
|
||||
}
|
||||
|
||||
// Auth authenticates the user via an HTTP header.
|
||||
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, setting *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||
username := r.Header.Get(a.Header)
|
||||
user, err := usr.Get(srv.Root, username)
|
||||
if errors.Is(err, fbErrors.ErrNotExist) {
|
||||
return nil, os.ErrPermission
|
||||
return a.createUser(usr, setting, srv, username)
|
||||
}
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (a ProxyAuth) createUser(usr users.Store, setting *settings.Settings, srv *settings.Server, username string) (*users.User, error) {
|
||||
const randomPasswordLength = settings.DefaultMinimumPasswordLength + 10
|
||||
pwd, err := users.RandomPwd(randomPasswordLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, err
|
||||
var hashedRandomPassword string
|
||||
hashedRandomPassword, err = users.HashAndValidatePwd(pwd, setting.MinimumPasswordLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := &users.User{
|
||||
Username: username,
|
||||
Password: hashedRandomPassword,
|
||||
LockPassword: true,
|
||||
}
|
||||
setting.Defaults.Apply(user)
|
||||
|
||||
var userHome string
|
||||
userHome, err = setting.MakeUserDir(user.Username, user.Scope, srv.Root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Scope = userHome
|
||||
|
||||
err = usr.Save(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// LoginPage tells that proxy auth doesn't require a login page.
|
||||
|
||||
@@ -32,6 +32,7 @@ func addConfigFlags(flags *pflag.FlagSet) {
|
||||
addUserFlags(flags)
|
||||
flags.BoolP("signup", "s", false, "allow users to signup")
|
||||
flags.Bool("create-user-dir", false, "generate user's home directory automatically")
|
||||
flags.Uint("minimum-password-length", settings.DefaultMinimumPasswordLength, "minimum password length for new users")
|
||||
flags.String("shell", "", "shell command to which other commands should be appended")
|
||||
|
||||
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
|
||||
@@ -144,6 +145,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
|
||||
|
||||
fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
|
||||
fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
|
||||
fmt.Fprintf(w, "Minimum Password Length:\t%d\n", set.MinimumPasswordLength)
|
||||
fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod)
|
||||
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
|
||||
fmt.Fprintln(w, "\nBranding:")
|
||||
|
||||
@@ -56,7 +56,7 @@ The path must be for a json or yaml file.`,
|
||||
checkErr(err)
|
||||
|
||||
var rawAuther interface{}
|
||||
if filepath.Ext(args[0]) != ".json" { //nolint:goconst
|
||||
if filepath.Ext(args[0]) != ".json" {
|
||||
rawAuther = cleanUpInterfaceMap(file.Auther.(map[interface{}]interface{}))
|
||||
} else {
|
||||
rawAuther = file.Auther
|
||||
|
||||
@@ -29,12 +29,13 @@ override the options.`,
|
||||
authMethod, auther := getAuthentication(flags)
|
||||
|
||||
s := &settings.Settings{
|
||||
Key: generateKey(),
|
||||
Signup: mustGetBool(flags, "signup"),
|
||||
CreateUserDir: mustGetBool(flags, "create-user-dir"),
|
||||
Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")),
|
||||
AuthMethod: authMethod,
|
||||
Defaults: defaults,
|
||||
Key: generateKey(),
|
||||
Signup: mustGetBool(flags, "signup"),
|
||||
CreateUserDir: mustGetBool(flags, "create-user-dir"),
|
||||
MinimumPasswordLength: mustGetUint(flags, "minimum-password-length"),
|
||||
Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")),
|
||||
AuthMethod: authMethod,
|
||||
Defaults: defaults,
|
||||
Branding: settings.Branding{
|
||||
Name: mustGetString(flags, "branding.name"),
|
||||
DisableExternal: mustGetBool(flags, "branding.disableExternal"),
|
||||
|
||||
@@ -51,6 +51,8 @@ you want to change. Other options will remain unchanged.`,
|
||||
set.Shell = convertCmdStrToCmdArray(mustGetString(flags, flag.Name))
|
||||
case "create-user-dir":
|
||||
set.CreateUserDir = mustGetBool(flags, flag.Name)
|
||||
case "minimum-password-length":
|
||||
set.MinimumPasswordLength = mustGetUint(flags, flag.Name)
|
||||
case "branding.name":
|
||||
set.Branding.Name = mustGetString(flags, flag.Name)
|
||||
case "branding.color":
|
||||
|
||||
161
cmd/root.go
161
cmd/root.go
@@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/afero"
|
||||
@@ -48,7 +50,7 @@ func init() {
|
||||
persistent.StringP("database", "d", "./filebrowser.db", "database path")
|
||||
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
|
||||
flags.String("username", "admin", "username for the first user when using quick config")
|
||||
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
||||
flags.String("password", "", "hashed password for the first user when using quick config")
|
||||
|
||||
addServerFlags(flags)
|
||||
}
|
||||
@@ -61,14 +63,14 @@ func addServerFlags(flags *pflag.FlagSet) {
|
||||
flags.StringP("key", "k", "", "tls key")
|
||||
flags.StringP("root", "r", ".", "root to prepend to relative paths")
|
||||
flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)")
|
||||
flags.Uint32("socket-perm", 0666, "unix socket file permissions") //nolint:gomnd
|
||||
flags.Uint32("socket-perm", 0666, "unix socket file permissions")
|
||||
flags.StringP("baseurl", "b", "", "base url")
|
||||
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
|
||||
flags.String("token-expiration-time", "2h", "user session timeout")
|
||||
flags.Int("img-processors", 4, "image processors count") //nolint:gomnd
|
||||
flags.Int("img-processors", 4, "image processors count") //nolint:mnd
|
||||
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
|
||||
flags.Bool("disable-preview-resize", false, "disable resize of image previews")
|
||||
flags.Bool("disable-exec", false, "disables Command Runner feature")
|
||||
flags.Bool("disable-exec", true, "disables Command Runner feature")
|
||||
flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers")
|
||||
}
|
||||
|
||||
@@ -76,7 +78,7 @@ var rootCmd = &cobra.Command{
|
||||
Use: "filebrowser",
|
||||
Short: "A stylish web-based file browser",
|
||||
Long: `File Browser CLI lets you create the database to use with File Browser,
|
||||
manage your users and all the configurations without acessing the
|
||||
manage your users and all the configurations without accessing the
|
||||
web interface.
|
||||
|
||||
If you've never run File Browser, you'll need to have a database for
|
||||
@@ -108,7 +110,7 @@ name in caps. So to set "database" via an env variable, you should
|
||||
set FB_DATABASE.
|
||||
|
||||
Also, if the database path doesn't exist, File Browser will enter into
|
||||
the quick setup mode and a new database will be bootstraped and a new
|
||||
the quick setup mode and a new database will be bootstrapped and a new
|
||||
user created with the credentials from options "username" and "password".`,
|
||||
Run: python(func(cmd *cobra.Command, _ []string, d pythonData) {
|
||||
log.Println(cfgFile)
|
||||
@@ -129,7 +131,7 @@ user created with the credentials from options "username" and "password".`,
|
||||
cacheDir, err := cmd.Flags().GetString("cache-dir")
|
||||
checkErr(err)
|
||||
if cacheDir != "" {
|
||||
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet,gomnd
|
||||
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet
|
||||
log.Fatalf("can't make directory %s: %s", cacheDir, err)
|
||||
}
|
||||
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
||||
@@ -167,10 +169,6 @@ user created with the credentials from options "username" and "password".`,
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
|
||||
go cleanupHandler(listener, sigc)
|
||||
|
||||
assetsFs, err := fs.Sub(frontend.Assets(), "dist")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -182,18 +180,31 @@ user created with the credentials from options "username" and "password".`,
|
||||
defer listener.Close()
|
||||
|
||||
log.Println("Listening on", listener.Addr().String())
|
||||
//nolint: gosec
|
||||
if err := http.Serve(listener, handler); err != nil {
|
||||
log.Fatal(err)
|
||||
srv := &http.Server{
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 60 * time.Second,
|
||||
}
|
||||
}, pythonConfig{allowNoDB: true}),
|
||||
}
|
||||
|
||||
func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfacer
|
||||
sig := <-c
|
||||
log.Printf("Caught signal %s: shutting down.", sig)
|
||||
listener.Close()
|
||||
os.Exit(0)
|
||||
go func() {
|
||||
if err := srv.Serve(listener); !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Fatalf("HTTP server error: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Stopped serving new connections.")
|
||||
}()
|
||||
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
|
||||
<-sigc
|
||||
|
||||
shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second) //nolint:mnd
|
||||
defer shutdownRelease()
|
||||
|
||||
if err := srv.Shutdown(shutdownCtx); err != nil {
|
||||
log.Fatalf("HTTP shutdown error: %v", err)
|
||||
}
|
||||
log.Println("Graceful shutdown complete.")
|
||||
}, pythonConfig{allowNoDB: true}),
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
@@ -201,42 +212,42 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
||||
server, err := st.Settings.GetServer()
|
||||
checkErr(err)
|
||||
|
||||
if val, set := getParamB(flags, "root"); set {
|
||||
if val, set := getStringParamB(flags, "root"); set {
|
||||
server.Root = val
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "baseurl"); set {
|
||||
if val, set := getStringParamB(flags, "baseurl"); set {
|
||||
server.BaseURL = val
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "log"); set {
|
||||
if val, set := getStringParamB(flags, "log"); set {
|
||||
server.Log = val
|
||||
}
|
||||
|
||||
isSocketSet := false
|
||||
isAddrSet := false
|
||||
|
||||
if val, set := getParamB(flags, "address"); set {
|
||||
if val, set := getStringParamB(flags, "address"); set {
|
||||
server.Address = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "port"); set {
|
||||
if val, set := getStringParamB(flags, "port"); set {
|
||||
server.Port = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "key"); set {
|
||||
if val, set := getStringParamB(flags, "key"); set {
|
||||
server.TLSKey = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "cert"); set {
|
||||
if val, set := getStringParamB(flags, "cert"); set {
|
||||
server.TLSCert = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "socket"); set {
|
||||
if val, set := getStringParamB(flags, "socket"); set {
|
||||
server.Socket = val
|
||||
isSocketSet = isSocketSet || set
|
||||
}
|
||||
@@ -250,33 +261,69 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
||||
server.Socket = ""
|
||||
}
|
||||
|
||||
_, disableThumbnails := getParamB(flags, "disable-thumbnails")
|
||||
disableThumbnails := getBoolParam(flags, "disable-thumbnails")
|
||||
server.EnableThumbnails = !disableThumbnails
|
||||
|
||||
_, disablePreviewResize := getParamB(flags, "disable-preview-resize")
|
||||
disablePreviewResize := getBoolParam(flags, "disable-preview-resize")
|
||||
server.ResizePreview = !disablePreviewResize
|
||||
|
||||
_, disableTypeDetectionByHeader := getParamB(flags, "disable-type-detection-by-header")
|
||||
disableTypeDetectionByHeader := getBoolParam(flags, "disable-type-detection-by-header")
|
||||
server.TypeDetectionByHeader = !disableTypeDetectionByHeader
|
||||
|
||||
_, disableExec := getParamB(flags, "disable-exec")
|
||||
disableExec := getBoolParam(flags, "disable-exec")
|
||||
server.EnableExec = !disableExec
|
||||
|
||||
if val, set := getParamB(flags, "token-expiration-time"); set {
|
||||
if server.EnableExec {
|
||||
log.Println("WARNING: Command Runner feature enabled!")
|
||||
log.Println("WARNING: This feature has known security vulnerabilities and should not")
|
||||
log.Println("WARNING: you fully understand the risks involved. For more information")
|
||||
log.Println("WARNING: read https://github.com/filebrowser/filebrowser/issues/5199")
|
||||
}
|
||||
|
||||
if val, set := getStringParamB(flags, "token-expiration-time"); set {
|
||||
server.TokenExpirationTime = val
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
// getParamB returns a parameter as a string and a boolean to tell if it is different from the default
|
||||
// getBoolParamB returns a parameter as a string and a boolean to tell if it is different from the default
|
||||
//
|
||||
// NOTE: we could simply bind the flags to viper and use IsSet.
|
||||
// Although there is a bug on Viper that always returns true on IsSet
|
||||
// if a flag is binded. Our alternative way is to manually check
|
||||
// the flag and then the value from env/config/gotten by viper.
|
||||
// https://github.com/spf13/viper/pull/331
|
||||
func getParamB(flags *pflag.FlagSet, key string) (string, bool) {
|
||||
func getBoolParamB(flags *pflag.FlagSet, key string) (value, ok bool) {
|
||||
value, _ = flags.GetBool(key)
|
||||
|
||||
// If set on Flags, use it.
|
||||
if flags.Changed(key) {
|
||||
return value, true
|
||||
}
|
||||
|
||||
// If set through viper (env, config), return it.
|
||||
if v.IsSet(key) {
|
||||
return v.GetBool(key), true
|
||||
}
|
||||
|
||||
// Otherwise use default value on flags.
|
||||
return value, false
|
||||
}
|
||||
|
||||
func getBoolParam(flags *pflag.FlagSet, key string) bool {
|
||||
val, _ := getBoolParamB(flags, key)
|
||||
return val
|
||||
}
|
||||
|
||||
// getStringParamB returns a parameter as a string and a boolean to tell if it is different from the default
|
||||
//
|
||||
// NOTE: we could simply bind the flags to viper and use IsSet.
|
||||
// Although there is a bug on Viper that always returns true on IsSet
|
||||
// if a flag is binded. Our alternative way is to manually check
|
||||
// the flag and then the value from env/config/gotten by viper.
|
||||
// https://github.com/spf13/viper/pull/331
|
||||
func getStringParamB(flags *pflag.FlagSet, key string) (string, bool) {
|
||||
value, _ := flags.GetString(key)
|
||||
|
||||
// If set on Flags, use it.
|
||||
@@ -293,8 +340,8 @@ func getParamB(flags *pflag.FlagSet, key string) (string, bool) {
|
||||
return value, false
|
||||
}
|
||||
|
||||
func getParam(flags *pflag.FlagSet, key string) string {
|
||||
val, _ := getParamB(flags, key)
|
||||
func getStringParam(flags *pflag.FlagSet, key string) string {
|
||||
val, _ := getStringParamB(flags, key)
|
||||
return val
|
||||
}
|
||||
|
||||
@@ -318,10 +365,11 @@ func setupLog(logMethod string) {
|
||||
|
||||
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
set := &settings.Settings{
|
||||
Key: generateKey(),
|
||||
Signup: false,
|
||||
CreateUserDir: false,
|
||||
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
|
||||
Key: generateKey(),
|
||||
Signup: false,
|
||||
CreateUserDir: false,
|
||||
MinimumPasswordLength: settings.DefaultMinimumPasswordLength,
|
||||
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
@@ -349,7 +397,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
}
|
||||
|
||||
var err error
|
||||
if _, noauth := getParamB(flags, "noauth"); noauth {
|
||||
if _, noauth := getStringParamB(flags, "noauth"); noauth {
|
||||
set.AuthMethod = auth.MethodNoAuth
|
||||
err = d.store.Auth.Save(&auth.NoAuth{})
|
||||
} else {
|
||||
@@ -362,23 +410,29 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
checkErr(err)
|
||||
|
||||
ser := &settings.Server{
|
||||
BaseURL: getParam(flags, "baseurl"),
|
||||
Port: getParam(flags, "port"),
|
||||
Log: getParam(flags, "log"),
|
||||
TLSKey: getParam(flags, "key"),
|
||||
TLSCert: getParam(flags, "cert"),
|
||||
Address: getParam(flags, "address"),
|
||||
Root: getParam(flags, "root"),
|
||||
BaseURL: getStringParam(flags, "baseurl"),
|
||||
Port: getStringParam(flags, "port"),
|
||||
Log: getStringParam(flags, "log"),
|
||||
TLSKey: getStringParam(flags, "key"),
|
||||
TLSCert: getStringParam(flags, "cert"),
|
||||
Address: getStringParam(flags, "address"),
|
||||
Root: getStringParam(flags, "root"),
|
||||
}
|
||||
|
||||
err = d.store.Settings.SaveServer(ser)
|
||||
checkErr(err)
|
||||
|
||||
username := getParam(flags, "username")
|
||||
password := getParam(flags, "password")
|
||||
username := getStringParam(flags, "username")
|
||||
password := getStringParam(flags, "password")
|
||||
|
||||
if password == "" {
|
||||
password, err = users.HashPwd("admin")
|
||||
var pwd string
|
||||
pwd, err = users.RandomPwd(set.MinimumPasswordLength)
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Randomly generated password for user 'admin':", pwd)
|
||||
|
||||
password, err = users.HashAndValidatePwd(pwd, set.MinimumPasswordLength)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
@@ -414,6 +468,7 @@ func initConfig() {
|
||||
v.SetEnvPrefix("FB")
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
var configParseError v.ConfigParseError
|
||||
|
||||
@@ -25,7 +25,7 @@ this version.`,
|
||||
flags := cmd.Flags()
|
||||
oldDB := mustGetString(flags, "old.database")
|
||||
oldConf := mustGetString(flags, "old.config")
|
||||
err := importer.Import(oldDB, oldConf, getParam(flags, "database"))
|
||||
err := importer.Import(oldDB, oldConf, getStringParam(flags, "database"))
|
||||
checkErr(err)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ var usersAddCmd = &cobra.Command{
|
||||
checkErr(err)
|
||||
getUserDefaults(cmd.Flags(), &s.Defaults, false)
|
||||
|
||||
password, err := users.HashPwd(args[1])
|
||||
password, err := users.HashAndValidatePwd(args[1], s.MinimumPasswordLength)
|
||||
checkErr(err)
|
||||
|
||||
user := &users.User{
|
||||
|
||||
@@ -27,8 +27,10 @@ options you want to change.`,
|
||||
password := mustGetString(flags, "password")
|
||||
newUsername := mustGetString(flags, "username")
|
||||
|
||||
s, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
var (
|
||||
err error
|
||||
user *users.User
|
||||
)
|
||||
|
||||
@@ -64,7 +66,7 @@ options you want to change.`,
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
user.Password, err = users.HashPwd(password)
|
||||
user.Password, err = users.HashAndValidatePwd(password, s.MinimumPasswordLength)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
|
||||
11
cmd/utils.go
11
cmd/utils.go
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/files"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/storage/bolt"
|
||||
@@ -72,7 +73,7 @@ func dbExists(path string) (bool, error) {
|
||||
d := filepath.Dir(path)
|
||||
_, err = os.Stat(d)
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet,gomnd
|
||||
if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
@@ -86,7 +87,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
data := pythonData{hadDB: true}
|
||||
|
||||
path := getParam(cmd.Flags(), "database")
|
||||
path := getStringParam(cmd.Flags(), "database")
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -105,7 +106,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||
|
||||
log.Println("Using database: " + absPath)
|
||||
data.hadDB = exists
|
||||
db, err := storm.Open(path)
|
||||
db, err := storm.Open(path, storm.BoltOptions(files.PermFile, nil))
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
data.store, err = bolt.NewStorage(db)
|
||||
@@ -124,7 +125,7 @@ func marshal(filename string, data interface{}) error {
|
||||
encoder := json.NewEncoder(fd)
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(data)
|
||||
case ".yml", ".yaml": //nolint:goconst
|
||||
case ".yml", ".yaml":
|
||||
encoder := yaml.NewEncoder(fd)
|
||||
return encoder.Encode(data)
|
||||
default:
|
||||
@@ -188,7 +189,7 @@ func cleanUpMapValue(v interface{}) interface{} {
|
||||
}
|
||||
|
||||
// convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
|
||||
// then returns empty string array, else returns the splitted word array of cmd.
|
||||
// then returns empty string array, else returns the split word array of cmd.
|
||||
// This is to ensure the result will never be []string{""}
|
||||
func convertCmdStrToCmdArray(cmd string) []string {
|
||||
var cmdArray []string
|
||||
|
||||
@@ -37,11 +37,11 @@ func (f *FileCache) Store(_ context.Context, key string, value []byte) error {
|
||||
defer mu.Unlock()
|
||||
|
||||
fileName := f.getFileName(key)
|
||||
if err := f.fs.MkdirAll(filepath.Dir(fileName), 0700); err != nil { //nolint:gomnd
|
||||
if err := f.fs.MkdirAll(filepath.Dir(fileName), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := afero.WriteFile(f.fs, fileName, value, 0700); err != nil { //nolint:gomnd
|
||||
if err := afero.WriteFile(f.fs, fileName, value, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
41
docker/alpine/init.sh
Executable file
41
docker/alpine/init.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# Backwards compatibility for old Docker image
|
||||
if [ -f "/.filebrowser.json" ]; then
|
||||
ln -s /.filebrowser.json /config/settings.json
|
||||
|
||||
echo ""
|
||||
echo "!!!!!!!!!!!!!!!!!!!!! IMPORTANT INFORMATION !!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Symlinking /.filebrowser.json to /config/settings.json for backwards compatibility."
|
||||
echo ""
|
||||
echo "The volume mount configuration has changed in the latest release."
|
||||
echo "Please rename .filebrowser.json to settings.json and mount the parent directory to /config".
|
||||
echo "Read more on https://github.com/filebrowser/filebrowser/blob/master/docs/installation.md#docker"
|
||||
echo ""
|
||||
echo "This workaround will be removed in a future release."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Backwards compatibility for old Docker image
|
||||
if [ -f "/database.db" ]; then
|
||||
ln -s /database.db /database/filebrowser.db
|
||||
|
||||
echo ""
|
||||
echo "!!!!!!!!!!!!!!!!!!!!! IMPORTANT INFORMATION !!!!!!!!!!!!!!!!!!!!!"
|
||||
echo ""
|
||||
echo "The volume mount configuration has changed in the latest release."
|
||||
echo "Please rename database.db to filebrowser.db and mount the parent directory to /database".
|
||||
echo "Read more on https://github.com/filebrowser/filebrowser/blob/master/docs/installation.md#docker"
|
||||
echo ""
|
||||
echo "This workaround will be removed in a future release."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Ensure configuration exists
|
||||
if [ ! -f "/config/settings.json" ]; then
|
||||
cp -a /defaults/settings.json /config/settings.json
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
9
docker/common/healthcheck.sh
Executable file
9
docker/common/healthcheck.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
PORT=${FB_PORT:-$(jq -r .port /config/settings.json)}
|
||||
ADDRESS=${FB_ADDRESS:-$(jq -r .address /config/settings.json)}
|
||||
ADDRESS=${ADDRESS:-localhost}
|
||||
|
||||
curl -f http://$ADDRESS:$PORT/health || exit 1
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
|
||||
exec s6-setuidgid abc filebrowser -c /config/settings.json -d /database/filebrowser.db;
|
||||
7
docker/root/etc/cont-init.d/20-config → docker/s6/custom-cont-init.d/20-config
Normal file → Executable file
7
docker/root/etc/cont-init.d/20-config → docker/s6/custom-cont-init.d/20-config
Normal file → Executable file
@@ -1,9 +1,6 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
|
||||
# make folders
|
||||
mkdir -p /database
|
||||
|
||||
# copy config
|
||||
# Ensure configuration exists
|
||||
if [ ! -f "/config/settings.json" ]; then
|
||||
cp -a /defaults/settings.json /config/settings.json
|
||||
fi
|
||||
@@ -12,4 +9,4 @@ fi
|
||||
chown abc:abc \
|
||||
/config/settings.json \
|
||||
/database \
|
||||
/srv
|
||||
/srv
|
||||
3
docker/s6/etc/services.d/filebrowser/run
Executable file
3
docker/s6/etc/services.d/filebrowser/run
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
|
||||
exec s6-setuidgid abc filebrowser -c /config/settings.json;
|
||||
@@ -7,6 +7,7 @@ var (
|
||||
ErrExist = errors.New("the resource already exists")
|
||||
ErrNotExist = errors.New("the resource does not exist")
|
||||
ErrEmptyPassword = errors.New("password is empty")
|
||||
ErrShortPassword = errors.New("password is too short")
|
||||
ErrEmptyUsername = errors.New("username is empty")
|
||||
ErrEmptyRequest = errors.New("empty request")
|
||||
ErrScopeIsRelative = errors.New("scope is a relative path")
|
||||
|
||||
@@ -27,8 +27,8 @@ import (
|
||||
"github.com/filebrowser/filebrowser/v2/rules"
|
||||
)
|
||||
|
||||
const PermFile = 0644
|
||||
const PermDir = 0755
|
||||
const PermFile = 0640
|
||||
const PermDir = 0750
|
||||
|
||||
var (
|
||||
reSubDirs = regexp.MustCompile("(?i)^sub(s|titles)$")
|
||||
@@ -86,6 +86,11 @@ func NewFileInfo(opts *FileOptions) (*FileInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do not expose the name of root directory.
|
||||
if file.Path == "/" {
|
||||
file.Name = ""
|
||||
}
|
||||
|
||||
if opts.Expand {
|
||||
if file.IsDir {
|
||||
if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { //nolint:govet
|
||||
@@ -217,7 +222,6 @@ func (i *FileInfo) RealPath() string {
|
||||
return i.Path
|
||||
}
|
||||
|
||||
//nolint:goconst
|
||||
func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error {
|
||||
if IsNamedPipe(i.Mode) {
|
||||
i.Type = "blob"
|
||||
@@ -314,7 +318,7 @@ func (i *FileInfo) readFirstBytes() []byte {
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
buffer := make([]byte, 512) //nolint:gomnd
|
||||
buffer := make([]byte, 512)
|
||||
n, err := reader.Read(buffer)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.Print(err)
|
||||
|
||||
@@ -16,8 +16,6 @@ type Listing struct {
|
||||
}
|
||||
|
||||
// ApplySort applies the sort order using .Order and .Sort
|
||||
//
|
||||
//nolint:goconst
|
||||
func (l Listing) ApplySort() {
|
||||
// Check '.Order' to know how to sort
|
||||
if !l.Sorting.Asc {
|
||||
|
||||
609
files/mime.go
Normal file
609
files/mime.go
Normal file
@@ -0,0 +1,609 @@
|
||||
package files
|
||||
|
||||
// This file contains code primarily sourced from::
|
||||
// github.com/kataras/iris
|
||||
|
||||
import (
|
||||
"mime"
|
||||
)
|
||||
|
||||
const (
|
||||
// ContentBinaryHeaderValue header value for binary data.
|
||||
ContentBinaryHeaderValue = "application/octet-stream"
|
||||
// ContentWebassemblyHeaderValue header value for web assembly files.
|
||||
ContentWebassemblyHeaderValue = "application/wasm"
|
||||
// ContentHTMLHeaderValue is the string of text/html response header's content type value.
|
||||
ContentHTMLHeaderValue = "text/html"
|
||||
// ContentJSONHeaderValue header value for JSON data.
|
||||
ContentJSONHeaderValue = "application/json"
|
||||
// ContentJSONProblemHeaderValue header value for JSON API problem error.
|
||||
// Read more at: https://tools.ietf.org/html/rfc7807
|
||||
ContentJSONProblemHeaderValue = "application/problem+json"
|
||||
// ContentXMLProblemHeaderValue header value for XML API problem error.
|
||||
// Read more at: https://tools.ietf.org/html/rfc7807
|
||||
ContentXMLProblemHeaderValue = "application/problem+xml"
|
||||
// ContentJavascriptHeaderValue header value for JSONP & Javascript data.
|
||||
ContentJavascriptHeaderValue = "text/javascript"
|
||||
// ContentTextHeaderValue header value for Text data.
|
||||
ContentTextHeaderValue = "text/plain"
|
||||
// ContentXMLHeaderValue header value for XML data.
|
||||
ContentXMLHeaderValue = "text/xml"
|
||||
// ContentXMLUnreadableHeaderValue obsolete header value for XML.
|
||||
ContentXMLUnreadableHeaderValue = "application/xml"
|
||||
// ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
|
||||
ContentMarkdownHeaderValue = "text/markdown"
|
||||
// ContentYAMLHeaderValue header value for YAML data.
|
||||
ContentYAMLHeaderValue = "application/x-yaml"
|
||||
// ContentYAMLTextHeaderValue header value for YAML plain text.
|
||||
ContentYAMLTextHeaderValue = "text/yaml"
|
||||
// ContentProtobufHeaderValue header value for Protobuf messages data.
|
||||
ContentProtobufHeaderValue = "application/x-protobuf"
|
||||
// ContentMsgPackHeaderValue header value for MsgPack data.
|
||||
ContentMsgPackHeaderValue = "application/msgpack"
|
||||
// ContentMsgPack2HeaderValue alternative header value for MsgPack data.
|
||||
ContentMsgPack2HeaderValue = "application/x-msgpack"
|
||||
// ContentFormHeaderValue header value for post form data.
|
||||
ContentFormHeaderValue = "application/x-www-form-urlencoded"
|
||||
// ContentFormMultipartHeaderValue header value for post multipart form data.
|
||||
ContentFormMultipartHeaderValue = "multipart/form-data"
|
||||
// ContentMultipartRelatedHeaderValue header value for multipart related data.
|
||||
ContentMultipartRelatedHeaderValue = "multipart/related"
|
||||
// ContentGRPCHeaderValue Content-Type header value for gRPC.
|
||||
ContentGRPCHeaderValue = "application/grpc"
|
||||
)
|
||||
|
||||
var types = map[string]string{
|
||||
".3dm": "x-world/x-3dmf",
|
||||
".3dmf": "x-world/x-3dmf",
|
||||
".7z": "application/x-7z-compressed",
|
||||
".a": "application/octet-stream",
|
||||
".aab": "application/x-authorware-bin",
|
||||
".aam": "application/x-authorware-map",
|
||||
".aas": "application/x-authorware-seg",
|
||||
".abc": "text/vndabc",
|
||||
".ace": "application/x-ace-compressed",
|
||||
".acgi": "text/html",
|
||||
".afl": "video/animaflex",
|
||||
".ai": "application/postscript",
|
||||
".aif": "audio/aiff",
|
||||
".aifc": "audio/aiff",
|
||||
".aiff": "audio/aiff",
|
||||
".aim": "application/x-aim",
|
||||
".aip": "text/x-audiosoft-intra",
|
||||
".alz": "application/x-alz-compressed",
|
||||
".ani": "application/x-navi-animation",
|
||||
".aos": "application/x-nokia-9000-communicator-add-on-software",
|
||||
".aps": "application/mime",
|
||||
".apk": "application/vnd.android.package-archive",
|
||||
".arc": "application/x-arc-compressed",
|
||||
".arj": "application/arj",
|
||||
".art": "image/x-jg",
|
||||
".asf": "video/x-ms-asf",
|
||||
".asm": "text/x-asm",
|
||||
".asp": "text/asp",
|
||||
".asx": "application/x-mplayer2",
|
||||
".au": "audio/basic",
|
||||
".avi": "video/x-msvideo",
|
||||
".avs": "video/avs-video",
|
||||
".bcpio": "application/x-bcpio",
|
||||
".bin": "application/mac-binary",
|
||||
".bmp": "image/bmp",
|
||||
".boo": "application/book",
|
||||
".book": "application/book",
|
||||
".boz": "application/x-bzip2",
|
||||
".bsh": "application/x-bsh",
|
||||
".bz2": "application/x-bzip2",
|
||||
".bz": "application/x-bzip",
|
||||
".c++": ContentTextHeaderValue,
|
||||
".c": "text/x-c",
|
||||
".cab": "application/vnd.ms-cab-compressed",
|
||||
".cat": "application/vndms-pkiseccat",
|
||||
".cc": "text/x-c",
|
||||
".ccad": "application/clariscad",
|
||||
".cco": "application/x-cocoa",
|
||||
".cdf": "application/cdf",
|
||||
".cer": "application/pkix-cert",
|
||||
".cha": "application/x-chat",
|
||||
".chat": "application/x-chat",
|
||||
".chrt": "application/vnd.kde.kchart",
|
||||
".class": "application/java",
|
||||
".com": ContentTextHeaderValue,
|
||||
".conf": ContentTextHeaderValue,
|
||||
".cpio": "application/x-cpio",
|
||||
".cpp": "text/x-c",
|
||||
".cpt": "application/mac-compactpro",
|
||||
".crl": "application/pkcs-crl",
|
||||
".crt": "application/pkix-cert",
|
||||
".crx": "application/x-chrome-extension",
|
||||
".csh": "text/x-scriptcsh",
|
||||
".css": "text/css",
|
||||
".csv": "text/csv",
|
||||
".cxx": ContentTextHeaderValue,
|
||||
".dar": "application/x-dar",
|
||||
".dcr": "application/x-director",
|
||||
".deb": "application/x-debian-package",
|
||||
".deepv": "application/x-deepv",
|
||||
".def": ContentTextHeaderValue,
|
||||
".der": "application/x-x509-ca-cert",
|
||||
".dif": "video/x-dv",
|
||||
".dir": "application/x-director",
|
||||
".divx": "video/divx",
|
||||
".dl": "video/dl",
|
||||
".dmg": "application/x-apple-diskimage",
|
||||
".doc": "application/msword",
|
||||
".dot": "application/msword",
|
||||
".dp": "application/commonground",
|
||||
".drw": "application/drafting",
|
||||
".dump": "application/octet-stream",
|
||||
".dv": "video/x-dv",
|
||||
".dvi": "application/x-dvi",
|
||||
".dwf": "drawing/x-dwf=(old)",
|
||||
".dwg": "application/acad",
|
||||
".dxf": "application/dxf",
|
||||
".dxr": "application/x-director",
|
||||
".el": "text/x-scriptelisp",
|
||||
".elc": "application/x-bytecodeelisp=(compiled=elisp)",
|
||||
".eml": "message/rfc822",
|
||||
".env": "application/x-envoy",
|
||||
".eps": "application/postscript",
|
||||
".es": "application/x-esrehber",
|
||||
".etx": "text/x-setext",
|
||||
".evy": "application/envoy",
|
||||
".exe": "application/octet-stream",
|
||||
".f77": "text/x-fortran",
|
||||
".f90": "text/x-fortran",
|
||||
".f": "text/x-fortran",
|
||||
".fdf": "application/vndfdf",
|
||||
".fif": "application/fractals",
|
||||
".fli": "video/fli",
|
||||
".flo": "image/florian",
|
||||
".flv": "video/x-flv",
|
||||
".flx": "text/vndfmiflexstor",
|
||||
".fmf": "video/x-atomic3d-feature",
|
||||
".for": "text/x-fortran",
|
||||
".fpx": "image/vndfpx",
|
||||
".frl": "application/freeloader",
|
||||
".funk": "audio/make",
|
||||
".g3": "image/g3fax",
|
||||
".g": ContentTextHeaderValue,
|
||||
".gif": "image/gif",
|
||||
".gl": "video/gl",
|
||||
".gsd": "audio/x-gsm",
|
||||
".gsm": "audio/x-gsm",
|
||||
".gsp": "application/x-gsp",
|
||||
".gss": "application/x-gss",
|
||||
".gtar": "application/x-gtar",
|
||||
".gz": "application/x-compressed",
|
||||
".gzip": "application/x-gzip",
|
||||
".h": "text/x-h",
|
||||
".hdf": "application/x-hdf",
|
||||
".help": "application/x-helpfile",
|
||||
".hgl": "application/vndhp-hpgl",
|
||||
".hh": "text/x-h",
|
||||
".hlb": "text/x-script",
|
||||
".hlp": "application/hlp",
|
||||
".hpg": "application/vndhp-hpgl",
|
||||
".hpgl": "application/vndhp-hpgl",
|
||||
".hqx": "application/binhex",
|
||||
".hta": "application/hta",
|
||||
".htc": "text/x-component",
|
||||
".htm": "text/html",
|
||||
".html": "text/html",
|
||||
".htmls": "text/html",
|
||||
".htt": "text/webviewhtml",
|
||||
".htx": "text/html",
|
||||
".ice": "x-conference/x-cooltalk",
|
||||
".ico": "image/x-icon",
|
||||
".ics": "text/calendar",
|
||||
".icz": "text/calendar",
|
||||
".idc": ContentTextHeaderValue,
|
||||
".ief": "image/ief",
|
||||
".iefs": "image/ief",
|
||||
".iges": "application/iges",
|
||||
".igs": "application/iges",
|
||||
".ima": "application/x-ima",
|
||||
".imap": "application/x-httpd-imap",
|
||||
".inf": "application/inf",
|
||||
".ins": "application/x-internett-signup",
|
||||
".ip": "application/x-ip2",
|
||||
".isu": "video/x-isvideo",
|
||||
".it": "audio/it",
|
||||
".iv": "application/x-inventor",
|
||||
".ivr": "i-world/i-vrml",
|
||||
".ivy": "application/x-livescreen",
|
||||
".jam": "audio/x-jam",
|
||||
".jav": "text/x-java-source",
|
||||
".java": "text/x-java-source",
|
||||
".jcm": "application/x-java-commerce",
|
||||
".jfif-tbnl": "image/jpeg",
|
||||
".jfif": "image/jpeg",
|
||||
".jnlp": "application/x-java-jnlp-file",
|
||||
".jpe": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".jpg": "image/jpeg",
|
||||
".jps": "image/x-jps",
|
||||
".js": ContentJavascriptHeaderValue,
|
||||
".mjs": ContentJavascriptHeaderValue,
|
||||
".json": ContentJSONHeaderValue,
|
||||
".vue": ContentJavascriptHeaderValue,
|
||||
".jut": "image/jutvision",
|
||||
".kar": "audio/midi",
|
||||
".karbon": "application/vnd.kde.karbon",
|
||||
".kfo": "application/vnd.kde.kformula",
|
||||
".flw": "application/vnd.kde.kivio",
|
||||
".kml": "application/vnd.google-earth.kml+xml",
|
||||
".kmz": "application/vnd.google-earth.kmz",
|
||||
".kon": "application/vnd.kde.kontour",
|
||||
".kpr": "application/vnd.kde.kpresenter",
|
||||
".kpt": "application/vnd.kde.kpresenter",
|
||||
".ksp": "application/vnd.kde.kspread",
|
||||
".kwd": "application/vnd.kde.kword",
|
||||
".kwt": "application/vnd.kde.kword",
|
||||
".ksh": "text/x-scriptksh",
|
||||
".la": "audio/nspaudio",
|
||||
".lam": "audio/x-liveaudio",
|
||||
".latex": "application/x-latex",
|
||||
".lha": "application/lha",
|
||||
".lhx": "application/octet-stream",
|
||||
".list": ContentTextHeaderValue,
|
||||
".lma": "audio/nspaudio",
|
||||
".log": ContentTextHeaderValue,
|
||||
".lsp": "text/x-scriptlisp",
|
||||
".lst": ContentTextHeaderValue,
|
||||
".lsx": "text/x-la-asf",
|
||||
".ltx": "application/x-latex",
|
||||
".lzh": "application/octet-stream",
|
||||
".lzx": "application/lzx",
|
||||
".m1v": "video/mpeg",
|
||||
".m2a": "audio/mpeg",
|
||||
".m2v": "video/mpeg",
|
||||
".m3u": "audio/x-mpegurl",
|
||||
".m": "text/x-m",
|
||||
".man": "application/x-troff-man",
|
||||
".manifest": "text/cache-manifest",
|
||||
".map": "application/x-navimap",
|
||||
".mar": ContentTextHeaderValue,
|
||||
".mbd": "application/mbedlet",
|
||||
".mc$": "application/x-magic-cap-package-10",
|
||||
".mcd": "application/mcad",
|
||||
".mcf": "text/mcf",
|
||||
".mcp": "application/netmc",
|
||||
".me": "application/x-troff-me",
|
||||
".mht": "message/rfc822",
|
||||
".mhtml": "message/rfc822",
|
||||
".mid": "application/x-midi",
|
||||
".midi": "application/x-midi",
|
||||
".mif": "application/x-frame",
|
||||
".mime": "message/rfc822",
|
||||
".mjf": "audio/x-vndaudioexplosionmjuicemediafile",
|
||||
".mjpg": "video/x-motion-jpeg",
|
||||
".mm": "application/base64",
|
||||
".mme": "application/base64",
|
||||
".mod": "audio/mod",
|
||||
".moov": "video/quicktime",
|
||||
".mov": "video/quicktime",
|
||||
".movie": "video/x-sgi-movie",
|
||||
".mp2": "audio/mpeg",
|
||||
".mp3": "audio/mpeg",
|
||||
".mp4": "video/mp4",
|
||||
".mpa": "audio/mpeg",
|
||||
".mpc": "application/x-project",
|
||||
".mpe": "video/mpeg",
|
||||
".mpeg": "video/mpeg",
|
||||
".mpg": "video/mpeg",
|
||||
".mpga": "audio/mpeg",
|
||||
".mpp": "application/vndms-project",
|
||||
".mpt": "application/x-project",
|
||||
".mpv": "application/x-project",
|
||||
".mpx": "application/x-project",
|
||||
".mrc": "application/marc",
|
||||
".ms": "application/x-troff-ms",
|
||||
".mv": "video/x-sgi-movie",
|
||||
".my": "audio/make",
|
||||
".mzz": "application/x-vndaudioexplosionmzz",
|
||||
".nap": "image/naplps",
|
||||
".naplps": "image/naplps",
|
||||
".nc": "application/x-netcdf",
|
||||
".ncm": "application/vndnokiaconfiguration-message",
|
||||
".nif": "image/x-niff",
|
||||
".niff": "image/x-niff",
|
||||
".nix": "application/x-mix-transfer",
|
||||
".nsc": "application/x-conference",
|
||||
".nvd": "application/x-navidoc",
|
||||
".o": "application/octet-stream",
|
||||
".oda": "application/oda",
|
||||
".odb": "application/vnd.oasis.opendocument.database",
|
||||
".odc": "application/vnd.oasis.opendocument.chart",
|
||||
".odf": "application/vnd.oasis.opendocument.formula",
|
||||
".odg": "application/vnd.oasis.opendocument.graphics",
|
||||
".odi": "application/vnd.oasis.opendocument.image",
|
||||
".odm": "application/vnd.oasis.opendocument.text-master",
|
||||
".odp": "application/vnd.oasis.opendocument.presentation",
|
||||
".ods": "application/vnd.oasis.opendocument.spreadsheet",
|
||||
".odt": "application/vnd.oasis.opendocument.text",
|
||||
".oga": "audio/ogg",
|
||||
".ogg": "audio/ogg",
|
||||
".ogv": "video/ogg",
|
||||
".omc": "application/x-omc",
|
||||
".omcd": "application/x-omcdatamaker",
|
||||
".omcr": "application/x-omcregerator",
|
||||
".otc": "application/vnd.oasis.opendocument.chart-template",
|
||||
".otf": "application/vnd.oasis.opendocument.formula-template",
|
||||
".otg": "application/vnd.oasis.opendocument.graphics-template",
|
||||
".oth": "application/vnd.oasis.opendocument.text-web",
|
||||
".oti": "application/vnd.oasis.opendocument.image-template",
|
||||
".otm": "application/vnd.oasis.opendocument.text-master",
|
||||
".otp": "application/vnd.oasis.opendocument.presentation-template",
|
||||
".ots": "application/vnd.oasis.opendocument.spreadsheet-template",
|
||||
".ott": "application/vnd.oasis.opendocument.text-template",
|
||||
".p10": "application/pkcs10",
|
||||
".p12": "application/pkcs-12",
|
||||
".p7a": "application/x-pkcs7-signature",
|
||||
".p7c": "application/pkcs7-mime",
|
||||
".p7m": "application/pkcs7-mime",
|
||||
".p7r": "application/x-pkcs7-certreqresp",
|
||||
".p7s": "application/pkcs7-signature",
|
||||
".p": "text/x-pascal",
|
||||
".part": "application/pro_eng",
|
||||
".pas": "text/pascal",
|
||||
".pbm": "image/x-portable-bitmap",
|
||||
".pcl": "application/vndhp-pcl",
|
||||
".pct": "image/x-pict",
|
||||
".pcx": "image/x-pcx",
|
||||
".pdb": "chemical/x-pdb",
|
||||
".pdf": "application/pdf",
|
||||
".pfunk": "audio/make",
|
||||
".pgm": "image/x-portable-graymap",
|
||||
".pic": "image/pict",
|
||||
".pict": "image/pict",
|
||||
".pkg": "application/x-newton-compatible-pkg",
|
||||
".pko": "application/vndms-pkipko",
|
||||
".pl": "text/x-scriptperl",
|
||||
".plx": "application/x-pixclscript",
|
||||
".pm4": "application/x-pagemaker",
|
||||
".pm5": "application/x-pagemaker",
|
||||
".pm": "text/x-scriptperl-module",
|
||||
".png": "image/png",
|
||||
".pnm": "application/x-portable-anymap",
|
||||
".pot": "application/mspowerpoint",
|
||||
".pov": "model/x-pov",
|
||||
".ppa": "application/vndms-powerpoint",
|
||||
".ppm": "image/x-portable-pixmap",
|
||||
".pps": "application/mspowerpoint",
|
||||
".ppt": "application/mspowerpoint",
|
||||
".ppz": "application/mspowerpoint",
|
||||
".pre": "application/x-freelance",
|
||||
".prt": "application/pro_eng",
|
||||
".ps": "application/postscript",
|
||||
".psd": "application/octet-stream",
|
||||
".pvu": "paleovu/x-pv",
|
||||
".pwz": "application/vndms-powerpoint",
|
||||
".py": "text/x-scriptphyton",
|
||||
".pyc": "application/x-bytecodepython",
|
||||
".qcp": "audio/vndqcelp",
|
||||
".qd3": "x-world/x-3dmf",
|
||||
".qd3d": "x-world/x-3dmf",
|
||||
".qif": "image/x-quicktime",
|
||||
".qt": "video/quicktime",
|
||||
".qtc": "video/x-qtc",
|
||||
".qti": "image/x-quicktime",
|
||||
".qtif": "image/x-quicktime",
|
||||
".ra": "audio/x-pn-realaudio",
|
||||
".ram": "audio/x-pn-realaudio",
|
||||
".rar": "application/x-rar-compressed",
|
||||
".ras": "application/x-cmu-raster",
|
||||
".rast": "image/cmu-raster",
|
||||
".rexx": "text/x-scriptrexx",
|
||||
".rf": "image/vndrn-realflash",
|
||||
".rgb": "image/x-rgb",
|
||||
".rm": "application/vndrn-realmedia",
|
||||
".rmi": "audio/mid",
|
||||
".rmm": "audio/x-pn-realaudio",
|
||||
".rmp": "audio/x-pn-realaudio",
|
||||
".rng": "application/ringing-tones",
|
||||
".rnx": "application/vndrn-realplayer",
|
||||
".roff": "application/x-troff",
|
||||
".rp": "image/vndrn-realpix",
|
||||
".rpm": "audio/x-pn-realaudio-plugin",
|
||||
".rt": "text/vndrn-realtext",
|
||||
".rtf": "text/richtext",
|
||||
".rtx": "text/richtext",
|
||||
".rv": "video/vndrn-realvideo",
|
||||
".s": "text/x-asm",
|
||||
".s3m": "audio/s3m",
|
||||
".s7z": "application/x-7z-compressed",
|
||||
".saveme": "application/octet-stream",
|
||||
".sbk": "application/x-tbook",
|
||||
".scm": "text/x-scriptscheme",
|
||||
".sdml": ContentTextHeaderValue,
|
||||
".sdp": "application/sdp",
|
||||
".sdr": "application/sounder",
|
||||
".sea": "application/sea",
|
||||
".set": "application/set",
|
||||
".sgm": "text/x-sgml",
|
||||
".sgml": "text/x-sgml",
|
||||
".sh": "text/x-scriptsh",
|
||||
".shar": "application/x-bsh",
|
||||
".shtml": "text/x-server-parsed-html",
|
||||
".sid": "audio/x-psid",
|
||||
".skd": "application/x-koan",
|
||||
".skm": "application/x-koan",
|
||||
".skp": "application/x-koan",
|
||||
".skt": "application/x-koan",
|
||||
".sit": "application/x-stuffit",
|
||||
".sitx": "application/x-stuffitx",
|
||||
".sl": "application/x-seelogo",
|
||||
".smi": "application/smil",
|
||||
".smil": "application/smil",
|
||||
".snd": "audio/basic",
|
||||
".sol": "application/solids",
|
||||
".spc": "text/x-speech",
|
||||
".spl": "application/futuresplash",
|
||||
".spr": "application/x-sprite",
|
||||
".sprite": "application/x-sprite",
|
||||
".spx": "audio/ogg",
|
||||
".src": "application/x-wais-source",
|
||||
".ssi": "text/x-server-parsed-html",
|
||||
".ssm": "application/streamingmedia",
|
||||
".sst": "application/vndms-pkicertstore",
|
||||
".step": "application/step",
|
||||
".stl": "application/sla",
|
||||
".stp": "application/step",
|
||||
".sv4cpio": "application/x-sv4cpio",
|
||||
".sv4crc": "application/x-sv4crc",
|
||||
".svf": "image/vnddwg",
|
||||
".svg": "image/svg+xml",
|
||||
".svr": "application/x-world",
|
||||
".swf": "application/x-shockwave-flash",
|
||||
".t": "application/x-troff",
|
||||
".talk": "text/x-speech",
|
||||
".tar": "application/x-tar",
|
||||
".tbk": "application/toolbook",
|
||||
".tcl": "text/x-scripttcl",
|
||||
".tcsh": "text/x-scripttcsh",
|
||||
".tex": "application/x-tex",
|
||||
".texi": "application/x-texinfo",
|
||||
".texinfo": "application/x-texinfo",
|
||||
".text": ContentTextHeaderValue,
|
||||
".tgz": "application/gnutar",
|
||||
".tif": "image/tiff",
|
||||
".tiff": "image/tiff",
|
||||
".tr": "application/x-troff",
|
||||
".tsi": "audio/tsp-audio",
|
||||
".tsp": "application/dsptype",
|
||||
".tsv": "text/tab-separated-values",
|
||||
".turbot": "image/florian",
|
||||
".txt": ContentTextHeaderValue,
|
||||
".uil": "text/x-uil",
|
||||
".uni": "text/uri-list",
|
||||
".unis": "text/uri-list",
|
||||
".unv": "application/i-deas",
|
||||
".uri": "text/uri-list",
|
||||
".uris": "text/uri-list",
|
||||
".ustar": "application/x-ustar",
|
||||
".uu": "text/x-uuencode",
|
||||
".uue": "text/x-uuencode",
|
||||
".vcd": "application/x-cdlink",
|
||||
".vcf": "text/x-vcard",
|
||||
".vcard": "text/x-vcard",
|
||||
".vcs": "text/x-vcalendar",
|
||||
".vda": "application/vda",
|
||||
".vdo": "video/vdo",
|
||||
".vew": "application/groupwise",
|
||||
".viv": "video/vivo",
|
||||
".vivo": "video/vivo",
|
||||
".vmd": "application/vocaltec-media-desc",
|
||||
".vmf": "application/vocaltec-media-file",
|
||||
".voc": "audio/voc",
|
||||
".vos": "video/vosaic",
|
||||
".vox": "audio/voxware",
|
||||
".vqe": "audio/x-twinvq-plugin",
|
||||
".vqf": "audio/x-twinvq",
|
||||
".vql": "audio/x-twinvq-plugin",
|
||||
".vrml": "application/x-vrml",
|
||||
".vrt": "x-world/x-vrt",
|
||||
".vsd": "application/x-visio",
|
||||
".vst": "application/x-visio",
|
||||
".vsw": "application/x-visio",
|
||||
".w60": "application/wordperfect60",
|
||||
".w61": "application/wordperfect61",
|
||||
".w6w": "application/msword",
|
||||
".wav": "audio/wav",
|
||||
".wb1": "application/x-qpro",
|
||||
".wbmp": "image/vnd.wap.wbmp",
|
||||
".web": "application/vndxara",
|
||||
".wiz": "application/msword",
|
||||
".wk1": "application/x-123",
|
||||
".wmf": "windows/metafile",
|
||||
".wml": "text/vnd.wap.wml",
|
||||
".wmlc": "application/vnd.wap.wmlc",
|
||||
".wmls": "text/vnd.wap.wmlscript",
|
||||
".wmlsc": "application/vnd.wap.wmlscriptc",
|
||||
".word": "application/msword",
|
||||
".wp5": "application/wordperfect",
|
||||
".wp6": "application/wordperfect",
|
||||
".wp": "application/wordperfect",
|
||||
".wpd": "application/wordperfect",
|
||||
".wq1": "application/x-lotus",
|
||||
".wri": "application/mswrite",
|
||||
".wrl": "application/x-world",
|
||||
".wrz": "model/vrml",
|
||||
".wsc": "text/scriplet",
|
||||
".wsrc": "application/x-wais-source",
|
||||
".wtk": "application/x-wintalk",
|
||||
".x-png": "image/png",
|
||||
".xbm": "image/x-xbitmap",
|
||||
".xdr": "video/x-amt-demorun",
|
||||
".xgz": "xgl/drawing",
|
||||
".xif": "image/vndxiff",
|
||||
".xl": "application/excel",
|
||||
".xla": "application/excel",
|
||||
".xlb": "application/excel",
|
||||
".xlc": "application/excel",
|
||||
".xld": "application/excel",
|
||||
".xlk": "application/excel",
|
||||
".xll": "application/excel",
|
||||
".xlm": "application/excel",
|
||||
".xls": "application/excel",
|
||||
".xlt": "application/excel",
|
||||
".xlv": "application/excel",
|
||||
".xlw": "application/excel",
|
||||
".xm": "audio/xm",
|
||||
".xml": ContentXMLHeaderValue,
|
||||
".xmz": "xgl/movie",
|
||||
".xpix": "application/x-vndls-xpix",
|
||||
".xpm": "image/x-xpixmap",
|
||||
".xsr": "video/x-amt-showrun",
|
||||
".xwd": "image/x-xwd",
|
||||
".xyz": "chemical/x-pdb",
|
||||
".z": "application/x-compress",
|
||||
".zip": "application/zip",
|
||||
".zoo": "application/octet-stream",
|
||||
".zsh": "text/x-scriptzsh",
|
||||
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
".docm": "application/vnd.ms-word.document.macroEnabled.12",
|
||||
".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
||||
".dotm": "application/vnd.ms-word.template.macroEnabled.12",
|
||||
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
|
||||
".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
||||
".xltm": "application/vnd.ms-excel.template.macroEnabled.12",
|
||||
".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
||||
".xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
|
||||
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
||||
".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
||||
".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
||||
".potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
|
||||
".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
|
||||
".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
|
||||
".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
|
||||
".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12",
|
||||
".thmx": "application/vnd.ms-officetheme",
|
||||
".onetoc": "application/onenote",
|
||||
".onetoc2": "application/onenote",
|
||||
".onetmp": "application/onenote",
|
||||
".onepkg": "application/onenote",
|
||||
".xpi": "application/x-xpinstall",
|
||||
".wasm": "application/wasm",
|
||||
".m4a": "audio/mp4",
|
||||
".flac": "audio/x-flac",
|
||||
".amr": "audio/amr",
|
||||
".aac": "audio/aac",
|
||||
".opus": "video/ogg",
|
||||
".m4v": "video/mp4",
|
||||
".mkv": "video/x-matroska",
|
||||
".caf": "audio/x-caf",
|
||||
".m3u8": "application/x-mpegURL",
|
||||
".mpd": "application/dash+xml",
|
||||
".webp": "image/webp",
|
||||
".epub": "application/epub+zip",
|
||||
}
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
for ext, typ := range types {
|
||||
// skip errors
|
||||
_ = mime.AddExtensionType(ext, typ)
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ func CommonPrefix(sep byte, paths ...string) string {
|
||||
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
||||
// path.Clean will have cleaned off trailing / separators with
|
||||
// the exception of the root directory, "/" (in which case we
|
||||
// make it "//", but this will get fixed up to "/" bellow).
|
||||
// make it "//", but this will get fixed up to "/" below).
|
||||
c = append(c, sep)
|
||||
|
||||
// Ignore the first path since it's already in c
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-typescript",
|
||||
"@vue/eslint-config-prettier"
|
||||
],
|
||||
"rules": {
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/no-mutating-props": [
|
||||
"error",
|
||||
{
|
||||
"shallowOnly": true
|
||||
}
|
||||
]
|
||||
// no-undef is already included in
|
||||
// @vue/eslint-config-typescript
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
# Ignore artifacts:
|
||||
dist
|
||||
dist
|
||||
pnpm-lock.yaml
|
||||
38
frontend/eslint.config.js
Normal file
38
frontend/eslint.config.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import pluginVue from "eslint-plugin-vue";
|
||||
import vueTsEslintConfig from "@vue/eslint-config-typescript";
|
||||
import prettierConfig from "@vue/eslint-config-prettier";
|
||||
|
||||
export default [
|
||||
{
|
||||
name: "app/files-to-lint",
|
||||
files: ["**/*.{ts,mts,tsx,vue}"],
|
||||
},
|
||||
|
||||
{
|
||||
name: "app/files-to-ignore",
|
||||
ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**"],
|
||||
},
|
||||
|
||||
...pluginVue.configs["flat/essential"],
|
||||
...vueTsEslintConfig(),
|
||||
prettierConfig,
|
||||
|
||||
{
|
||||
rules: {
|
||||
// Note: you must disable the base rule as it can report incorrect errors
|
||||
"no-unused-expressions": "off",
|
||||
"@typescript-eslint/no-unused-expressions": "off",
|
||||
// TODO: theres too many of these from before ts
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// TODO: finish the ts conversion
|
||||
"vue/block-lang": "off",
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/no-mutating-props": [
|
||||
"error",
|
||||
{
|
||||
shallowOnly: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
7705
frontend/package-lock.json
generated
7705
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,68 +4,75 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"npm": ">=7.0.0",
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=22.0.0",
|
||||
"pnpm": ">=9.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "npm run typecheck && vite build",
|
||||
"build": "pnpm run typecheck && vite build",
|
||||
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
|
||||
"typecheck": "vue-tsc -p ./tsconfig.json --noEmit",
|
||||
"lint": "npm run typecheck && eslint --ext .vue,.ts src/",
|
||||
"lint:fix": "eslint --ext .vue,.ts --fix src/",
|
||||
"typecheck": "vue-tsc -p ./tsconfig.tsc.json --noEmit",
|
||||
"lint": "eslint src/",
|
||||
"lint:fix": "eslint --fix src/",
|
||||
"format": "prettier --write .",
|
||||
"test": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chenfengyuan/vue-number-input": "^2.0.1",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"@vueuse/integrations": "^10.9.0",
|
||||
"ace-builds": "^1.32.9",
|
||||
"core-js": "^3.36.1",
|
||||
"@vueuse/core": "^12.5.0",
|
||||
"@vueuse/integrations": "^12.5.0",
|
||||
"ace-builds": "^1.37.5",
|
||||
"core-js": "^3.40.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"dompurify": "^3.2.6",
|
||||
"epubjs": "^0.3.93",
|
||||
"filesize": "^10.1.1",
|
||||
"js-base64": "^3.7.7",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"material-icons": "^1.13.12",
|
||||
"marked": "^15.0.6",
|
||||
"material-icons": "^1.13.13",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia": "^2.3.1",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"qrcode.vue": "^3.4.1",
|
||||
"tus-js-client": "^4.1.0",
|
||||
"tus-js-client": "^4.3.1",
|
||||
"utif": "^3.1.0",
|
||||
"video.js": "^8.10.0",
|
||||
"video.js": "^8.21.0",
|
||||
"videojs-hotkeys": "^0.2.28",
|
||||
"videojs-mobile-ui": "^1.1.1",
|
||||
"vue": "^3.4.21",
|
||||
"vue-final-modal": "^4.5.4",
|
||||
"vue-i18n": "^9.10.2",
|
||||
"vue-i18n": "^11.1.2",
|
||||
"vue-lazyload": "^3.0.0",
|
||||
"vue-reader": "^1.2.17",
|
||||
"vue-router": "^4.3.0",
|
||||
"vue-toastification": "^2.0.0-rc.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||
"@playwright/test": "^1.42.1",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.3",
|
||||
"@playwright/test": "^1.50.0",
|
||||
"@tsconfig/node22": "^22.0.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.12.2",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@vitejs/plugin-legacy": "^5.3.2",
|
||||
"@types/node": "^22.10.10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.21.0",
|
||||
"@vitejs/plugin-legacy": "^6.0.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"@vue/eslint-config-typescript": "^14.3.0",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"concurrently": "^9.1.2",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-vue": "^9.24.0",
|
||||
"jsdom": "^24.0.0",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.2.5",
|
||||
"terser": "^5.30.0",
|
||||
"vite": "^5.2.7",
|
||||
"jsdom": "^26.0.0",
|
||||
"postcss": "^8.5.1",
|
||||
"prettier": "^3.4.2",
|
||||
"terser": "^5.37.0",
|
||||
"vite": "^6.1.6",
|
||||
"vite-plugin-compression2": "^1.0.0",
|
||||
"vue-tsc": "^2.0.7"
|
||||
}
|
||||
"vue-tsc": "^2.2.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
|
||||
}
|
||||
|
||||
5442
frontend/pnpm-lock.yaml
generated
Normal file
5442
frontend/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
import { removePrefix } from "./utils";
|
||||
import { baseURL } from "@/utils/constants";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { removePrefix } from "./utils";
|
||||
|
||||
const ssl = window.location.protocol === "https:";
|
||||
const protocol = ssl ? "wss:" : "ws:";
|
||||
@@ -11,10 +10,8 @@ export default function command(
|
||||
onmessage: WebSocket["onmessage"],
|
||||
onclose: WebSocket["onclose"]
|
||||
) {
|
||||
const authStore = useAuthStore();
|
||||
|
||||
url = removePrefix(url);
|
||||
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${authStore.jwt}`;
|
||||
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}`;
|
||||
|
||||
const conn = new window.WebSocket(url);
|
||||
conn.onopen = () => conn.send(command);
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import { createURL, fetchURL, removePrefix } from "./utils";
|
||||
import { baseURL } from "@/utils/constants";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { baseURL } from "@/utils/constants";
|
||||
import { upload as postTus, useTus } from "./tus";
|
||||
import { createURL, fetchURL, removePrefix, StatusError } from "./utils";
|
||||
|
||||
export async function fetch(url: string) {
|
||||
export async function fetch(url: string, signal?: AbortSignal) {
|
||||
url = removePrefix(url);
|
||||
const res = await fetchURL(`/api/resources${url}`, { signal });
|
||||
|
||||
const res = await fetchURL(`/api/resources${url}`, {});
|
||||
|
||||
const data = (await res.json()) as Resource;
|
||||
let data: Resource;
|
||||
try {
|
||||
data = (await res.json()) as Resource;
|
||||
} catch (e) {
|
||||
// Check if the error is an intentional cancellation
|
||||
if (e instanceof Error && e.name === "AbortError") {
|
||||
throw new StatusError("000 No connection", 0, true);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
data.url = `/files${url}`;
|
||||
|
||||
if (data.isDir) {
|
||||
@@ -74,11 +83,6 @@ export function download(format: any, ...files: string[]) {
|
||||
url += `algo=${format}&`;
|
||||
}
|
||||
|
||||
const authStore = useAuthStore();
|
||||
if (authStore.jwt) {
|
||||
url += `auth=${authStore.jwt}&`;
|
||||
}
|
||||
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
@@ -156,6 +160,7 @@ function moveCopy(
|
||||
overwrite = false,
|
||||
rename = false
|
||||
) {
|
||||
const layoutStore = useLayoutStore();
|
||||
const promises = [];
|
||||
|
||||
for (const item of items) {
|
||||
@@ -166,7 +171,7 @@ function moveCopy(
|
||||
}&destination=${to}&override=${overwrite}&rename=${rename}`;
|
||||
promises.push(resourceAction(url, "PATCH"));
|
||||
}
|
||||
|
||||
layoutStore.closeHovers();
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
@@ -208,10 +213,18 @@ export function getSubtitlesURL(file: ResourceItem) {
|
||||
return file.subtitles?.map((d) => createURL("api/subtitle" + d, params));
|
||||
}
|
||||
|
||||
export async function usage(url: string) {
|
||||
export async function usage(url: string, signal: AbortSignal) {
|
||||
url = removePrefix(url);
|
||||
|
||||
const res = await fetchURL(`/api/usage${url}`, {});
|
||||
const res = await fetchURL(`/api/usage${url}`, { signal });
|
||||
|
||||
return await res.json();
|
||||
try {
|
||||
return await res.json();
|
||||
} catch (e) {
|
||||
// Check if the error is an intentional cancellation
|
||||
if (e instanceof Error && e.name == "AbortError") {
|
||||
throw new StatusError("000 No connection", 0, true);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,5 +71,5 @@ export function getDownloadURL(res: Resource, inline = false) {
|
||||
...(res.token && { token: res.token }),
|
||||
};
|
||||
|
||||
return createURL("api/public/dl/" + res.hash + res.path, params, false);
|
||||
return createURL("api/public/dl/" + res.hash + res.path, params);
|
||||
}
|
||||
|
||||
@@ -41,5 +41,5 @@ export async function create(
|
||||
}
|
||||
|
||||
export function getShareURL(share: Share) {
|
||||
return createURL("share/" + share.hash, {}, false);
|
||||
return createURL("share/" + share.hash, {});
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function upload(
|
||||
fileData.hasStarted = true;
|
||||
fileData.lastProgressTimestamp = Date.now();
|
||||
|
||||
fileData.interval = setInterval(() => {
|
||||
fileData.interval = window.setInterval(() => {
|
||||
calcProgress(filePath);
|
||||
}, SPEED_UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function create(user: IUser) {
|
||||
throw new StatusError(await res.text(), res.status);
|
||||
}
|
||||
|
||||
export async function update(user: IUser, which = ["all"]) {
|
||||
export async function update(user: Partial<IUser>, which = ["all"]) {
|
||||
await fetchURL(`/api/users/${user.id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
|
||||
@@ -6,7 +6,8 @@ import { encodePath } from "@/utils/url";
|
||||
export class StatusError extends Error {
|
||||
constructor(
|
||||
message: any,
|
||||
public status?: number
|
||||
public status?: number,
|
||||
public is_canceled?: boolean
|
||||
) {
|
||||
super(message);
|
||||
this.name = "StatusError";
|
||||
@@ -33,7 +34,11 @@ export async function fetchURL(
|
||||
},
|
||||
...rest,
|
||||
});
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// Check if the error is an intentional cancellation
|
||||
if (e instanceof Error && e.name === "AbortError") {
|
||||
throw new StatusError("000 No connection", 0, true);
|
||||
}
|
||||
throw new StatusError("000 No connection", 0);
|
||||
}
|
||||
|
||||
@@ -76,23 +81,13 @@ export function removePrefix(url: string): string {
|
||||
return url;
|
||||
}
|
||||
|
||||
export function createURL(endpoint: string, params = {}, auth = true): string {
|
||||
const authStore = useAuthStore();
|
||||
|
||||
export function createURL(endpoint: string, searchParams = {}): string {
|
||||
let prefix = baseURL;
|
||||
if (!prefix.endsWith("/")) {
|
||||
prefix = prefix + "/";
|
||||
}
|
||||
const url = new URL(prefix + encodePath(endpoint), origin);
|
||||
|
||||
const searchParams: SearchParams = {
|
||||
...(auth && { auth: authStore.jwt }),
|
||||
...params,
|
||||
};
|
||||
|
||||
for (const key in searchParams) {
|
||||
url.searchParams.set(key, searchParams[key]);
|
||||
}
|
||||
url.search = new URLSearchParams(searchParams).toString();
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ const props = defineProps<{
|
||||
|
||||
const items = computed(() => {
|
||||
const relativePath = route.path.replace(props.base, "");
|
||||
let parts = relativePath.split("/");
|
||||
const parts = relativePath.split("/");
|
||||
|
||||
if (parts[0] === "") {
|
||||
parts.shift();
|
||||
@@ -44,7 +44,7 @@ const items = computed(() => {
|
||||
parts.pop();
|
||||
}
|
||||
|
||||
let breadcrumbs: BreadCrumb[] = [];
|
||||
const breadcrumbs: BreadCrumb[] = [];
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
if (i === 0) {
|
||||
|
||||
@@ -46,7 +46,7 @@ https://raw.githubusercontent.com/dzwillia/vue-simple-progress/master/src/compon
|
||||
|
||||
<script>
|
||||
// We're leaving this untouched as you can read in the beginning
|
||||
var isNumber = function (n) {
|
||||
const isNumber = function (n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
};
|
||||
|
||||
@@ -107,7 +107,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
pct() {
|
||||
var pct = (this.val / this.max) * 100;
|
||||
let pct = (this.val / this.max) * 100;
|
||||
pct = pct.toFixed(2);
|
||||
return Math.min(pct, this.max);
|
||||
},
|
||||
@@ -160,7 +160,7 @@ export default {
|
||||
return isNumber(this.fontSize) ? this.fontSize : 13;
|
||||
},
|
||||
progress_style() {
|
||||
var style = {
|
||||
const style = {
|
||||
background: this.bgColor,
|
||||
};
|
||||
|
||||
@@ -177,7 +177,7 @@ export default {
|
||||
return style;
|
||||
},
|
||||
bar_style() {
|
||||
var style = {
|
||||
const style = {
|
||||
background: this.barColor,
|
||||
width: this.pct + "%",
|
||||
height: this.size_px + "px",
|
||||
@@ -198,7 +198,7 @@ export default {
|
||||
return style;
|
||||
},
|
||||
text_style() {
|
||||
var style = {
|
||||
const style = {
|
||||
color: this.textFgColor,
|
||||
"font-size": this.text_font_size + "px",
|
||||
"text-align": this.textAlign,
|
||||
|
||||
@@ -50,7 +50,7 @@ import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
|
||||
import { commands } from "@/api";
|
||||
import { throttle } from "lodash";
|
||||
import { throttle } from "lodash-es";
|
||||
import { theme } from "@/utils/constants";
|
||||
|
||||
export default {
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
this.canInput = false;
|
||||
event.target.innerHTML = "";
|
||||
|
||||
let results = {
|
||||
const results = {
|
||||
text: `${cmd}\n\n`,
|
||||
};
|
||||
|
||||
@@ -180,7 +180,7 @@ export default {
|
||||
},
|
||||
() => {
|
||||
results.text = results.text
|
||||
// eslint-disable-next-line no-control-regex
|
||||
|
||||
.replace(/\u001b\[[0-9;]+m/g, "") // Filter ANSI color for now
|
||||
.trimEnd();
|
||||
this.canInput = true;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<div v-show="active" @click="closeHovers" class="overlay"></div>
|
||||
<nav :class="{ active }">
|
||||
<template v-if="isLoggedIn">
|
||||
<button
|
||||
@@ -100,7 +101,7 @@
|
||||
href="https://github.com/filebrowser/filebrowser"
|
||||
>File Browser</a
|
||||
>
|
||||
<span> {{ version }}</span>
|
||||
<span> {{ " " }} {{ version }}</span>
|
||||
</span>
|
||||
<span>
|
||||
<a @click="help">{{ $t("sidebar.help") }}</a>
|
||||
@@ -128,6 +129,7 @@ import {
|
||||
import { files as api } from "@/api";
|
||||
import ProgressBar from "@/components/ProgressBar.vue";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
import { StatusError } from "@/api/utils.js";
|
||||
|
||||
const USAGE_DEFAULT = { used: "0 B", total: "0 B", usedPercentage: 0 };
|
||||
|
||||
@@ -135,7 +137,7 @@ export default {
|
||||
name: "sidebar",
|
||||
setup() {
|
||||
const usage = reactive(USAGE_DEFAULT);
|
||||
return { usage };
|
||||
return { usage, usageAbortController: new AbortController() };
|
||||
},
|
||||
components: {
|
||||
ProgressBar,
|
||||
@@ -156,8 +158,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
|
||||
abortOngoingFetchUsage() {
|
||||
this.usageAbortController.abort();
|
||||
},
|
||||
async fetchUsage() {
|
||||
let path = this.$route.path.endsWith("/")
|
||||
const path = this.$route.path.endsWith("/")
|
||||
? this.$route.path
|
||||
: this.$route.path + "/";
|
||||
let usageStats = USAGE_DEFAULT;
|
||||
@@ -165,13 +170,18 @@ export default {
|
||||
return Object.assign(this.usage, usageStats);
|
||||
}
|
||||
try {
|
||||
let usage = await api.usage(path);
|
||||
this.abortOngoingFetchUsage();
|
||||
this.usageAbortController = new AbortController();
|
||||
const usage = await api.usage(path, this.usageAbortController.signal);
|
||||
usageStats = {
|
||||
used: prettyBytes(usage.used, { binary: true }),
|
||||
total: prettyBytes(usage.total, { binary: true }),
|
||||
usedPercentage: Math.round((usage.used / usage.total) * 100),
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof StatusError && error.is_canceled) {
|
||||
return;
|
||||
}
|
||||
this.$showError(error);
|
||||
}
|
||||
return Object.assign(this.usage, usageStats);
|
||||
@@ -190,9 +200,17 @@ export default {
|
||||
logout: auth.logout,
|
||||
},
|
||||
watch: {
|
||||
isFiles(newValue) {
|
||||
newValue && this.fetchUsage();
|
||||
$route: {
|
||||
handler(to) {
|
||||
if (to.path.includes("/files")) {
|
||||
this.fetchUsage();
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
unmounted() {
|
||||
this.abortOngoingFetchUsage();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import throttle from "lodash/throttle";
|
||||
import { throttle } from "lodash-es";
|
||||
import UTIF from "utif";
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
|
||||
interface IProps {
|
||||
src: string;
|
||||
moveDisabledTime: number;
|
||||
classList: any[];
|
||||
zoomStep: number;
|
||||
moveDisabledTime?: number;
|
||||
classList?: any[];
|
||||
zoomStep?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
@@ -102,10 +102,11 @@ const decodeUTIF = () => {
|
||||
if (document?.location?.pathname === undefined) {
|
||||
return;
|
||||
}
|
||||
let suff = document.location.pathname.split(".")?.pop()?.toLowerCase() ?? "";
|
||||
const suff =
|
||||
document.location.pathname.split(".")?.pop()?.toLowerCase() ?? "";
|
||||
|
||||
if (sufs.indexOf(suff) == -1) return false;
|
||||
let xhr = new XMLHttpRequest();
|
||||
const xhr = new XMLHttpRequest();
|
||||
UTIF._xhrs.push(xhr);
|
||||
UTIF._imgs.push(imgex.value);
|
||||
xhr.open("GET", props.src);
|
||||
@@ -230,7 +231,7 @@ const touchMove = (event: TouchEvent) => {
|
||||
if (imgex.value === null) {
|
||||
return;
|
||||
}
|
||||
let step = imgex.value.width / 5;
|
||||
const step = imgex.value.width / 5;
|
||||
if (event.targetTouches.length === 2) {
|
||||
moveDisabled.value = true;
|
||||
if (disabledTimer.value) clearTimeout(disabledTimer.value);
|
||||
@@ -239,9 +240,9 @@ const touchMove = (event: TouchEvent) => {
|
||||
props.moveDisabledTime
|
||||
);
|
||||
|
||||
let p1 = event.targetTouches[0];
|
||||
let p2 = event.targetTouches[1];
|
||||
let touchDistance = Math.sqrt(
|
||||
const p1 = event.targetTouches[0];
|
||||
const p2 = event.targetTouches[1];
|
||||
const touchDistance = Math.sqrt(
|
||||
Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
|
||||
);
|
||||
if (!lastTouchDistance.value) {
|
||||
@@ -253,8 +254,8 @@ const touchMove = (event: TouchEvent) => {
|
||||
setZoom();
|
||||
} else if (event.targetTouches.length === 1) {
|
||||
if (moveDisabled.value) return;
|
||||
let x = event.targetTouches[0].pageX - (lastX.value ?? 0);
|
||||
let y = event.targetTouches[0].pageY - (lastY.value ?? 0);
|
||||
const x = event.targetTouches[0].pageX - (lastX.value ?? 0);
|
||||
const y = event.targetTouches[0].pageY - (lastY.value ?? 0);
|
||||
if (Math.abs(x) >= step && Math.abs(y) >= step) return;
|
||||
lastX.value = event.targetTouches[0].pageX;
|
||||
lastY.value = event.targetTouches[0].pageY;
|
||||
@@ -268,8 +269,8 @@ const doMove = (x: number, y: number) => {
|
||||
}
|
||||
const style = imgex.value.style;
|
||||
|
||||
let posX = pxStringToNumber(style.left) + x;
|
||||
let posY = pxStringToNumber(style.top) + y;
|
||||
const posX = pxStringToNumber(style.left) + x;
|
||||
const posY = pxStringToNumber(style.top) + y;
|
||||
|
||||
style.left = posX + "px";
|
||||
style.top = posY + "px";
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
:data-type="type"
|
||||
:aria-label="name"
|
||||
:aria-selected="isSelected"
|
||||
:data-ext="getExtension(name).toLowerCase()"
|
||||
>
|
||||
<div>
|
||||
<img
|
||||
@@ -81,7 +82,7 @@ const isDraggable = computed(
|
||||
const canDrop = computed(() => {
|
||||
if (!props.isDir || props.readOnly) return false;
|
||||
|
||||
for (let i of fileStore.selected) {
|
||||
for (const i of fileStore.selected) {
|
||||
if (fileStore.req?.items[i].url === props.url) {
|
||||
return false;
|
||||
}
|
||||
@@ -155,9 +156,9 @@ const drop = async (event: Event) => {
|
||||
}
|
||||
}
|
||||
|
||||
let items: any[] = [];
|
||||
const items: any[] = [];
|
||||
|
||||
for (let i of fileStore.selected) {
|
||||
for (const i of fileStore.selected) {
|
||||
if (fileStore.req) {
|
||||
items.push({
|
||||
from: fileStore.req?.items[i].url,
|
||||
@@ -171,10 +172,10 @@ const drop = async (event: Event) => {
|
||||
if (el === null) {
|
||||
return;
|
||||
}
|
||||
let path = el.__vue__.url;
|
||||
let baseItems = (await api.fetch(path)).items;
|
||||
const path = el.__vue__.url;
|
||||
const baseItems = (await api.fetch(path)).items;
|
||||
|
||||
let action = (overwrite: boolean, rename: boolean) => {
|
||||
const action = (overwrite: boolean, rename: boolean) => {
|
||||
api
|
||||
.move(items, overwrite, rename)
|
||||
.then(() => {
|
||||
@@ -183,7 +184,7 @@ const drop = async (event: Event) => {
|
||||
.catch($showError);
|
||||
};
|
||||
|
||||
let conflict = upload.checkConflict(items, baseItems);
|
||||
const conflict = upload.checkConflict(items, baseItems);
|
||||
|
||||
let overwrite = false;
|
||||
let rename = false;
|
||||
@@ -209,8 +210,10 @@ const drop = async (event: Event) => {
|
||||
|
||||
const itemClick = (event: Event | KeyboardEvent) => {
|
||||
if (
|
||||
!((event as KeyboardEvent).ctrlKey || (event as KeyboardEvent).metaKey) &&
|
||||
singleClick.value &&
|
||||
!(event as KeyboardEvent).ctrlKey &&
|
||||
!(event as KeyboardEvent).metaKey &&
|
||||
!(event as KeyboardEvent).shiftKey &&
|
||||
!fileStore.multiple
|
||||
)
|
||||
open();
|
||||
@@ -270,4 +273,12 @@ const click = (event: Event | KeyboardEvent) => {
|
||||
const open = () => {
|
||||
router.push({ path: props.url });
|
||||
};
|
||||
|
||||
const getExtension = (fileName: string): string => {
|
||||
const lastDotIndex = fileName.lastIndexOf(".");
|
||||
if (lastDotIndex === -1) {
|
||||
return fileName;
|
||||
}
|
||||
return fileName.substring(lastDotIndex);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<video ref="videoPlayer" class="video-max video-js" controls>
|
||||
<source :src="source" />
|
||||
<video ref="videoPlayer" class="video-max video-js" controls preload="auto">
|
||||
<source />
|
||||
<track
|
||||
kind="subtitles"
|
||||
v-for="(sub, index) in subtitles"
|
||||
@@ -18,12 +18,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick } from "vue";
|
||||
import videojs from "video.js";
|
||||
import type Player from "video.js/dist/types/player";
|
||||
import "videojs-mobile-ui";
|
||||
import "videojs-hotkeys";
|
||||
|
||||
import "video.js/dist/video-js.min.css";
|
||||
import "videojs-mobile-ui/dist/videojs-mobile-ui.css";
|
||||
|
||||
@@ -41,34 +40,15 @@ const props = withDefaults(
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
player.value = videojs(
|
||||
videoPlayer.value!,
|
||||
{
|
||||
html5: {
|
||||
// needed for customizable subtitles
|
||||
// TODO: add to user settings
|
||||
nativeTextTracks: false,
|
||||
},
|
||||
plugins: {
|
||||
hotkeys: {
|
||||
volumeStep: 0.1,
|
||||
seekStep: 10,
|
||||
enableModifiersForNumbers: false,
|
||||
},
|
||||
},
|
||||
...props.options,
|
||||
},
|
||||
// onReady callback
|
||||
async () => {
|
||||
// player.value!.log("onPlayerReady", this);
|
||||
}
|
||||
);
|
||||
// TODO: need to test on mobile
|
||||
// @ts-ignore
|
||||
player.value!.mobileUi();
|
||||
const source = ref(props.source);
|
||||
const sourceType = ref("");
|
||||
|
||||
nextTick(() => {
|
||||
initVideoPlayer();
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (player.value) {
|
||||
player.value.dispose();
|
||||
@@ -76,11 +56,77 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
});
|
||||
|
||||
const initVideoPlayer = async () => {
|
||||
try {
|
||||
const lang = document.documentElement.lang;
|
||||
const languagePack = await (
|
||||
languageImports[lang] || languageImports.en
|
||||
)?.();
|
||||
const code = languageImports[lang] ? lang : "en";
|
||||
videojs.addLanguage(code, languagePack.default);
|
||||
sourceType.value = "";
|
||||
|
||||
//
|
||||
sourceType.value = getSourceType(source.value);
|
||||
|
||||
const srcOpt = { sources: { src: props.source, type: sourceType.value } };
|
||||
//Supporting localized language display.
|
||||
const langOpt = { language: code };
|
||||
// support for playback at different speeds.
|
||||
const playbackRatesOpt = { playbackRates: [0.5, 1, 1.5, 2, 2.5, 3] };
|
||||
const options = getOptions(
|
||||
props.options,
|
||||
langOpt,
|
||||
srcOpt,
|
||||
playbackRatesOpt
|
||||
);
|
||||
player.value = videojs(videoPlayer.value!, options, () => {});
|
||||
|
||||
// TODO: need to test on mobile
|
||||
// @ts-expect-error no ts definition for mobileUi
|
||||
player.value!.mobileUi();
|
||||
} catch (error) {
|
||||
console.error("Error initializing video player:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const getOptions = (...srcOpt: any[]) => {
|
||||
const options = {
|
||||
controlBar: {
|
||||
skipButtons: {
|
||||
forward: 5,
|
||||
backward: 5,
|
||||
},
|
||||
},
|
||||
html5: {
|
||||
nativeTextTracks: false,
|
||||
},
|
||||
plugins: {
|
||||
hotkeys: {
|
||||
volumeStep: 0.1,
|
||||
seekStep: 10,
|
||||
enableModifiersForNumbers: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return videojs.obj.merge(options, ...srcOpt);
|
||||
};
|
||||
|
||||
// Attempting to fix the issue of being unable to play .MKV format video files
|
||||
const getSourceType = (source: string) => {
|
||||
const fileExtension = source ? source.split("?")[0].split(".").pop() : "";
|
||||
if (fileExtension?.toLowerCase() === "mkv") {
|
||||
return "video/mp4";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const subLabel = (subUrl: string) => {
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(subUrl);
|
||||
} catch (_) {
|
||||
} catch {
|
||||
// treat it as a relative url
|
||||
// we only need this for filename
|
||||
url = new URL(subUrl, window.location.origin);
|
||||
@@ -95,6 +141,35 @@ const subLabel = (subUrl: string) => {
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
interface LanguageImports {
|
||||
[key: string]: () => Promise<any>;
|
||||
}
|
||||
|
||||
const languageImports: LanguageImports = {
|
||||
he: () => import("video.js/dist/lang/he.json"),
|
||||
hu: () => import("video.js/dist/lang/hu.json"),
|
||||
ar: () => import("video.js/dist/lang/ar.json"),
|
||||
de: () => import("video.js/dist/lang/de.json"),
|
||||
el: () => import("video.js/dist/lang/el.json"),
|
||||
en: () => import("video.js/dist/lang/en.json"),
|
||||
es: () => import("video.js/dist/lang/es.json"),
|
||||
fr: () => import("video.js/dist/lang/fr.json"),
|
||||
it: () => import("video.js/dist/lang/it.json"),
|
||||
ja: () => import("video.js/dist/lang/ja.json"),
|
||||
ko: () => import("video.js/dist/lang/ko.json"),
|
||||
"nl-be": () => import("video.js/dist/lang/nl.json"),
|
||||
pl: () => import("video.js/dist/lang/pl.json"),
|
||||
"pt-br": () => import("video.js/dist/lang/pt-BR.json"),
|
||||
pt: () => import("video.js/dist/lang/pt-PT.json"),
|
||||
ro: () => import("video.js/dist/lang/ro.json"),
|
||||
ru: () => import("video.js/dist/lang/ru.json"),
|
||||
sk: () => import("video.js/dist/lang/sk.json"),
|
||||
tr: () => import("video.js/dist/lang/tr.json"),
|
||||
uk: () => import("video.js/dist/lang/uk.json"),
|
||||
"zh-cn": () => import("video.js/dist/lang/zh-CN.json"),
|
||||
"zh-tw": () => import("video.js/dist/lang/zh-TW.json"),
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.video-max {
|
||||
|
||||
@@ -82,10 +82,10 @@ export default {
|
||||
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
||||
copy: async function (event) {
|
||||
event.preventDefault();
|
||||
let items = [];
|
||||
const items = [];
|
||||
|
||||
// Create a new promise for each file.
|
||||
for (let item of this.selected) {
|
||||
for (const item of this.selected) {
|
||||
items.push({
|
||||
from: this.req.items[item].url,
|
||||
to: this.dest + encodeURIComponent(this.req.items[item].name),
|
||||
@@ -93,7 +93,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
let action = async (overwrite, rename) => {
|
||||
const action = async (overwrite, rename) => {
|
||||
buttons.loading("copy");
|
||||
|
||||
await api
|
||||
@@ -122,8 +122,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
let dstItems = (await api.fetch(this.dest)).items;
|
||||
let conflict = upload.checkConflict(items, dstItems);
|
||||
const dstItems = (await api.fetch(this.dest)).items;
|
||||
const conflict = upload.checkConflict(items, dstItems);
|
||||
|
||||
let overwrite = false;
|
||||
let rename = false;
|
||||
|
||||
@@ -74,8 +74,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
for (let index of this.selected) {
|
||||
const promises = [];
|
||||
for (const index of this.selected) {
|
||||
promises.push(api.remove(this.req.items[index].url));
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
submit: async function () {
|
||||
this.updateRequest(null);
|
||||
|
||||
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||
const uri = url.removeLastDir(this.$route.path) + "/";
|
||||
this.$router.push({ path: uri });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -31,6 +31,7 @@ import { useFileStore } from "@/stores/file";
|
||||
|
||||
import url from "@/utils/url";
|
||||
import { files } from "@/api";
|
||||
import { StatusError } from "@/api/utils.js";
|
||||
|
||||
export default {
|
||||
name: "file-list",
|
||||
@@ -43,6 +44,7 @@ export default {
|
||||
},
|
||||
selected: null,
|
||||
current: window.location.pathname,
|
||||
nextAbortController: new AbortController(),
|
||||
};
|
||||
},
|
||||
inject: ["$showError"],
|
||||
@@ -56,7 +58,13 @@ export default {
|
||||
mounted() {
|
||||
this.fillOptions(this.req);
|
||||
},
|
||||
unmounted() {
|
||||
this.abortOngoingNext();
|
||||
},
|
||||
methods: {
|
||||
abortOngoingNext() {
|
||||
this.nextAbortController.abort();
|
||||
},
|
||||
fillOptions(req) {
|
||||
// Sets the current path and resets
|
||||
// the current items.
|
||||
@@ -80,7 +88,7 @@ export default {
|
||||
|
||||
// Otherwise we add every directory to the
|
||||
// move options.
|
||||
for (let item of req.items) {
|
||||
for (const item of req.items) {
|
||||
if (!item.isDir) continue;
|
||||
|
||||
this.items.push({
|
||||
@@ -93,12 +101,21 @@ export default {
|
||||
// Retrieves the URL of the directory the user
|
||||
// just clicked in and fill the options with its
|
||||
// content.
|
||||
let uri = event.currentTarget.dataset.url;
|
||||
|
||||
files.fetch(uri).then(this.fillOptions).catch(this.$showError);
|
||||
const uri = event.currentTarget.dataset.url;
|
||||
this.abortOngoingNext();
|
||||
this.nextAbortController = new AbortController();
|
||||
files
|
||||
.fetch(uri, this.nextAbortController.signal)
|
||||
.then(this.fillOptions)
|
||||
.catch((e) => {
|
||||
if (e instanceof StatusError && e.is_canceled) {
|
||||
return;
|
||||
}
|
||||
this.$showError(e);
|
||||
});
|
||||
},
|
||||
touchstart(event) {
|
||||
let url = event.currentTarget.dataset.url;
|
||||
const url = event.currentTarget.dataset.url;
|
||||
|
||||
// In 300 milliseconds, we shall reset the count.
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<li><strong>DEL</strong> - {{ $t("help.del") }}</li>
|
||||
<li><strong>ESC</strong> - {{ $t("help.esc") }}</li>
|
||||
<li><strong>CTRL + S</strong> - {{ $t("help.ctrl.s") }}</li>
|
||||
<li><strong>CTRL + F</strong> - {{ $t("help.ctrl.f") }}</li>
|
||||
<li><strong>CTRL + SHIFT + F</strong> - {{ $t("help.ctrl.f") }}</li>
|
||||
<li><strong>CTRL + Click</strong> - {{ $t("help.ctrl.click") }}</li>
|
||||
<li><strong>Click</strong> - {{ $t("help.click") }}</li>
|
||||
<li><strong>Double click</strong> - {{ $t("help.doubleClick") }}</li>
|
||||
|
||||
@@ -124,7 +124,7 @@ export default {
|
||||
|
||||
let sum = 0;
|
||||
|
||||
for (let selected of this.selected) {
|
||||
for (const selected of this.selected) {
|
||||
sum += this.req.items[selected].size;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,9 +81,9 @@ export default {
|
||||
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
||||
move: async function (event) {
|
||||
event.preventDefault();
|
||||
let items = [];
|
||||
const items = [];
|
||||
|
||||
for (let item of this.selected) {
|
||||
for (const item of this.selected) {
|
||||
items.push({
|
||||
from: this.req.items[item].url,
|
||||
to: this.dest + encodeURIComponent(this.req.items[item].name),
|
||||
@@ -91,7 +91,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
let action = async (overwrite, rename) => {
|
||||
const action = async (overwrite, rename) => {
|
||||
buttons.loading("move");
|
||||
|
||||
await api
|
||||
@@ -106,8 +106,8 @@ export default {
|
||||
});
|
||||
};
|
||||
|
||||
let dstItems = (await api.fetch(this.dest)).items;
|
||||
let conflict = upload.checkConflict(items, dstItems);
|
||||
const dstItems = (await api.fetch(this.dest)).items;
|
||||
const conflict = upload.checkConflict(items, dstItems);
|
||||
|
||||
let overwrite = false;
|
||||
let rename = false;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import { watch } from "vue";
|
||||
import { ModalsContainer, useModal } from "vue-final-modal";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
@@ -30,8 +30,6 @@ const layoutStore = useLayoutStore();
|
||||
|
||||
const { currentPromptName } = storeToRefs(layoutStore);
|
||||
|
||||
const closeModal = ref<() => Promise<string>>();
|
||||
|
||||
const components = new Map<string, any>([
|
||||
["info", Info],
|
||||
["help", Help],
|
||||
@@ -52,11 +50,6 @@ const components = new Map<string, any>([
|
||||
]);
|
||||
|
||||
watch(currentPromptName, (newValue) => {
|
||||
if (closeModal.value) {
|
||||
closeModal.value();
|
||||
closeModal.value = undefined;
|
||||
}
|
||||
|
||||
const modal = components.get(newValue!);
|
||||
if (!modal) return;
|
||||
|
||||
@@ -67,7 +60,7 @@ watch(currentPromptName, (newValue) => {
|
||||
},
|
||||
});
|
||||
|
||||
closeModal.value = close;
|
||||
layoutStore.setCloseOnPrompt(close, newValue!);
|
||||
open();
|
||||
});
|
||||
|
||||
|
||||
@@ -196,13 +196,23 @@ export default {
|
||||
methods: {
|
||||
...mapActions(useLayoutStore, ["closeHovers"]),
|
||||
copyToClipboard: function (text) {
|
||||
copy(text).then(
|
||||
copy({ text }).then(
|
||||
() => {
|
||||
// clipboard successfully set
|
||||
this.$showSuccess(this.$t("success.linkCopied"));
|
||||
},
|
||||
() => {
|
||||
// clipboard write failed
|
||||
copy({ text }, { permission: true }).then(
|
||||
() => {
|
||||
// clipboard successfully set
|
||||
this.$showSuccess(this.$t("success.linkCopied"));
|
||||
},
|
||||
(e) => {
|
||||
// clipboard write failed
|
||||
this.$showError(e);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@@ -48,12 +48,10 @@ const layoutStore = useLayoutStore();
|
||||
|
||||
// TODO: this is a copy of the same function in FileListing.vue
|
||||
const uploadInput = (event: Event) => {
|
||||
layoutStore.closeHovers();
|
||||
|
||||
let files = (event.currentTarget as HTMLInputElement)?.files;
|
||||
const files = (event.currentTarget as HTMLInputElement)?.files;
|
||||
if (files === null) return;
|
||||
|
||||
let folder_upload = !!files[0].webkitRelativePath;
|
||||
const folder_upload = !!files[0].webkitRelativePath;
|
||||
|
||||
const uploadFiles: UploadList = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
@@ -68,8 +66,8 @@ const uploadInput = (event: Event) => {
|
||||
});
|
||||
}
|
||||
|
||||
let path = route.path.endsWith("/") ? route.path : route.path + "/";
|
||||
let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
|
||||
const path = route.path.endsWith("/") ? route.path : route.path + "/";
|
||||
const conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
|
||||
|
||||
if (conflict) {
|
||||
layoutStore.showHover({
|
||||
|
||||
@@ -117,3 +117,11 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.upload-info {
|
||||
min-width: 19ch;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,11 +13,13 @@ export default {
|
||||
name: "languages",
|
||||
props: ["locale"],
|
||||
data() {
|
||||
let dataObj = {};
|
||||
const dataObj = {};
|
||||
const locales = {
|
||||
he: "עברית",
|
||||
hu: "Magyar",
|
||||
ar: "العربية",
|
||||
ca: "Català",
|
||||
cs: "Čeština",
|
||||
de: "Deutsch",
|
||||
el: "Ελληνικά",
|
||||
en: "English",
|
||||
@@ -37,6 +39,7 @@ export default {
|
||||
"sv-se": "Swedish (Sweden)",
|
||||
tr: "Türkçe",
|
||||
uk: "Українська",
|
||||
vi: "Tiếng Việt",
|
||||
"zh-cn": "中文 (简体)",
|
||||
"zh-tw": "中文 (繁體)",
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
methods: {
|
||||
remove(event, index) {
|
||||
event.preventDefault();
|
||||
let rules = [...this.rules];
|
||||
const rules = [...this.rules];
|
||||
rules.splice(index, 1);
|
||||
this.$emit("update:rules", [...rules]);
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SelectHTMLAttributes } from "vue";
|
||||
import type { SelectHTMLAttributes } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
@@ -17,7 +17,6 @@ defineProps<{
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
(e: "update:theme", val: string | null): void;
|
||||
}>();
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ watch(createUserDirData, () => {
|
||||
if (props.user?.scope) {
|
||||
props.user.scope = createUserDirData.value
|
||||
? ""
|
||||
: originalUserScope.value ?? "";
|
||||
: (originalUserScope.value ?? "");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -6,15 +6,22 @@
|
||||
background: var(--surfacePrimary);
|
||||
color: var(--textPrimary);
|
||||
z-index: 9999;
|
||||
background: rgba(127, 127, 127, 0.1);
|
||||
background: var(--dividerSecondary);
|
||||
transition: 0.2s ease background;
|
||||
cursor: ns-resize;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.shell__divider {
|
||||
background: rgba(127, 127, 127, 0.3);
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.shell__divider:hover {
|
||||
background: rgba(127, 127, 127, 0.4);
|
||||
background: rgba(127, 127, 127, 0.9);
|
||||
}
|
||||
|
||||
.shell__content {
|
||||
@@ -34,7 +41,7 @@
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 9998;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
background-color: var(--dividerPrimary);
|
||||
}
|
||||
|
||||
body.rtl .shell-content {
|
||||
@@ -75,4 +82,5 @@ body.rtl .shell-content {
|
||||
font-family: inherit;
|
||||
white-space: pre-wrap;
|
||||
width: 100%;
|
||||
color: var(--textSecondary);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
--hover: rgba(0, 0, 0, 0.1);
|
||||
--borderPrimary: rgba(0, 0, 0, 0.1);
|
||||
--borderSecondary: rgba(0, 0, 0, 0.2);
|
||||
--dividerPrimary: rgba(255, 255, 255, 0.4);
|
||||
--dividerSecondary: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
@@ -51,4 +53,6 @@
|
||||
--hover: rgba(255, 255, 255, 0.1);
|
||||
--borderPrimary: rgba(255, 255, 255, 0.05);
|
||||
--borderSecondary: rgba(255, 255, 255, 0.15);
|
||||
--dividerPrimary: rgba(30, 30, 30, 0.4);
|
||||
--dividerSecondary: rgba(30, 30, 30, 0.6);
|
||||
}
|
||||
|
||||
78
frontend/src/css/epubReader.css
Normal file
78
frontend/src/css/epubReader.css
Normal file
@@ -0,0 +1,78 @@
|
||||
.epub-reader {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.epub-reader .container {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: calc(100% - 64px);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.epub-reader .arrow.pre {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.epub-reader .readerArea {
|
||||
background-color: var(--background) !important;
|
||||
}
|
||||
|
||||
.epub-reader .titleArea {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.epub-reader .tocButtonBar {
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.epub-reader .tocButton {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.epub-reader .tocButton.tocButtonExpanded {
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
.epub-reader .tocAreaButton.active {
|
||||
color: var(--blue);
|
||||
border-color: var(--dark-blue);
|
||||
}
|
||||
|
||||
.epub-reader .tocArea {
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
.epub-reader .readerArea .arrow {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.epub-reader .readerArea .arrow:hover {
|
||||
color: var(--hover);
|
||||
}
|
||||
|
||||
.epub-reader .size {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
z-index: 111;
|
||||
right: 25px;
|
||||
outline: none;
|
||||
position: absolute;
|
||||
top: 78px;
|
||||
}
|
||||
|
||||
.epub-reader .size span {
|
||||
color: var(--textSecondary);
|
||||
}
|
||||
|
||||
.epub-reader .size button {
|
||||
background: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
color: var(--textPrimary);
|
||||
padding: 0;
|
||||
}
|
||||
@@ -63,8 +63,8 @@
|
||||
local("Roboto"),
|
||||
local("Roboto-Regular"),
|
||||
url(../assets/fonts/roboto/normal-latin-ext.woff2) format("woff2");
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
|
||||
U+A720-A7FF;
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
|
||||
U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -142,8 +142,8 @@
|
||||
local("Roboto Medium"),
|
||||
local("Roboto-Medium"),
|
||||
url(../assets/fonts/roboto/medium-latin-ext.woff2) format("woff2");
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
|
||||
U+A720-A7FF;
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
|
||||
U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -221,8 +221,8 @@
|
||||
local("Roboto Bold"),
|
||||
local("Roboto-Bold"),
|
||||
url(../assets/fonts/roboto/bold-latin-ext.woff2) format("woff2");
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
|
||||
U+A720-A7FF;
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
|
||||
U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.file-icons [aria-label^="."] {
|
||||
opacity: 0.33;
|
||||
}
|
||||
.file-icons [aria-label$=".bak"] {
|
||||
.file-icons [data-ext=".bak"] {
|
||||
opacity: 0.33;
|
||||
}
|
||||
|
||||
@@ -33,117 +33,117 @@
|
||||
|
||||
/* #f90 - Image */
|
||||
|
||||
.file-icons [aria-label$=".ai"] i::before,
|
||||
.file-icons [aria-label$=".odg"] i::before,
|
||||
.file-icons [aria-label$=".xcf"] i::before {
|
||||
.file-icons [data-ext=".ai"] i::before,
|
||||
.file-icons [data-ext=".odg"] i::before,
|
||||
.file-icons [data-ext=".xcf"] i::before {
|
||||
content: "image";
|
||||
}
|
||||
|
||||
/* #f90 - Presentation */
|
||||
|
||||
.file-icons [aria-label$=".odp"] i::before,
|
||||
.file-icons [aria-label$=".ppt"] i::before,
|
||||
.file-icons [aria-label$=".pptx"] i::before {
|
||||
.file-icons [data-ext=".odp"] i::before,
|
||||
.file-icons [data-ext=".ppt"] i::before,
|
||||
.file-icons [data-ext=".pptx"] i::before {
|
||||
content: "slideshow";
|
||||
}
|
||||
|
||||
/* #0f0 - Spreadsheet/Database */
|
||||
|
||||
.file-icons [aria-label$=".csv"] i::before,
|
||||
.file-icons [aria-label$=".db"] i::before,
|
||||
.file-icons [aria-label$=".odb"] i::before,
|
||||
.file-icons [aria-label$=".ods"] i::before,
|
||||
.file-icons [aria-label$=".xls"] i::before,
|
||||
.file-icons [aria-label$=".xlsx"] i::before {
|
||||
.file-icons [data-ext=".csv"] i::before,
|
||||
.file-icons [data-ext=".db"] i::before,
|
||||
.file-icons [data-ext=".odb"] i::before,
|
||||
.file-icons [data-ext=".ods"] i::before,
|
||||
.file-icons [data-ext=".xls"] i::before,
|
||||
.file-icons [data-ext=".xlsx"] i::before {
|
||||
content: "border_all";
|
||||
}
|
||||
|
||||
/* #00f - Document */
|
||||
|
||||
.file-icons [aria-label$=".doc"] i::before,
|
||||
.file-icons [aria-label$=".docx"] i::before,
|
||||
.file-icons [aria-label$=".log"] i::before,
|
||||
.file-icons [aria-label$=".odt"] i::before,
|
||||
.file-icons [aria-label$=".rtf"] i::before {
|
||||
.file-icons [data-ext=".doc"] i::before,
|
||||
.file-icons [data-ext=".docx"] i::before,
|
||||
.file-icons [data-ext=".log"] i::before,
|
||||
.file-icons [data-ext=".odt"] i::before,
|
||||
.file-icons [data-ext=".rtf"] i::before {
|
||||
content: "description";
|
||||
}
|
||||
|
||||
/* #999 - Code */
|
||||
|
||||
.file-icons [aria-label$=".c"] i::before,
|
||||
.file-icons [aria-label$=".cpp"] i::before,
|
||||
.file-icons [aria-label$=".cs"] i::before,
|
||||
.file-icons [aria-label$=".css"] i::before,
|
||||
.file-icons [aria-label$=".go"] i::before,
|
||||
.file-icons [aria-label$=".h"] i::before,
|
||||
.file-icons [aria-label$=".html"] i::before,
|
||||
.file-icons [aria-label$=".java"] i::before,
|
||||
.file-icons [aria-label$=".js"] i::before,
|
||||
.file-icons [aria-label$=".json"] i::before,
|
||||
.file-icons [aria-label$=".kt"] i::before,
|
||||
.file-icons [aria-label$=".php"] i::before,
|
||||
.file-icons [aria-label$=".py"] i::before,
|
||||
.file-icons [aria-label$=".rb"] i::before,
|
||||
.file-icons [aria-label$=".rs"] i::before,
|
||||
.file-icons [aria-label$=".vue"] i::before,
|
||||
.file-icons [aria-label$=".xml"] i::before,
|
||||
.file-icons [aria-label$=".yml"] i::before {
|
||||
.file-icons [data-ext=".c"] i::before,
|
||||
.file-icons [data-ext=".cpp"] i::before,
|
||||
.file-icons [data-ext=".cs"] i::before,
|
||||
.file-icons [data-ext=".css"] i::before,
|
||||
.file-icons [data-ext=".go"] i::before,
|
||||
.file-icons [data-ext=".h"] i::before,
|
||||
.file-icons [data-ext=".html"] i::before,
|
||||
.file-icons [data-ext=".java"] i::before,
|
||||
.file-icons [data-ext=".js"] i::before,
|
||||
.file-icons [data-ext=".json"] i::before,
|
||||
.file-icons [data-ext=".kt"] i::before,
|
||||
.file-icons [data-ext=".php"] i::before,
|
||||
.file-icons [data-ext=".py"] i::before,
|
||||
.file-icons [data-ext=".rb"] i::before,
|
||||
.file-icons [data-ext=".rs"] i::before,
|
||||
.file-icons [data-ext=".vue"] i::before,
|
||||
.file-icons [data-ext=".xml"] i::before,
|
||||
.file-icons [data-ext=".yml"] i::before {
|
||||
content: "code";
|
||||
}
|
||||
|
||||
/* #999 - Executable */
|
||||
|
||||
.file-icons [aria-label$=".apk"] i::before,
|
||||
.file-icons [aria-label$=".bat"] i::before,
|
||||
.file-icons [aria-label$=".exe"] i::before,
|
||||
.file-icons [aria-label$=".jar"] i::before,
|
||||
.file-icons [aria-label$=".ps1"] i::before,
|
||||
.file-icons [aria-label$=".sh"] i::before {
|
||||
.file-icons [data-ext=".apk"] i::before,
|
||||
.file-icons [data-ext=".bat"] i::before,
|
||||
.file-icons [data-ext=".exe"] i::before,
|
||||
.file-icons [data-ext=".jar"] i::before,
|
||||
.file-icons [data-ext=".ps1"] i::before,
|
||||
.file-icons [data-ext=".sh"] i::before {
|
||||
content: "web_asset";
|
||||
}
|
||||
|
||||
/* #999 - Installer */
|
||||
|
||||
.file-icons [aria-label$=".deb"] i::before,
|
||||
.file-icons [aria-label$=".msi"] i::before,
|
||||
.file-icons [aria-label$=".pkg"] i::before,
|
||||
.file-icons [aria-label$=".rpm"] i::before {
|
||||
.file-icons [data-ext=".deb"] i::before,
|
||||
.file-icons [data-ext=".msi"] i::before,
|
||||
.file-icons [data-ext=".pkg"] i::before,
|
||||
.file-icons [data-ext=".rpm"] i::before {
|
||||
content: "archive";
|
||||
}
|
||||
|
||||
/* #999 - Compressed */
|
||||
|
||||
.file-icons [aria-label$=".7z"] i::before,
|
||||
.file-icons [aria-label$=".bz2"] i::before,
|
||||
.file-icons [aria-label$=".cab"] i::before,
|
||||
.file-icons [aria-label$=".gz"] i::before,
|
||||
.file-icons [aria-label$=".rar"] i::before,
|
||||
.file-icons [aria-label$=".tar"] i::before,
|
||||
.file-icons [aria-label$=".xz"] i::before,
|
||||
.file-icons [aria-label$=".zip"] i::before,
|
||||
.file-icons [aria-label$=".zst"] i::before {
|
||||
.file-icons [data-ext=".7z"] i::before,
|
||||
.file-icons [data-ext=".bz2"] i::before,
|
||||
.file-icons [data-ext=".cab"] i::before,
|
||||
.file-icons [data-ext=".gz"] i::before,
|
||||
.file-icons [data-ext=".rar"] i::before,
|
||||
.file-icons [data-ext=".tar"] i::before,
|
||||
.file-icons [data-ext=".xz"] i::before,
|
||||
.file-icons [data-ext=".zip"] i::before,
|
||||
.file-icons [data-ext=".zst"] i::before {
|
||||
content: "folder_zip";
|
||||
}
|
||||
|
||||
/* #999 - Disk */
|
||||
|
||||
.file-icons [aria-label$=".ccd"] i::before,
|
||||
.file-icons [aria-label$=".dmg"] i::before,
|
||||
.file-icons [aria-label$=".iso"] i::before,
|
||||
.file-icons [aria-label$=".mdf"] i::before,
|
||||
.file-icons [aria-label$=".vdi"] i::before,
|
||||
.file-icons [aria-label$=".vhd"] i::before,
|
||||
.file-icons [aria-label$=".vmdk"] i::before,
|
||||
.file-icons [aria-label$=".wim"] i::before {
|
||||
.file-icons [data-ext=".ccd"] i::before,
|
||||
.file-icons [data-ext=".dmg"] i::before,
|
||||
.file-icons [data-ext=".iso"] i::before,
|
||||
.file-icons [data-ext=".mdf"] i::before,
|
||||
.file-icons [data-ext=".vdi"] i::before,
|
||||
.file-icons [data-ext=".vhd"] i::before,
|
||||
.file-icons [data-ext=".vmdk"] i::before,
|
||||
.file-icons [data-ext=".wim"] i::before {
|
||||
content: "album";
|
||||
}
|
||||
|
||||
/* #999 - Font */
|
||||
|
||||
.file-icons [aria-label$=".otf"] i::before,
|
||||
.file-icons [aria-label$=".ttf"] i::before,
|
||||
.file-icons [aria-label$=".woff"] i::before,
|
||||
.file-icons [aria-label$=".woff2"] i::before {
|
||||
.file-icons [data-ext=".otf"] i::before,
|
||||
.file-icons [data-ext=".ttf"] i::before,
|
||||
.file-icons [data-ext=".woff"] i::before,
|
||||
.file-icons [data-ext=".woff2"] i::before {
|
||||
content: "font_download";
|
||||
}
|
||||
|
||||
@@ -166,77 +166,77 @@
|
||||
|
||||
/* #f00 - Adobe/Oracle */
|
||||
|
||||
.file-icons [aria-label$=".ai"] i,
|
||||
.file-icons [aria-label$=".java"] i,
|
||||
.file-icons [aria-label$=".jar"] i,
|
||||
.file-icons [aria-label$=".psd"] i,
|
||||
.file-icons [aria-label$=".rb"] i,
|
||||
.file-icons [data-type="pdf"] i {
|
||||
.file-icons [data-ext=".ai"] i,
|
||||
.file-icons [data-ext=".java"] i,
|
||||
.file-icons [data-ext=".jar"] i,
|
||||
.file-icons [data-ext=".psd"] i,
|
||||
.file-icons [data-ext=".rb"] i,
|
||||
.file-icons [data-ext=".pdf"] i {
|
||||
color: var(--icon-red);
|
||||
}
|
||||
|
||||
/* #f90 - Image/Presentation */
|
||||
|
||||
.file-icons [aria-label$=".html"] i,
|
||||
.file-icons [aria-label$=".odg"] i,
|
||||
.file-icons [aria-label$=".odp"] i,
|
||||
.file-icons [aria-label$=".ppt"] i,
|
||||
.file-icons [aria-label$=".pptx"] i,
|
||||
.file-icons [aria-label$=".vue"] i,
|
||||
.file-icons [aria-label$=".xcf"] i {
|
||||
.file-icons [data-ext=".html"] i,
|
||||
.file-icons [data-ext=".odg"] i,
|
||||
.file-icons [data-ext=".odp"] i,
|
||||
.file-icons [data-ext=".ppt"] i,
|
||||
.file-icons [data-ext=".pptx"] i,
|
||||
.file-icons [data-ext=".vue"] i,
|
||||
.file-icons [data-ext=".xcf"] i {
|
||||
color: var(--icon-orange);
|
||||
}
|
||||
|
||||
/* #ff0 - Various */
|
||||
|
||||
.file-icons [aria-label$=".css"] i,
|
||||
.file-icons [aria-label$=".js"] i,
|
||||
.file-icons [aria-label$=".json"] i,
|
||||
.file-icons [aria-label$=".zip"] i {
|
||||
.file-icons [data-ext=".css"] i,
|
||||
.file-icons [data-ext=".js"] i,
|
||||
.file-icons [data-ext=".json"] i,
|
||||
.file-icons [data-ext=".zip"] i {
|
||||
color: var(--icon-yellow);
|
||||
}
|
||||
|
||||
/* #0f0 - Spreadsheet/Google */
|
||||
|
||||
.file-icons [aria-label$=".apk"] i,
|
||||
.file-icons [aria-label$=".dex"] i,
|
||||
.file-icons [aria-label$=".go"] i,
|
||||
.file-icons [aria-label$=".ods"] i,
|
||||
.file-icons [aria-label$=".xls"] i,
|
||||
.file-icons [aria-label$=".xlsx"] i {
|
||||
.file-icons [data-ext=".apk"] i,
|
||||
.file-icons [data-ext=".dex"] i,
|
||||
.file-icons [data-ext=".go"] i,
|
||||
.file-icons [data-ext=".ods"] i,
|
||||
.file-icons [data-ext=".xls"] i,
|
||||
.file-icons [data-ext=".xlsx"] i {
|
||||
color: var(--icon-green);
|
||||
}
|
||||
|
||||
/* #00f - Document/Microsoft/Apple/Closed */
|
||||
|
||||
.file-icons [aria-label$=".aac"] i,
|
||||
.file-icons [aria-label$=".bat"] i,
|
||||
.file-icons [aria-label$=".cab"] i,
|
||||
.file-icons [aria-label$=".cs"] i,
|
||||
.file-icons [aria-label$=".dmg"] i,
|
||||
.file-icons [aria-label$=".doc"] i,
|
||||
.file-icons [aria-label$=".docx"] i,
|
||||
.file-icons [aria-label$=".emf"] i,
|
||||
.file-icons [aria-label$=".exe"] i,
|
||||
.file-icons [aria-label$=".ico"] i,
|
||||
.file-icons [aria-label$=".mp2"] i,
|
||||
.file-icons [aria-label$=".mp3"] i,
|
||||
.file-icons [aria-label$=".mp4"] i,
|
||||
.file-icons [aria-label$=".mpg"] i,
|
||||
.file-icons [aria-label$=".msi"] i,
|
||||
.file-icons [aria-label$=".odt"] i,
|
||||
.file-icons [aria-label$=".ps1"] i,
|
||||
.file-icons [aria-label$=".rtf"] i,
|
||||
.file-icons [aria-label$=".vob"] i,
|
||||
.file-icons [aria-label$=".wim"] i {
|
||||
.file-icons [data-ext=".aac"] i,
|
||||
.file-icons [data-ext=".bat"] i,
|
||||
.file-icons [data-ext=".cab"] i,
|
||||
.file-icons [data-ext=".cs"] i,
|
||||
.file-icons [data-ext=".dmg"] i,
|
||||
.file-icons [data-ext=".doc"] i,
|
||||
.file-icons [data-ext=".docx"] i,
|
||||
.file-icons [data-ext=".emf"] i,
|
||||
.file-icons [data-ext=".exe"] i,
|
||||
.file-icons [data-ext=".ico"] i,
|
||||
.file-icons [data-ext=".mp2"] i,
|
||||
.file-icons [data-ext=".mp3"] i,
|
||||
.file-icons [data-ext=".mp4"] i,
|
||||
.file-icons [data-ext=".mpg"] i,
|
||||
.file-icons [data-ext=".msi"] i,
|
||||
.file-icons [data-ext=".odt"] i,
|
||||
.file-icons [data-ext=".ps1"] i,
|
||||
.file-icons [data-ext=".rtf"] i,
|
||||
.file-icons [data-ext=".vob"] i,
|
||||
.file-icons [data-ext=".wim"] i {
|
||||
color: var(--icon-blue);
|
||||
}
|
||||
|
||||
/* #60f - Various */
|
||||
|
||||
.file-icons [aria-label$=".iso"] i,
|
||||
.file-icons [aria-label$=".php"] i,
|
||||
.file-icons [aria-label$=".rar"] i {
|
||||
.file-icons [data-ext=".iso"] i,
|
||||
.file-icons [data-ext=".php"] i,
|
||||
.file-icons [data-ext=".rar"] i {
|
||||
color: var(--icon-violet);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,6 +195,10 @@ html[dir="rtl"] #listing {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#listing.list .item p.name:not(#listing.list .item.header .name) {
|
||||
margin-right: -3em;
|
||||
}
|
||||
|
||||
#listing.list .item .name {
|
||||
width: 50%;
|
||||
}
|
||||
@@ -227,10 +231,6 @@ html[dir="rtl"] #listing {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#listing.list .item.header .name {
|
||||
margin-right: 3em;
|
||||
}
|
||||
|
||||
#listing.list .header a {
|
||||
color: inherit;
|
||||
}
|
||||
@@ -241,10 +241,9 @@ html[dir="rtl"] #listing {
|
||||
|
||||
#listing.list .name {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#listing.list .item.header .name {
|
||||
margin-right: 3em;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
#listing.list .header span {
|
||||
|
||||
13
frontend/src/css/mdPreview.css
Normal file
13
frontend/src/css/mdPreview.css
Normal file
@@ -0,0 +1,13 @@
|
||||
.md_preview {
|
||||
overflow-y: auto;
|
||||
max-height: 80vh;
|
||||
padding: 1rem;
|
||||
border: 1px solid #000;
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
#preview-container {
|
||||
overflow: auto;
|
||||
max-height: 80vh; /* Match the max-height of md_preview for scrolling */
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
@import "./dashboard.css";
|
||||
@import "./login.css";
|
||||
@import "./mobile.css";
|
||||
@import "./epubReader.css";
|
||||
@import "./mdPreview.css";
|
||||
|
||||
/* For testing only
|
||||
:focus {
|
||||
@@ -269,7 +271,7 @@ main .spinner .bounce2 {
|
||||
#previewer .pdf {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 4em;
|
||||
padding-top: 4em;
|
||||
}
|
||||
|
||||
#previewer h2.message {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"ok": "موافق",
|
||||
"permalink": "الحصول على رابط دائم",
|
||||
"previous": "السابق",
|
||||
"preview": "Preview",
|
||||
"publish": "نشر",
|
||||
"rename": "إعادة تسمية",
|
||||
"replace": "استبدال",
|
||||
@@ -169,6 +170,7 @@
|
||||
"commandRunnerHelp": "هنا بإمكانك تعيين اﻷوامر التي سيتم تنفيذها في اﻷحداث المسماة. يجب كتابة أمر واحد في كل سطر. ستكون المتغيرات البيئية (env) {0} و {1} متاحة، حيث {0} نسبي لـ {1}. لمزيد من المعلومات حول هذه الميزة و المتغيرات البيئية المتاحة، يرجى قراءة {2}.",
|
||||
"commandsUpdated": "تم تحديث اﻷوامر",
|
||||
"createUserDir": "إنشاء مجلد المستخدم (home) تلقائياً عند إنشاء مستخدم جديد",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "التحميلات المتقطعة",
|
||||
"tusUploadsHelp": "يدعم متصفح الملفات تحميل الملفات المتقطعة، مما يسمح بتحميلات الملفات بشكل فعال و موثوق و قابلة للمتابغة و متقطعة حتى على الشبكات غير الموثوقة.",
|
||||
"tusUploadsChunkSize": "يشير إلى الحد اﻷقصى لحجم الطلب (سيتم استخدام التحميل المباشر للتحميلات صغيرة الخحم). يمكنك إدخال عدد صحيح عادي يدل على الحجم بوحدة البايت أو نمظ مثل10MB, 1GB, إلخ.",
|
||||
|
||||
266
frontend/src/i18n/ca.json
Normal file
266
frontend/src/i18n/ca.json
Normal file
@@ -0,0 +1,266 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Cancel·lar",
|
||||
"clear": "Netejar",
|
||||
"close": "Tancar",
|
||||
"continue": "Continuar",
|
||||
"copy": "Copiar",
|
||||
"copyFile": "Copiar fitxer",
|
||||
"copyToClipboard": "Copiar al porta-retalls",
|
||||
"copyDownloadLinkToClipboard": "Copiar l'enllaç de descàrrega al portapapers",
|
||||
"create": "Crear",
|
||||
"delete": "Esborrar",
|
||||
"download": "Descarregar",
|
||||
"file": "Fitxer",
|
||||
"folder": "Carpeta",
|
||||
"fullScreen": "Canviar a pantalla completa",
|
||||
"hideDotfiles": "Ocultar fitxers que comencen per punt",
|
||||
"info": "Info",
|
||||
"more": "Més",
|
||||
"move": "Moure",
|
||||
"moveFile": "Moure fitxer",
|
||||
"new": "Nou",
|
||||
"next": "Següent",
|
||||
"ok": "D'acord",
|
||||
"permalink": "Enllaç permanent",
|
||||
"previous": "Anterior",
|
||||
"preview": "Preview",
|
||||
"publish": "Publicar",
|
||||
"rename": "Reanomenar",
|
||||
"replace": "Substituir",
|
||||
"reportIssue": "Reportar problema",
|
||||
"save": "Desar",
|
||||
"schedule": "Programar",
|
||||
"search": "Cercar",
|
||||
"select": "Seleccionar",
|
||||
"selectMultiple": "Selecció múltiple",
|
||||
"share": "Compartir",
|
||||
"shell": "Prem Enter per cercar...",
|
||||
"submit": "Enviar",
|
||||
"switchView": "Canviar vista",
|
||||
"toggleSidebar": "Mostrar/ocultar menú",
|
||||
"update": "Actualitzar",
|
||||
"upload": "Pujar",
|
||||
"openFile": "Obrir fitxer",
|
||||
"discardChanges": "Descartar"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Descarregar fitxer",
|
||||
"downloadFolder": "Descarregar directori",
|
||||
"downloadSelected": "Descarregar seleccionats"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Are you sure you wish to abort?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "No tens els permisos necessaris per accedir.",
|
||||
"internal": "La veritat és que alguna cosa ha anat malament.",
|
||||
"notFound": "No es pot accedir a aquest lloc.",
|
||||
"connection": "No es pot accedir al servidor."
|
||||
},
|
||||
"files": {
|
||||
"body": "Cos",
|
||||
"closePreview": "Tancar vista prèvia",
|
||||
"files": "Fitxers",
|
||||
"folders": "Carpetes",
|
||||
"home": "Inici",
|
||||
"lastModified": "Última modificació",
|
||||
"loading": "Carregant...",
|
||||
"lonely": "Un se sent molt sol aquí...",
|
||||
"metadata": "Metadades",
|
||||
"multipleSelectionEnabled": "Selecció múltiple activada",
|
||||
"name": "Nom",
|
||||
"size": "Mida",
|
||||
"sortByLastModified": "Ordenar per última modificació",
|
||||
"sortByName": "Ordenar per nom",
|
||||
"sortBySize": "Ordenar per mida",
|
||||
"noPreview": "La vista prèvia no està disponible per a aquest fitxer."
|
||||
},
|
||||
"help": {
|
||||
"click": "seleccionar fitxer o carpeta",
|
||||
"ctrl": {
|
||||
"click": "seleccionar múltiples fitxers o carpetes",
|
||||
"f": "obre la cerca",
|
||||
"s": "desa un fitxer o el descarrega a la carpeta en què estàs"
|
||||
},
|
||||
"del": "elimina els ítems seleccionats",
|
||||
"doubleClick": "obre un fitxer o carpeta",
|
||||
"esc": "neteja la selecció i/o tanca la finestra",
|
||||
"f1": "aquesta informació",
|
||||
"f2": "reanomenar fitxer",
|
||||
"help": "Ajuda"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Crear un compte",
|
||||
"loginInstead": "Usuari ja existent",
|
||||
"password": "Contrasenya",
|
||||
"passwordConfirm": "Confirmació de contrasenya",
|
||||
"passwordsDontMatch": "Les contrasenyes no coincideixen",
|
||||
"signup": "Registra't",
|
||||
"submit": "Iniciar sessió",
|
||||
"username": "Usuari",
|
||||
"usernameTaken": "Nom d'usuari no disponible",
|
||||
"wrongCredentials": "Usuari i/o contrasenya incorrectes"
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
"copy": "Copiar",
|
||||
"copyMessage": "Tria el lloc on vols copiar els teus fitxers:",
|
||||
"currentlyNavigating": "Actualment estàs a:",
|
||||
"deleteMessageMultiple": "Estàs segur que vols eliminar {count} fitxer(s)?",
|
||||
"deleteMessageSingle": "Estàs segur que vols eliminar aquest fitxer/carpeta?",
|
||||
"deleteMessageShare": "Estàs segur que vols eliminar aquest recurs compartit ({path})?",
|
||||
"deleteUser": "Esteu segur que voleu eliminar aquest usuari?",
|
||||
"deleteTitle": "Esborrar fitxers",
|
||||
"displayName": "Nom:",
|
||||
"download": "Descarregar fitxers",
|
||||
"downloadMessage": "Tria el format de descàrrega.",
|
||||
"error": "Alguna cosa ha fallat",
|
||||
"fileInfo": "Informació del fitxer",
|
||||
"filesSelected": "{count} fitxers seleccionats.",
|
||||
"lastModified": "Última modificació",
|
||||
"move": "Moure",
|
||||
"moveMessage": "Tria una nova casa per als teus fitxers/carpeta(s):",
|
||||
"newArchetype": "Crea un nou post basat en un arquetip. El teu fitxer serà creat a la carpeta de contingut.",
|
||||
"newDir": "Nova carpeta",
|
||||
"newDirMessage": "Escriu el nom de la nova carpeta.",
|
||||
"newFile": "Nou fitxer",
|
||||
"newFileMessage": "Escriu el nom del nou fitxer.",
|
||||
"numberDirs": "Nombre de carpetes",
|
||||
"numberFiles": "Nombre de fitxers",
|
||||
"rename": "Reanomenar",
|
||||
"renameMessage": "Escriu el nou nom per a",
|
||||
"replace": "Substituir",
|
||||
"replaceMessage": "Un dels fitxers que intentes pujar està creant conflicte pel seu nom. Vols canviar el nom del ja existent?\n",
|
||||
"schedule": "Programar",
|
||||
"scheduleMessage": "Tria una hora i data per programar la publicació d'aquest post.",
|
||||
"show": "Mostrar",
|
||||
"size": "Mida",
|
||||
"upload": "Pujar",
|
||||
"uploadFiles": "Pujant {files} fitxers...",
|
||||
"uploadMessage": "Seleccioneu una opció per pujar.",
|
||||
"optionalPassword": "Contrasenya opcional",
|
||||
"resolution": "Resolució",
|
||||
"discardEditorChanges": "Esteu segur que voleu descartar els canvis que heu fet?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Imatges",
|
||||
"music": "Música",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Prem Enter per cercar...",
|
||||
"search": "Cercar...",
|
||||
"typeToSearch": "Escriu per fer una cerca...",
|
||||
"types": "Tipus",
|
||||
"video": "Vídeo"
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrador",
|
||||
"allowCommands": "Executar comandes",
|
||||
"allowEdit": "Editar, reanomenar i esborrar fitxers o carpetes",
|
||||
"allowNew": "Crear nous fitxers i carpetes",
|
||||
"allowPublish": "Publicar nous posts i pàgines",
|
||||
"allowSignup": "Permetre registre d'usuaris",
|
||||
"avoidChanges": "(deixar en blanc per evitar canvis)",
|
||||
"branding": "Marca",
|
||||
"brandingDirectoryPath": "Ruta de la carpeta de personalització de marca",
|
||||
"brandingHelp": "Pots personalitzar com es veu la teva instància de FileBrowser canviant-li el nom, reemplaçant el logotip, afegint estils personalitzats i fins i tot deshabilitant els enllaços externs que apunten cap a GitHub. \nPer a més informació sobre personalització de marca, si us plau revisa el {0}.",
|
||||
"changePassword": "Canviar contrasenya",
|
||||
"commandRunner": "Executor de comandes",
|
||||
"commandRunnerHelp": "Aquí pots establir les comandes que s'executen en els esdeveniments anomenats. Has d'escriure'n una per línia. Les variables d'entorn {0} i {1} estaran disponibles, sent {0} relativa a {1}. Per a més informació sobre aquesta característica i les variables d'entorn disponibles, si us plau llegeix el {2}.",
|
||||
"commandsUpdated": "Comandes actualitzades!",
|
||||
"createUserDir": "Crea automàticament una carpeta d'inici quan s'afegeix un usuari",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "Càrregues a trossos",
|
||||
"tusUploadsHelp": "El File Browser suporta càrregues de fitxers a trossos, permetent la creació de càrregues de fitxers eficients, fiables, reanudables i a trossos fins i tot en xarxes poc fiables.",
|
||||
"tusUploadsChunkSize": "Indica la mida màxima d'una sol·licitud (s'utilitzaran càrregues directes per a càrregues més petites). Podeu introduir un enter pla que indiqui la mida en bytes o una cadena com 10MB, 1GB, etc.",
|
||||
"tusUploadsRetryCount": "Nombre de reintents a realitzar si una part falla en carregar-se.",
|
||||
"userHomeBasePath": "Ruta base per als directoris personals dels usuaris",
|
||||
"userScopeGenerationPlaceholder": "L'àmbit es generarà automàticament",
|
||||
"createUserHomeDirectory": "Crear el directori principal de l'usuari",
|
||||
"customStylesheet": "Modificar full d'estils",
|
||||
"defaultUserDescription": "Aquestes són les configuracions per defecte per a nous usuaris.",
|
||||
"disableExternalLinks": "Deshabilitar enllaços externs (excepte documentació)",
|
||||
"disableUsedDiskPercentage": "Desactivar el gràfic de percentatge de disc utilitzat",
|
||||
"documentation": "documentació",
|
||||
"examples": "Exemples",
|
||||
"executeOnShell": "Executar a la shell",
|
||||
"executeOnShellDescription": "Per defecte, FileBrowser executa les comandes cridant directament els seus binaris. Si vols executar-los en una shell en lloc (com Bash o PowerShell), pots definir-ho aquí amb els arguments i flags necessaris. Si es defineix, la comanda que s'executa s'afegirà com a argument. Això s'aplica tant a les comandes d'usuari com als ganxos d'esdeveniments.",
|
||||
"globalRules": "Es tracta d'un conjunt global de regles de permís i rebuig. S'apliquen a tots els usuaris. Pots definir regles específiques en la configuració de cada usuari per anul·lar aquestes.",
|
||||
"globalSettings": "Ajustos globals",
|
||||
"hideDotfiles": "Ocultar fitxers que comencen per punt",
|
||||
"insertPath": "Introdueix la ruta",
|
||||
"insertRegex": "Introduir expressió regular",
|
||||
"instanceName": "Nom de la instància",
|
||||
"language": "Idioma",
|
||||
"lockPassword": "Evitar que l'usuari canviï la contrasenya",
|
||||
"newPassword": "La teva nova contrasenya",
|
||||
"newPasswordConfirm": "Confirma la teva contrasenya",
|
||||
"newUser": "Nou usuari",
|
||||
"password": "Contrasenya",
|
||||
"passwordUpdated": "Contrasenya actualitzada!",
|
||||
"path": "Ruta",
|
||||
"perm": {
|
||||
"create": "Crear fitxers i directoris",
|
||||
"delete": "Eliminar fitxers i directoris",
|
||||
"download": "Descarregar",
|
||||
"execute": "Executar comandes",
|
||||
"modify": "Editar fitxers",
|
||||
"rename": "Reanomenar o moure fitxers i directoris",
|
||||
"share": "Compartir fitxers"
|
||||
},
|
||||
"permissions": "Permisos",
|
||||
"permissionsHelp": "Pots nomenar l'usuari com a administrador o triar els permisos individualment. Si selecciones \"Administrador\", totes les altres opcions s'activaran automàticament. L'administració d'usuaris és un privilegi d'administrador.\n",
|
||||
"profileSettings": "Ajustos del perfil",
|
||||
"ruleExample1": "prevé l'accés a una extensió de fitxer (Com .git) en cada carpeta.\n",
|
||||
"ruleExample2": "bloqueja l'accés al fitxer anomenat Caddyfile a la carpeta arrel.",
|
||||
"rules": "Regles",
|
||||
"rulesHelp": "Aquí pots definir un conjunt de regles de permisos per a aquest usuari específic. Els fitxers bloquejats no es mostraran en les llistes i no seran accessibles per l'usuari. Pots utilitzar regex i rutes relatives a l'arrel de l'usuari.\n",
|
||||
"scope": "Arrel",
|
||||
"setDateFormat": "Establir el format exacte de la data",
|
||||
"settingsUpdated": "Ajustos actualitzats!",
|
||||
"shareDuration": "Compartir Duració",
|
||||
"shareManagement": "Gestió Compartida",
|
||||
"shareDeleted": "Recurs compartit eliminat!",
|
||||
"singleClick": "Utilitza un sol clic per obrir fitxers i directoris",
|
||||
"themes": {
|
||||
"default": "Valor per defecte del sistema",
|
||||
"dark": "Fosc",
|
||||
"light": "Clar",
|
||||
"title": "Tema"
|
||||
},
|
||||
"user": "Usuari",
|
||||
"userCommands": "Comandes",
|
||||
"userCommandsHelp": "Una llista separada per espais amb les comandes permeses per a aquest usuari. Exemple:\n",
|
||||
"userCreated": "Usuari creat!",
|
||||
"userDefaults": "Configuració d'usuari per defecte",
|
||||
"userDeleted": "Usuari eliminat!",
|
||||
"userManagement": "Administració d'usuaris",
|
||||
"userUpdated": "Usuari actualitzat!",
|
||||
"username": "Usuari",
|
||||
"users": "Usuaris"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
"hugoNew": "Nou Hugo",
|
||||
"login": "Iniciar sessió",
|
||||
"logout": "Tancar sessió",
|
||||
"myFiles": "Els meus fitxers",
|
||||
"newFile": "Nou fitxer",
|
||||
"newFolder": "Nova carpeta",
|
||||
"preview": "Vista prèvia",
|
||||
"settings": "Ajustos",
|
||||
"signup": "Registra't",
|
||||
"siteSettings": "Ajustos del lloc"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Enllaç copiat!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Dies",
|
||||
"hours": "Hores",
|
||||
"minutes": "Minuts",
|
||||
"seconds": "Segons",
|
||||
"unit": "Unitat"
|
||||
}
|
||||
}
|
||||
266
frontend/src/i18n/cs.json
Normal file
266
frontend/src/i18n/cs.json
Normal file
@@ -0,0 +1,266 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Zrušit",
|
||||
"clear": "Vymazat",
|
||||
"close": "Zavřít",
|
||||
"continue": "Pokračovat",
|
||||
"copy": "Kopírovat",
|
||||
"copyFile": "Kopírovat soubor",
|
||||
"copyToClipboard": "Kopírovat do schránky",
|
||||
"copyDownloadLinkToClipboard": "Kopírovat odkaz na stažení do schránky",
|
||||
"create": "Vytvořit",
|
||||
"delete": "Smazat",
|
||||
"download": "Stáhnout",
|
||||
"file": "Soubor",
|
||||
"folder": "Složka",
|
||||
"fullScreen": "Přepnout na celou obrazovku",
|
||||
"hideDotfiles": "Skrýt skryté soubory",
|
||||
"info": "Informace",
|
||||
"more": "Více",
|
||||
"move": "Přesunout",
|
||||
"moveFile": "Přesunout soubor",
|
||||
"new": "Nový",
|
||||
"next": "Další",
|
||||
"ok": "OK",
|
||||
"permalink": "Získat trvalý odkaz",
|
||||
"previous": "Předchozí",
|
||||
"preview": "Preview",
|
||||
"publish": "Publikovat",
|
||||
"rename": "Přejmenovat",
|
||||
"replace": "Nahradit",
|
||||
"reportIssue": "Nahlásit problém",
|
||||
"save": "Uložit",
|
||||
"schedule": "Naplánovat",
|
||||
"search": "Hledat",
|
||||
"select": "Vybrat",
|
||||
"selectMultiple": "Vybrat více",
|
||||
"share": "Sdílet",
|
||||
"shell": "Přepnout shell",
|
||||
"submit": "Odeslat",
|
||||
"switchView": "Přepnout zobrazení",
|
||||
"toggleSidebar": "Přepnout postranní panel",
|
||||
"update": "Aktualizovat",
|
||||
"upload": "Nahrát",
|
||||
"openFile": "Otevřít soubor",
|
||||
"discardChanges": "Zrušit změny"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Stáhnout soubor",
|
||||
"downloadFolder": "Stáhnout složku",
|
||||
"downloadSelected": "Stáhnout vybrané"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Opravdu chcete přerušit nahrávání?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Nemáte oprávnění k přístupu.",
|
||||
"internal": "Nastala vážná chyba.",
|
||||
"notFound": "Tuto lokaci nelze najít.",
|
||||
"connection": "Server nelze dosáhnout."
|
||||
},
|
||||
"files": {
|
||||
"body": "Tělo",
|
||||
"closePreview": "Zavřít náhled",
|
||||
"files": "Soubory",
|
||||
"folders": "Složky",
|
||||
"home": "Domů",
|
||||
"lastModified": "Naposledy změněno",
|
||||
"loading": "Načítání...",
|
||||
"lonely": "Je tu osaměle...",
|
||||
"metadata": "Metadata",
|
||||
"multipleSelectionEnabled": "Vícenásobný výběr povolen",
|
||||
"name": "Název",
|
||||
"size": "Velikost",
|
||||
"sortByLastModified": "Seřadit podle poslední změny",
|
||||
"sortByName": "Seřadit podle názvu",
|
||||
"sortBySize": "Seřadit podle velikosti",
|
||||
"noPreview": "Náhled pro tento soubor není k dispozici."
|
||||
},
|
||||
"help": {
|
||||
"click": "vyberte soubor nebo adresář",
|
||||
"ctrl": {
|
||||
"click": "vybrat více souborů nebo adresářů",
|
||||
"f": "otevřít vyhledávání",
|
||||
"s": "uložit soubor nebo stáhnout adresář, kde se nacházíte"
|
||||
},
|
||||
"del": "smazat vybrané položky",
|
||||
"doubleClick": "otevřít soubor nebo adresář",
|
||||
"esc": "zrušit výběr a/nebo zavřít výzvu",
|
||||
"f1": "tato informace",
|
||||
"f2": "přejmenovat soubor",
|
||||
"help": "Nápověda"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Vytvořit účet",
|
||||
"loginInstead": "Již máte účet",
|
||||
"password": "Heslo",
|
||||
"passwordConfirm": "Potvrzení hesla",
|
||||
"passwordsDontMatch": "Hesla se neshodují",
|
||||
"signup": "Registrace",
|
||||
"submit": "Přihlásit se",
|
||||
"username": "Uživatelské jméno",
|
||||
"usernameTaken": "Uživatelské jméno již existuje",
|
||||
"wrongCredentials": "Nesprávné přihlašovací údaje"
|
||||
},
|
||||
"permanent": "Trvalý",
|
||||
"prompts": {
|
||||
"copy": "Kopírovat",
|
||||
"copyMessage": "Vyberte místo, kam chcete soubory kopírovat:",
|
||||
"currentlyNavigating": "Aktuálně navigujete v:",
|
||||
"deleteMessageMultiple": "Opravdu chcete smazat {count} soubor(ů)?",
|
||||
"deleteMessageSingle": "Opravdu chcete smazat tento soubor/složku?",
|
||||
"deleteMessageShare": "Opravdu chcete smazat toto sdílení({path})?",
|
||||
"deleteUser": "Opravdu chcete smazat tohoto uživatele?",
|
||||
"deleteTitle": "Smazat soubory",
|
||||
"displayName": "Zobrazované jméno:",
|
||||
"download": "Stáhnout soubory",
|
||||
"downloadMessage": "Vyberte formát, který chcete stáhnout.",
|
||||
"error": "Něco se pokazilo",
|
||||
"fileInfo": "Informace o souboru",
|
||||
"filesSelected": "{count} souborů vybráno.",
|
||||
"lastModified": "Naposledy změněno",
|
||||
"move": "Přesunout",
|
||||
"moveMessage": "Vyberte nové umístění pro váš soubor(y)/složku(y):",
|
||||
"newArchetype": "Vytvořit nový příspěvek na základě archetypu. Váš soubor bude vytvořen ve složce content.",
|
||||
"newDir": "Nový adresář",
|
||||
"newDirMessage": "Pojmenujte svůj nový adresář.",
|
||||
"newFile": "Nový soubor",
|
||||
"newFileMessage": "Pojmenujte svůj nový soubor.",
|
||||
"numberDirs": "Počet adresářů",
|
||||
"numberFiles": "Počet souborů",
|
||||
"rename": "Přejmenovat",
|
||||
"renameMessage": "Vložte nový název pro",
|
||||
"replace": "Nahradit",
|
||||
"replaceMessage": "Jeden ze souborů, které se snažíte nahrát, má konfliktní název. Chcete tento soubor přeskočit a pokračovat v nahrávání, nebo nahradit stávající?",
|
||||
"schedule": "Naplánovat",
|
||||
"scheduleMessage": "Vyberte datum a čas pro naplánování publikace tohoto příspěvku.",
|
||||
"show": "Zobrazit",
|
||||
"size": "Velikost",
|
||||
"upload": "Nahrát",
|
||||
"uploadFiles": "Nahrávání {files} souborů...",
|
||||
"uploadMessage": "Vyberte možnost pro nahrání.",
|
||||
"optionalPassword": "Volitelné heslo",
|
||||
"resolution": "Rozlišení",
|
||||
"discardEditorChanges": "Opravdu chcete zrušit provedené změny?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Obrázky",
|
||||
"music": "Hudba",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Stiskněte enter pro hledání...",
|
||||
"search": "Hledat...",
|
||||
"typeToSearch": "Zadejte pro hledání...",
|
||||
"types": "Typy",
|
||||
"video": "Video"
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrátor",
|
||||
"allowCommands": "Povolit příkazy",
|
||||
"allowEdit": "Upravit, přejmenovat a mazat soubory nebo adresáře",
|
||||
"allowNew": "Vytvářet nové soubory a adresáře",
|
||||
"allowPublish": "Publikovat nové příspěvky a stránky",
|
||||
"allowSignup": "Povolit uživatelům registraci",
|
||||
"avoidChanges": "(ponechte prázdné pro zabránění změnám)",
|
||||
"branding": "Branding",
|
||||
"brandingDirectoryPath": "Cesta ke složce s brandingem",
|
||||
"brandingHelp": "Můžete přizpůsobit vzhled a dojem z vaší instance File Browseru změnou názvu, nahrazením loga, přidáním vlastních stylů a dokonce zakázat externí odkazy na GitHub.\nPro více informací o přizpůsobení brandingu se podívejte na {0}.",
|
||||
"changePassword": "Změnit heslo",
|
||||
"commandRunner": "Spouštění příkazů",
|
||||
"commandRunnerHelp": "Zde můžete nastavit příkazy, které se spustí při určených událostech. Každý příkaz musí být na samostatném řádku. Budou k dispozici proměnné prostředí {0} a {1}, přičemž {0} se vztahuje na {1}. Pro více informací o této funkci a dostupných proměnných prostředí si přečtěte {2}.",
|
||||
"commandsUpdated": "Příkazy aktualizovány!",
|
||||
"createUserDir": "Automaticky vytvořit domovskou složku uživatele při přidání nového uživatele",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "Nahrávání po částech",
|
||||
"tusUploadsHelp": "File Browser podporuje nahrávání souborů po částech, což umožňuje vytváření efektivních, spolehlivých, obnovitelných a rozdělených nahrávek souborů i na nespolehlivých sítích.",
|
||||
"tusUploadsChunkSize": "Maximální velikost požadavku (přímé nahrávání bude použito pro menší nahrávky). Můžete zadat prosté číslo označující velikost v bajtech nebo řetězec jako 10MB, 1GB atd.",
|
||||
"tusUploadsRetryCount": "Počet pokusů o opakování, pokud se nahrání části nezdaří.",
|
||||
"userHomeBasePath": "Základní cesta pro domovské adresáře uživatelů",
|
||||
"userScopeGenerationPlaceholder": "Rozsah bude automaticky vygenerován",
|
||||
"createUserHomeDirectory": "Vytvořit domovský adresář uživatele",
|
||||
"customStylesheet": "Vlastní stylový soubor",
|
||||
"defaultUserDescription": "Toto jsou výchozí nastavení pro nové uživatele.",
|
||||
"disableExternalLinks": "Zakázat externí odkazy (kromě dokumentace)",
|
||||
"disableUsedDiskPercentage": "Zakázat graf s procentem využitého disku",
|
||||
"documentation": "dokumentace",
|
||||
"examples": "Příklady",
|
||||
"executeOnShell": "Spustit na shellu",
|
||||
"executeOnShellDescription": "Ve výchozím nastavení File Browser spouští příkazy přímo voláním jejich binárek. Pokud je chcete spouštět na shellu (např. Bash nebo PowerShell), můžete to zde definovat s požadovanými argumenty a příznaky. Pokud je nastaveno, příkaz, který spustíte, bude přidán jako argument. To platí jak pro uživatelské příkazy, tak pro háky událostí.",
|
||||
"globalRules": "Jedná se o globální sadu povolení a zakázání pravidel. Platí pro každého uživatele. Specifická pravidla můžete definovat v nastaveních každého uživatele, aby přepsala tato pravidla.",
|
||||
"globalSettings": "Globální nastavení",
|
||||
"hideDotfiles": "Skrýt skryté soubory",
|
||||
"insertPath": "Vložte cestu",
|
||||
"insertRegex": "Vložte regex výraz",
|
||||
"instanceName": "Název instance",
|
||||
"language": "Jazyk",
|
||||
"lockPassword": "Zabránit uživateli ve změně hesla",
|
||||
"newPassword": "Vaše nové heslo",
|
||||
"newPasswordConfirm": "Potvrďte své nové heslo",
|
||||
"newUser": "Nový uživatel",
|
||||
"password": "Heslo",
|
||||
"passwordUpdated": "Heslo bylo aktualizováno!",
|
||||
"path": "Cesta",
|
||||
"perm": {
|
||||
"create": "Vytvářet soubory a adresáře",
|
||||
"delete": "Mazat soubory a adresáře",
|
||||
"download": "Stahovat",
|
||||
"execute": "Spouštět příkazy",
|
||||
"modify": "Upravit soubory",
|
||||
"rename": "Přejmenovat nebo přesunout soubory a adresáře",
|
||||
"share": "Sdílet soubory"
|
||||
},
|
||||
"permissions": "Oprávnění",
|
||||
"permissionsHelp": "Můžete nastavit uživatele jako administrátora nebo zvolit jednotlivá oprávnění. Pokud vyberete \"Administrátor\", všechny ostatní možnosti budou automaticky zaškrtnuty. Správa uživatelů zůstává výsadou administrátora.\n",
|
||||
"profileSettings": "Nastavení profilu",
|
||||
"ruleExample1": "zabraňuje přístupu k jakémukoli skrytému souboru (např. .git, .gitignore) v každé složce.\n",
|
||||
"ruleExample2": "blokuje přístup k souboru s názvem Caddyfile v kořenovém adresáři.",
|
||||
"rules": "Pravidla",
|
||||
"rulesHelp": "Zde můžete definovat sadu povolení a zakázání pravidel pro tohoto konkrétního uživatele. Blokované soubory se nebudou zobrazovat v seznamech a uživatel k nim nebude mít přístup. Podporujeme regex a cesty relativní k rozsahu uživatele.\n",
|
||||
"scope": "Rozsah",
|
||||
"setDateFormat": "Nastavit přesný formát data",
|
||||
"settingsUpdated": "Nastavení aktualizována!",
|
||||
"shareDuration": "Doba sdílení",
|
||||
"shareManagement": "Správa sdílení",
|
||||
"shareDeleted": "Sdílení bylo smazáno!",
|
||||
"singleClick": "Použít jediné kliknutí pro otevření souborů a adresářů",
|
||||
"themes": {
|
||||
"default": "Systémové výchozí",
|
||||
"dark": "Tmavý",
|
||||
"light": "Světlý",
|
||||
"title": "Motiv"
|
||||
},
|
||||
"user": "Uživatel",
|
||||
"userCommands": "Příkazy",
|
||||
"userCommandsHelp": "Seznam dostupných příkazů pro tohoto uživatele oddělený mezerami. Příklad:\n",
|
||||
"userCreated": "Uživatel vytvořen!",
|
||||
"userDefaults": "Výchozí nastavení uživatele",
|
||||
"userDeleted": "Uživatel smazán!",
|
||||
"userManagement": "Správa uživatelů",
|
||||
"userUpdated": "Uživatel aktualizován!",
|
||||
"username": "Uživatelské jméno",
|
||||
"users": "Uživatelé"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Nápověda",
|
||||
"hugoNew": "Hugo Nový",
|
||||
"login": "Přihlásit se",
|
||||
"logout": "Odhlásit se",
|
||||
"myFiles": "Moje soubory",
|
||||
"newFile": "Nový soubor",
|
||||
"newFolder": "Nová složka",
|
||||
"preview": "Náhled",
|
||||
"settings": "Nastavení",
|
||||
"signup": "Registrace",
|
||||
"siteSettings": "Nastavení webu"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Odkaz zkopírován!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Dny",
|
||||
"hours": "Hodiny",
|
||||
"minutes": "Minuty",
|
||||
"seconds": "Sekundy",
|
||||
"unit": "Časová jednotka"
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,17 @@
|
||||
"cancel": "Abbrechen",
|
||||
"clear": "Schließen",
|
||||
"close": "Schließen",
|
||||
"continue": "Fortfahren",
|
||||
"copy": "Kopieren",
|
||||
"copyFile": "Kopiere Datei",
|
||||
"copyToClipboard": "In Zwischenablage kopieren",
|
||||
"copyDownloadLinkToClipboard": "Download-Link in die Zwischenablage kopieren",
|
||||
"create": "Neu",
|
||||
"delete": "Löschen",
|
||||
"download": "Herunterladen",
|
||||
"file": "Datei",
|
||||
"folder": "Ordner",
|
||||
"fullScreen": "Vollbildmodus umschalten",
|
||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||
"info": "Info",
|
||||
"more": "mehr",
|
||||
@@ -21,6 +24,7 @@
|
||||
"ok": "OK",
|
||||
"permalink": "permanenten Verweis anzeigen",
|
||||
"previous": "vorherige",
|
||||
"preview": "Vorschau",
|
||||
"publish": "Veröffentlichen",
|
||||
"rename": "umbenennen",
|
||||
"replace": "Ersetzen",
|
||||
@@ -37,16 +41,20 @@
|
||||
"toggleSidebar": "Seitenleiste anzeigen",
|
||||
"update": "Update",
|
||||
"upload": "Upload",
|
||||
"openFile": "Datei öffnen"
|
||||
"openFile": "Datei öffnen",
|
||||
"discardChanges": "Verwerfen"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Download Datei",
|
||||
"downloadFolder": "Download Ordner",
|
||||
"downloadSelected": "Auswahl herunterladen"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Sind Sie sicher, dass Sie den Vorgang abbrechen möchten?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
|
||||
"internal": "Etwas ist schief gelaufen.",
|
||||
"internal": "Etwas ist schiefgelaufen.",
|
||||
"notFound": "Dieser Ort kann nicht angezeigt werden.",
|
||||
"connection": "Der Server ist nicht erreichbar."
|
||||
},
|
||||
@@ -73,7 +81,7 @@
|
||||
"ctrl": {
|
||||
"click": "Markiere mehrere Dateien oder Ordner",
|
||||
"f": "Öffnet eine neue Suche",
|
||||
"s": "Speichert eine Datei oder einen Ordner am akutellen Ort"
|
||||
"s": "Speichert eine Datei oder einen Ordner am aktuellen Ort"
|
||||
},
|
||||
"del": "Löscht die ausgewählten Elemente",
|
||||
"doubleClick": "Öffnet eine Datei oder einen Ordner",
|
||||
@@ -102,11 +110,12 @@
|
||||
"deleteMessageMultiple": "Sind Sie sicher, dass Sie {count} Datei(en) löschen möchten?",
|
||||
"deleteMessageSingle": "Sind Sie sicher, dass Sie diesen Ordner/diese Datei löschen möchten?",
|
||||
"deleteMessageShare": "Sind Sie sicher, dass Sie diese Freigabe löschen möchten ({path})?",
|
||||
"deleteUser": "Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?",
|
||||
"deleteTitle": "Lösche Dateien",
|
||||
"displayName": "Anzeigename:",
|
||||
"download": "Lade Dateien",
|
||||
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
|
||||
"error": "Etwas ist schief gelaufen",
|
||||
"error": "Etwas ist schiefgelaufen",
|
||||
"fileInfo": "Dateiinformation",
|
||||
"filesSelected": "{count} Dateien ausgewählt.",
|
||||
"lastModified": "Zuletzt geändert",
|
||||
@@ -130,7 +139,9 @@
|
||||
"upload": "Upload",
|
||||
"uploadFiles": "Upload von {files} Dateien...",
|
||||
"uploadMessage": "Wählen Sie eine Upload-Methode",
|
||||
"optionalPassword": "Optionales Passwort"
|
||||
"optionalPassword": "Optionales Passwort",
|
||||
"resolution": "Auflösung",
|
||||
"discardEditorChanges": "Möchten Sie die vorgenommenen Änderungen wirklich verwerfen?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Bilder",
|
||||
@@ -150,19 +161,23 @@
|
||||
"allowNew": "Erstellen neuer Dateien und Ordner",
|
||||
"allowPublish": "Veröffentlichen von neuen Beiträgen und Seiten",
|
||||
"allowSignup": "Erlaube Benutzern sich zu registrieren",
|
||||
"avoidChanges": "(leer lassen um Änderungen zu vermeiden)",
|
||||
"avoidChanges": "(leer lassen, um Änderungen zu vermeiden)",
|
||||
"branding": "Design",
|
||||
"brandingDirectoryPath": "Designverzeichnispfad",
|
||||
"brandingHelp": "Sie können das Erscheinungsbild Ihres File Browser anpassen, in dem Sie den Namen ändern, das Logo austauchsen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen des Designs zu bekommen, gehen Sie bitte zu {0}.",
|
||||
"brandingHelp": "Sie können das Erscheinungsbild Ihres File Browser anpassen, in dem Sie den Namen ändern, das Logo austauschen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen des Designs zu bekommen, gehen Sie bitte zu {0}.",
|
||||
"changePassword": "Passwort ändern",
|
||||
"commandRunner": "Befehlseingabe",
|
||||
"commandRunnerHelp": "Hier könne Sie Befehle eintragen, welche bei den benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen Befehl eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen, lesen Sie bitte die {2}.",
|
||||
"commandRunnerHelp": "Hier könne Sie Befehle eintragen, welche bei den benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen Befehl eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen lesen Sie bitte die {2}.",
|
||||
"commandsUpdated": "Befehle aktualisiert!",
|
||||
"createUserDir": "Automatisches Erstellen des Home-Verzeichnisses beim Anlegen neuer Benutzer",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "Gestückelter Upload",
|
||||
"tusUploadsHelp": "File Browser unterstützt das Hochladen von gestückelten Dateien und ermöglicht so einen effizienten, zuverlässigen, fortsetzbaren und gestückelten Datei-Upload auch in unzuverlässigen Netzwerken.",
|
||||
"tusUploadsChunkSize": "Gibt die maximale Größe pro Anfrage an (direkte Uploads werden für kleinere Uploads verwendet). Bitte geben Sie eine Byte-Angabe oder eine Zeichenfolge wie 10 MB, 1 GB usw. an",
|
||||
"tusUploadsRetryCount": "Anzahl der Wiederholungsversuche, wenn das Hochladen eines Stückes fehlschlägt.",
|
||||
"userHomeBasePath": "Basispfad für Benutzer-Home-Verzeichnisse",
|
||||
"userScopeGenerationPlaceholder": "Scope wird automatisch generiert",
|
||||
"createUserHomeDirectory": "Benutzer-Home-Verzeichnis erstellen",
|
||||
"customStylesheet": "Individuelles Stylesheet",
|
||||
"defaultUserDescription": "Das sind die Standardeinstellung für Benutzer",
|
||||
"disableExternalLinks": "Externe Links deaktivieren (außer Dokumentation)",
|
||||
@@ -170,7 +185,7 @@
|
||||
"documentation": "Dokumentation",
|
||||
"examples": "Beispiele",
|
||||
"executeOnShell": "In Shell ausführen",
|
||||
"executeOnShellDescription": "Es ist voreingestellt das der File Brower Befehle ausführt in dem er die Befehlsdateien direkt aufruft. Wenn Sie wollen, dass sie über einer Kommandozeile (wie Bash oder PowerShell) laufen, könne Sie diese hier definieren mit allen bennötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benuzerkommandos sowie auch für Ereignisse.",
|
||||
"executeOnShellDescription": "Es ist voreingestellt, dass der File Brower Befehle ausführt, indem er die Befehlsdateien direkt aufruft. Wenn Sie wollen, dass sie über einer Kommandozeile (wie Bash oder PowerShell) laufen, könne Sie diese hier definieren mit allen benötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benutzerkommandos sowie auch für Ereignisse.",
|
||||
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden, die diese überschreiben.",
|
||||
"globalSettings": "Globale Einstellungen",
|
||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||
@@ -195,7 +210,7 @@
|
||||
"share": "Datei teilen"
|
||||
},
|
||||
"permissions": "Berechtigungen",
|
||||
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigunen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
|
||||
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigungen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
|
||||
"profileSettings": "Profileinstellungen",
|
||||
"ruleExample1": "Verhindert den Zugang zu versteckten Dateien (dot-Files, wie .git, .gitignore) in allen Ordnern\n",
|
||||
"ruleExample2": "blockiert den Zugang auf Dateien mit dem Namen Caddyfile in der Wurzel/Basis des Scopes.",
|
||||
@@ -209,6 +224,7 @@
|
||||
"shareDeleted": "Freigabe gelöscht!",
|
||||
"singleClick": "Einfacher Klick zum Öffnen von Dateien und Ordnern",
|
||||
"themes": {
|
||||
"default": "Systemstandard",
|
||||
"dark": "Dunkel",
|
||||
"light": "Hell",
|
||||
"title": "Erscheinungsbild"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"cancel": "Ακύρωση",
|
||||
"clear": "Καθαρισμός",
|
||||
"close": "Κλείσιμο",
|
||||
"continue": "Continue",
|
||||
"copy": "Αντιγραφή",
|
||||
"copyFile": "Αντιγραφή αρχείου",
|
||||
"copyToClipboard": "Αντιγραφή στο πρόχειρο",
|
||||
@@ -12,6 +13,7 @@
|
||||
"download": "Λήψη",
|
||||
"file": "Αρχείο",
|
||||
"folder": "Φάκελος",
|
||||
"fullScreen": "Toggle full screen",
|
||||
"hideDotfiles": "Απόκρυψη κρυφών αρχείων",
|
||||
"info": "Πληροφορίες",
|
||||
"more": "Περισσότερα",
|
||||
@@ -22,6 +24,7 @@
|
||||
"ok": "Εντάξει",
|
||||
"permalink": "Λήψη μόνιμου συνδέσμου",
|
||||
"previous": "Προηγούμενο",
|
||||
"preview": "Preview",
|
||||
"publish": "Δημοσίευση",
|
||||
"rename": "Μετονομασία",
|
||||
"replace": "Αντικατάσταση",
|
||||
@@ -32,12 +35,14 @@
|
||||
"select": "Επιλογή",
|
||||
"selectMultiple": "Επιλογή πολλαπλών",
|
||||
"share": "Κοινοποίηση",
|
||||
"shell": "Toggle shell",
|
||||
"submit": "Υποβολή",
|
||||
"switchView": "Εναλλαγή προβολής",
|
||||
"toggleSidebar": "(Απ-)ενεργοποίησης της πλευρικής μπάρας",
|
||||
"update": "Ενημέρωση",
|
||||
"upload": "Μεταφόρτωση",
|
||||
"openFile": "Άνοιγμα αρχείου"
|
||||
"openFile": "Άνοιγμα αρχείου",
|
||||
"discardChanges": "Discard"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Λήψη αρχείου",
|
||||
@@ -101,9 +106,11 @@
|
||||
"prompts": {
|
||||
"copy": "Αντιγραφή",
|
||||
"copyMessage": "Επιλέξτε τοποθεσία για αντιγραφή των αρχείων σας:",
|
||||
"currentlyNavigating": "Currently navigating on:",
|
||||
"deleteMessageMultiple": "Είστε σίγουροι ότι θέλετε να διαγράψετε {count} αρχεία;",
|
||||
"deleteMessageSingle": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το αρχείο/φάκελο;",
|
||||
"deleteMessageShare": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτή την κοινοποίηση ({path});",
|
||||
"deleteUser": "Are you sure you want to delete this user?",
|
||||
"deleteTitle": "Διαγραφή αρχείων",
|
||||
"displayName": "Εμφάνιση ονόματος:",
|
||||
"download": "Λήψη αρχείων",
|
||||
@@ -132,7 +139,9 @@
|
||||
"upload": "Μεταφόρτωση",
|
||||
"uploadFiles": "Μεταφόρτωση {files} αρχείων…",
|
||||
"uploadMessage": "Επιλέξτε μια επιλογή για τη μεταφόρτωση.",
|
||||
"optionalPassword": "Προαιρετικός κωδικός πρόσβασης"
|
||||
"optionalPassword": "Προαιρετικός κωδικός πρόσβασης",
|
||||
"resolution": "Resolution",
|
||||
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Εικόνες",
|
||||
@@ -161,6 +170,7 @@
|
||||
"commandRunnerHelp": "Εδώ μπορείτε να ορίσετε εντολές που εκτελούνται στα ονομασμένα γεγονότα και δραστηριότητες. Πρέπει να γράψετε μία εντολή ανά γραμμή. Οι μεταβλητές περιβάλλοντος {0} και {1} θα είναι διαθέσιμες, και θα είναι {0} σχετικές με το {1}. Για περισσότερες πληροφορίες σχετικά με αυτή τη λειτουργία και τις διαθέσιμες μεταβλητές περιβάλλοντος, παρακαλώ διαβάστε το {2}.",
|
||||
"commandsUpdated": "Οι εντολές ενημερώθηκαν!",
|
||||
"createUserDir": "Αυτόματη δημιουργία φακέλου χρήστη κατά την προσθήκη νέου χρήστη",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "Τμηματικές μεταφορές αρχείων",
|
||||
"tusUploadsHelp": "Η εφαρμογή File Browser υποστηρίζει τμηματικές μεταφορτώσεις αρχείων, επιτρέποντας την αποδοτική, αξιόπιστη και συνεχιζόμενη μεταφόρτωση αρχείων ακόμα και σε ασταθείς συνδέσεις δικτύου.",
|
||||
"tusUploadsChunkSize": "Υποδεικνύει το μέγιστο μέγεθος ενός αιτήματος μεταφόρτωσης (για μικρότερες μεταφορές αρχείων θα χρησιμοποιηθούν απευθείας και όχι τμηματικές μεταφορτώσεις). Μπορείτε να εισάγετε έναν ακέραιο αριθμό που υποδηλώνει το μέγεθος σε bytes, ή κείμενο με αριθμό και μονάδα μέτρησης μεγέθους δεδομένων, όπως 10MB, 1GB κλπ.",
|
||||
@@ -214,6 +224,7 @@
|
||||
"shareDeleted": "Η κοινοποίηση διαγράφηκε!",
|
||||
"singleClick": "Χρήση μονού κλικ για να ανοίξετε αρχεία και φακέλους",
|
||||
"themes": {
|
||||
"default": "System default",
|
||||
"dark": "Σκοτεινό",
|
||||
"light": "Φωτεινό",
|
||||
"title": "Μοτίβο"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"ok": "OK",
|
||||
"permalink": "Get Permanent Link",
|
||||
"previous": "Previous",
|
||||
"preview": "Preview",
|
||||
"publish": "Publish",
|
||||
"rename": "Rename",
|
||||
"replace": "Replace",
|
||||
@@ -169,6 +170,7 @@
|
||||
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
||||
"commandsUpdated": "Commands updated!",
|
||||
"createUserDir": "Auto create user home dir while adding new user",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "Chunked Uploads",
|
||||
"tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.",
|
||||
"tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.",
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
"copy": "Copiar",
|
||||
"copyFile": "Copiar archivo",
|
||||
"copyToClipboard": "Copiar al portapapeles",
|
||||
"copyDownloadLinkToClipboard": "Copy download link to clipboard",
|
||||
"create": "Crear",
|
||||
"delete": "Borrar",
|
||||
"download": "Descargar",
|
||||
"file": "Archivo",
|
||||
"folder": "Carpeta",
|
||||
"fullScreen": "Toggle full screen",
|
||||
"hideDotfiles": "Ocultar archivos empezados por punto",
|
||||
"info": "Info",
|
||||
"more": "Más",
|
||||
@@ -22,6 +24,7 @@
|
||||
"ok": "OK",
|
||||
"permalink": "Link permanente",
|
||||
"previous": "Anterior",
|
||||
"preview": "Preview",
|
||||
"publish": "Publicar",
|
||||
"rename": "Renombrar",
|
||||
"replace": "Reemplazar",
|
||||
@@ -38,13 +41,17 @@
|
||||
"toggleSidebar": "Mostrar/Ocultar menú",
|
||||
"update": "Actualizar",
|
||||
"upload": "Subir",
|
||||
"openFile": "Abrir archivo"
|
||||
"openFile": "Abrir archivo",
|
||||
"discardChanges": "Discard"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Descargar fichero",
|
||||
"downloadFolder": "Descargar directorio",
|
||||
"downloadSelected": "Descargar seleccionados"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Are you sure you wish to abort?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "No tienes los permisos necesarios para acceder.",
|
||||
"internal": "La verdad es que algo ha ido mal.",
|
||||
@@ -103,6 +110,7 @@
|
||||
"deleteMessageMultiple": "¿Estás seguro que quieres eliminar {count} archivo(s)?",
|
||||
"deleteMessageSingle": "¿Estás seguro que quieres eliminar este archivo/carpeta?",
|
||||
"deleteMessageShare": "¿Está seguro de que quiere eliminar este recurso compartido({path})?",
|
||||
"deleteUser": "Are you sure you want to delete this user?",
|
||||
"deleteTitle": "Borrar archivos",
|
||||
"displayName": "Nombre:",
|
||||
"download": "Descargar archivos",
|
||||
@@ -131,7 +139,9 @@
|
||||
"upload": "Subir",
|
||||
"uploadFiles": "Subiendo {files} archivos...",
|
||||
"uploadMessage": "Seleccione una opción para subir.",
|
||||
"optionalPassword": "Contraseña opcional"
|
||||
"optionalPassword": "Contraseña opcional",
|
||||
"resolution": "Resolution",
|
||||
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Imágenes",
|
||||
@@ -160,6 +170,11 @@
|
||||
"commandRunnerHelp": "Aquí puede establecer los comandos que se ejecutan en los eventos nombrados. Debe escribir uno por línea. Las variables de entorno {0} y {1} estarán disponibles, siendo {0} relativa a {1}. Para más información sobre esta característica y las variables de entorno disponibles, por favor lea el {2}.",
|
||||
"commandsUpdated": "¡Comandos actualizados!",
|
||||
"createUserDir": "Crea automaticamente una carpeta de inicio cuando se agrega un usuario",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "Chunked Uploads",
|
||||
"tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.",
|
||||
"tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.",
|
||||
"tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.",
|
||||
"userHomeBasePath": "Ruta base para los directorios personales de los usuarios",
|
||||
"userScopeGenerationPlaceholder": "El ámbito se generará automáticamente",
|
||||
"createUserHomeDirectory": "Crear el directorio principal del usuario",
|
||||
@@ -173,7 +188,7 @@
|
||||
"executeOnShellDescription": "Por defecto, FileBrowser ejecuta los comandos llamando directamente a sus binarios. Si quieres ejecutarlos en un shell en su lugar (como Bash o PowerShell), puedes definirlo aquí con los argumentos y banderas (flags) necesarios. Si se define, el comando que se ejecuta se añadirá como argumento. Esto se aplica tanto a los comandos de usuario como a los ganchos de eventos.",
|
||||
"globalRules": "Se trata de un conjunto global de reglas de permiso y rechazo. Se aplican a todos los usuarios. Puedes definir reglas específicas en la configuración de cada usuario para anular estas.",
|
||||
"globalSettings": "Ajustes globales",
|
||||
"hideDotfiles": "",
|
||||
"hideDotfiles": "Ocultar archivos empezados por punto",
|
||||
"insertPath": "Introduce la ruta",
|
||||
"insertRegex": "Introducir expresión regular",
|
||||
"instanceName": "Nombre de la instancia",
|
||||
@@ -209,6 +224,7 @@
|
||||
"shareDeleted": "¡Recurso compartido eliminado!",
|
||||
"singleClick": "Utilice un solo clic para abrir archivos y directorios",
|
||||
"themes": {
|
||||
"default": "System default",
|
||||
"dark": "Oscuro",
|
||||
"light": "Claro",
|
||||
"title": "Tema"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user