Compare commits
26 Commits
v2.53.1
...
metadata-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4692ac2748 | ||
|
|
85c64667c1 | ||
|
|
a58f930d58 | ||
|
|
69b54f1ae8 | ||
|
|
ef70de2676 | ||
|
|
1053aace8c | ||
|
|
004488c15b | ||
|
|
3032a1fade | ||
|
|
87f1d00fd7 | ||
|
|
f0f2f1ff06 | ||
|
|
08c8ede587 | ||
|
|
1154b49974 | ||
|
|
785b7abb7b | ||
|
|
550a73b6ba | ||
|
|
e7ea1ad27d | ||
|
|
24781badd4 | ||
|
|
4094fb359b | ||
|
|
cfa6c5864e | ||
|
|
59ca0c340a | ||
|
|
037e29a708 | ||
|
|
fda8a99292 | ||
|
|
208535a8cc | ||
|
|
464b581953 | ||
|
|
20312ff18e | ||
|
|
219582c0b0 | ||
|
|
4fd18a382c |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -37,3 +37,12 @@ build/
|
||||
|
||||
default.nix
|
||||
Dockerfile.dev
|
||||
filebrowser.log
|
||||
filebrowser.pid
|
||||
frontend-dev.log
|
||||
frontend.pid
|
||||
SWAG.mp3
|
||||
test/M5.flac
|
||||
test/MALIBU.flac
|
||||
test/SWAG.mp3
|
||||
test
|
||||
|
||||
@@ -17,6 +17,7 @@ builds:
|
||||
- linux
|
||||
- windows
|
||||
- freebsd
|
||||
- openbsd
|
||||
goarch:
|
||||
- amd64
|
||||
- "386"
|
||||
@@ -30,6 +31,12 @@ builds:
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: "386"
|
||||
# Experimental, may not work properly
|
||||
- goos: openbsd
|
||||
goarch: riscv64
|
||||
# Broken as of Go 1.24, deprecated as of Go 1.26
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
|
||||
|
||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -2,6 +2,49 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
||||
|
||||
## [2.56.0](https://github.com/filebrowser/filebrowser/compare/v2.55.0...v2.56.0) (2026-01-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Updates for project File Browser ([#5698](https://github.com/filebrowser/filebrowser/issues/5698)) ([f0f2f1f](https://github.com/filebrowser/filebrowser/commit/f0f2f1ff069aae566d8bf25ec275da59f29a96bc))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adjust columns of the table from the "users ls" command ([#5716](https://github.com/filebrowser/filebrowser/issues/5716)) ([3032a1f](https://github.com/filebrowser/filebrowser/commit/3032a1fade43737c51c49b5ccda34f336394c2ed))
|
||||
* avoid clearing selection when clicking elements outside the empty area ([#5715](https://github.com/filebrowser/filebrowser/issues/5715)) ([004488c](https://github.com/filebrowser/filebrowser/commit/004488c15b3c30784e1ea564b3ca9feec7bcad08))
|
||||
|
||||
## [2.55.0](https://github.com/filebrowser/filebrowser/compare/v2.54.0...v2.55.0) (2026-01-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added cut, copy, paste and show command palette functions in header ([#5648](https://github.com/filebrowser/filebrowser/issues/5648)) ([785b7ab](https://github.com/filebrowser/filebrowser/commit/785b7abb7ba7a86cc0deae1052c319ff714c222c))
|
||||
* update translations ([#5677](https://github.com/filebrowser/filebrowser/issues/5677)) ([e7ea1ad](https://github.com/filebrowser/filebrowser/commit/e7ea1ad27d3d17e249489d3338be40bfea15e2a1))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent context menu clicks from clearing file selection ([#5681](https://github.com/filebrowser/filebrowser/issues/5681)) ([59ca0c3](https://github.com/filebrowser/filebrowser/commit/59ca0c340afc7774747c70ede9a5a5a3c9349d6b))
|
||||
* request current password when deleting users ([#5667](https://github.com/filebrowser/filebrowser/issues/5667)) ([cfa6c58](https://github.com/filebrowser/filebrowser/commit/cfa6c5864e5e7673aa9f3180e4964e0db92cc4da))
|
||||
* retain file selection when closing the editor ([#5693](https://github.com/filebrowser/filebrowser/issues/5693)) ([4094fb3](https://github.com/filebrowser/filebrowser/commit/4094fb359babac70e88d0ed4bfe3bd100744aad6))
|
||||
|
||||
## [2.54.0](https://github.com/filebrowser/filebrowser/compare/v2.53.1...v2.54.0) (2026-01-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add "redirect after copy/move" user setting ([#5662](https://github.com/filebrowser/filebrowser/issues/5662)) ([fda8a99](https://github.com/filebrowser/filebrowser/commit/fda8a992929b1466e75fb2813f2c4e293c12d244))
|
||||
* force file sync while uploading file ([#5668](https://github.com/filebrowser/filebrowser/issues/5668)) ([4fd18a3](https://github.com/filebrowser/filebrowser/commit/4fd18a382c31bbe7059d6733ffa371e70051865b))
|
||||
* update translations ([#5659](https://github.com/filebrowser/filebrowser/issues/5659)) ([464b581](https://github.com/filebrowser/filebrowser/commit/464b581953139c17e3276b774e381e4052827125))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear selection by clicking on empty area ([#5663](https://github.com/filebrowser/filebrowser/issues/5663)) ([208535a](https://github.com/filebrowser/filebrowser/commit/208535a8cc23254de0013dfab9008486707ee6c2))
|
||||
* hide "change password form" in noauth setting ([#5652](https://github.com/filebrowser/filebrowser/issues/5652)) ([219582c](https://github.com/filebrowser/filebrowser/commit/219582c0b03fd90979b1d1398dba7919d086a23f))
|
||||
|
||||
## [2.53.1](https://github.com/filebrowser/filebrowser/compare/v2.53.0...v2.53.1) (2026-01-03)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM ghcr.io/linuxserver/baseimage-alpine:3.23
|
||||
|
||||
RUN apk update && \
|
||||
apk --no-cache add ca-certificates mailcap jq libcap
|
||||
apk --no-cache add ca-certificates mailcap jq libcap ffmpeg
|
||||
|
||||
# Make user and create necessary directories
|
||||
RUN mkdir -p /config /database /srv && \
|
||||
|
||||
@@ -28,3 +28,4 @@ Contributions are always welcome. To start contributing to this project, read ou
|
||||
## License
|
||||
|
||||
[Apache License 2.0](LICENSE) © File Browser Contributors
|
||||
# Work in progress: metadata modifier
|
||||
|
||||
37
auth/hook.go
37
auth/hook.go
@@ -158,16 +158,17 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
|
||||
// create user with the provided credentials
|
||||
d := &users.User{
|
||||
Username: a.Cred.Username,
|
||||
Password: pass,
|
||||
Scope: a.Settings.Defaults.Scope,
|
||||
Locale: a.Settings.Defaults.Locale,
|
||||
ViewMode: a.Settings.Defaults.ViewMode,
|
||||
SingleClick: a.Settings.Defaults.SingleClick,
|
||||
Sorting: a.Settings.Defaults.Sorting,
|
||||
Perm: a.Settings.Defaults.Perm,
|
||||
Commands: a.Settings.Defaults.Commands,
|
||||
HideDotfiles: a.Settings.Defaults.HideDotfiles,
|
||||
Username: a.Cred.Username,
|
||||
Password: pass,
|
||||
Scope: a.Settings.Defaults.Scope,
|
||||
Locale: a.Settings.Defaults.Locale,
|
||||
ViewMode: a.Settings.Defaults.ViewMode,
|
||||
SingleClick: a.Settings.Defaults.SingleClick,
|
||||
RedirectAfterCopyMove: a.Settings.Defaults.RedirectAfterCopyMove,
|
||||
Sorting: a.Settings.Defaults.Sorting,
|
||||
Perm: a.Settings.Defaults.Perm,
|
||||
Commands: a.Settings.Defaults.Commands,
|
||||
HideDotfiles: a.Settings.Defaults.HideDotfiles,
|
||||
}
|
||||
u = a.GetUser(d)
|
||||
|
||||
@@ -219,13 +220,14 @@ func (a *HookAuth) GetUser(d *users.User) *users.User {
|
||||
Download: isAdmin || a.Fields.GetBoolean("user.perm.download", d.Perm.Download),
|
||||
}
|
||||
user := users.User{
|
||||
ID: d.ID,
|
||||
Username: d.Username,
|
||||
Password: d.Password,
|
||||
Scope: a.Fields.GetString("user.scope", d.Scope),
|
||||
Locale: a.Fields.GetString("user.locale", d.Locale),
|
||||
ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
|
||||
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
|
||||
ID: d.ID,
|
||||
Username: d.Username,
|
||||
Password: d.Password,
|
||||
Scope: a.Fields.GetString("user.scope", d.Scope),
|
||||
Locale: a.Fields.GetString("user.locale", d.Locale),
|
||||
ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
|
||||
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
|
||||
RedirectAfterCopyMove: a.Fields.GetBoolean("user.redirectAfterCopyMove", d.RedirectAfterCopyMove),
|
||||
Sorting: files.Sorting{
|
||||
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
|
||||
By: a.Fields.GetString("user.sorting.by", d.Sorting.By),
|
||||
@@ -251,6 +253,7 @@ var validHookFields = []string{
|
||||
"user.locale",
|
||||
"user.viewMode",
|
||||
"user.singleClick",
|
||||
"user.redirectAfterCopyMove",
|
||||
"user.sorting.by",
|
||||
"user.sorting.asc",
|
||||
"user.commands",
|
||||
|
||||
16
auth/json.go
16
auth/json.go
@@ -14,6 +14,10 @@ import (
|
||||
// MethodJSONAuth is used to identify json auth.
|
||||
const MethodJSONAuth settings.AuthMethod = "json"
|
||||
|
||||
// dummyHash is used to prevent user enumeration timing attacks.
|
||||
// It MUST be a valid bcrypt hash.
|
||||
const dummyHash = "$2a$10$O4mEMeOL/nit6zqe.WQXauLRbRlzb3IgLHsa26Pf0N/GiU9b.wK1m"
|
||||
|
||||
type jsonCred struct {
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
@@ -52,7 +56,17 @@ func (a JSONAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, s
|
||||
}
|
||||
|
||||
u, err := usr.Get(srv.Root, cred.Username)
|
||||
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
|
||||
|
||||
hash := dummyHash
|
||||
if err == nil {
|
||||
hash = u.Password
|
||||
}
|
||||
|
||||
if !users.CheckPwd(cred.Password, hash) {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ func getProxyAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (a
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if header == "" && defaultAuther != nil {
|
||||
if header == "" && defaultAuther != nil {
|
||||
header = defaultAuther["header"].(string)
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
|
||||
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
||||
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
||||
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
|
||||
fmt.Fprintf(w, "\tRedirect after Copy/Move:\t%t\n", set.Defaults.RedirectAfterCopyMove)
|
||||
fmt.Fprintf(w, "\tFile Creation Mode:\t%O\n", set.FileMode)
|
||||
fmt.Fprintf(w, "\tDirectory Creation Mode:\t%O\n", set.DirMode)
|
||||
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
|
||||
|
||||
@@ -393,10 +393,11 @@ func quickSetup(v *viper.Viper, s *storage.Storage) error {
|
||||
MinimumPasswordLength: settings.DefaultMinimumPasswordLength,
|
||||
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
SingleClick: false,
|
||||
AceEditorTheme: v.GetString("defaults.aceEditorTheme"),
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
SingleClick: false,
|
||||
RedirectAfterCopyMove: true,
|
||||
AceEditorTheme: v.GetString("defaults.aceEditorTheme"),
|
||||
Perm: users.Permissions{
|
||||
Admin: false,
|
||||
Execute: true,
|
||||
|
||||
@@ -27,16 +27,17 @@ var usersCmd = &cobra.Command{
|
||||
|
||||
func printUsers(usrs []*users.User) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tRed. After C/M\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||
|
||||
for _, u := range usrs {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||
u.ID,
|
||||
u.Username,
|
||||
u.Scope,
|
||||
u.Locale,
|
||||
u.ViewMode,
|
||||
u.SingleClick,
|
||||
u.RedirectAfterCopyMove,
|
||||
u.Perm.Admin,
|
||||
u.Perm.Execute,
|
||||
u.Perm.Create,
|
||||
@@ -77,6 +78,7 @@ func addUserFlags(flags *pflag.FlagSet) {
|
||||
flags.String("locale", "en", "locale for users")
|
||||
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
||||
flags.Bool("singleClick", false, "use single clicks only")
|
||||
flags.Bool("redirectAfterCopyMove", false, "redirect to destination after copy/move")
|
||||
flags.Bool("dateFormat", false, "use date format (true for absolute time, false for relative)")
|
||||
flags.Bool("hideDotfiles", false, "hide dotfiles")
|
||||
flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users")
|
||||
@@ -110,6 +112,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
|
||||
defaults.ViewMode, err = getAndParseViewMode(flags)
|
||||
case "singleClick":
|
||||
defaults.SingleClick, err = flags.GetBool(flag.Name)
|
||||
case "redirectAfterCopyMove":
|
||||
defaults.RedirectAfterCopyMove, err = flags.GetBool(flag.Name)
|
||||
case "aceEditorTheme":
|
||||
defaults.AceEditorTheme, err = flags.GetString(flag.Name)
|
||||
case "perm.admin":
|
||||
|
||||
@@ -52,13 +52,14 @@ options you want to change.`,
|
||||
}
|
||||
|
||||
defaults := settings.UserDefaults{
|
||||
Scope: user.Scope,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
Perm: user.Perm,
|
||||
Sorting: user.Sorting,
|
||||
Commands: user.Commands,
|
||||
Scope: user.Scope,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
RedirectAfterCopyMove: user.RedirectAfterCopyMove,
|
||||
Perm: user.Perm,
|
||||
Sorting: user.Sorting,
|
||||
Commands: user.Commands,
|
||||
}
|
||||
|
||||
err = getUserDefaults(flags, &defaults, false)
|
||||
@@ -70,6 +71,7 @@ options you want to change.`,
|
||||
user.Locale = defaults.Locale
|
||||
user.ViewMode = defaults.ViewMode
|
||||
user.SingleClick = defaults.SingleClick
|
||||
user.RedirectAfterCopyMove = defaults.RedirectAfterCopyMove
|
||||
user.Perm = defaults.Perm
|
||||
user.Commands = defaults.Commands
|
||||
user.Sorting = defaults.Sorting
|
||||
|
||||
@@ -35,22 +35,24 @@ var (
|
||||
// FileInfo describes a file.
|
||||
type FileInfo struct {
|
||||
*Listing
|
||||
Fs afero.Fs `json:"-"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
Extension string `json:"extension"`
|
||||
ModTime time.Time `json:"modified"`
|
||||
Mode os.FileMode `json:"mode"`
|
||||
IsDir bool `json:"isDir"`
|
||||
IsSymlink bool `json:"isSymlink"`
|
||||
Type string `json:"type"`
|
||||
Subtitles []string `json:"subtitles,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Checksums map[string]string `json:"checksums,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
currentDir []os.FileInfo `json:"-"`
|
||||
Resolution *ImageResolution `json:"resolution,omitempty"`
|
||||
Fs afero.Fs `json:"-"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
Extension string `json:"extension"`
|
||||
ModTime time.Time `json:"modified"`
|
||||
Mode os.FileMode `json:"mode"`
|
||||
IsDir bool `json:"isDir"`
|
||||
IsSymlink bool `json:"isSymlink"`
|
||||
Type string `json:"type"`
|
||||
Subtitles []string `json:"subtitles,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Checksums map[string]string `json:"checksums,omitempty"`
|
||||
// Tags holds audio metadata (ID3, VorbisComment, MP4 tags, ...)
|
||||
Tags map[string]interface{} `json:"tags,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
currentDir []os.FileInfo `json:"-"`
|
||||
Resolution *ImageResolution `json:"resolution,omitempty"`
|
||||
}
|
||||
|
||||
// FileOptions are the options when getting a file info.
|
||||
|
||||
100
files/tags.go
Normal file
100
files/tags.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/dhowden/tag"
|
||||
)
|
||||
|
||||
// ReadAudioTags extracts common audio metadata from the file and stores it in
|
||||
// the FileInfo.Tags map. It attempts to extract common fields and includes
|
||||
// embedded picture(s) as base64 where present.
|
||||
func (i *FileInfo) ReadAudioTags() error {
|
||||
if i.IsDir {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := i.Fs.Open(i.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
m, err := tag.ReadFrom(f)
|
||||
if err != nil {
|
||||
// don't fail hard; log and return nil so callers still get file info
|
||||
log.Printf("ReadAudioTags: failed to read tags for %s: %v", i.Path, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
tags := map[string]interface{}{}
|
||||
|
||||
if v := m.Title(); v != "" {
|
||||
tags["title"] = v
|
||||
}
|
||||
if v := m.Album(); v != "" {
|
||||
tags["album"] = v
|
||||
}
|
||||
if v := m.Artist(); v != "" {
|
||||
tags["artist"] = v
|
||||
}
|
||||
if v := m.AlbumArtist(); v != "" {
|
||||
tags["albumartist"] = v
|
||||
}
|
||||
if v := m.Composer(); v != "" {
|
||||
tags["composer"] = v
|
||||
}
|
||||
if v := m.Year(); v != 0 {
|
||||
tags["year"] = v
|
||||
}
|
||||
if t, _ := m.Track(); t > 0 {
|
||||
tags["track"] = t
|
||||
}
|
||||
if dnum, _ := m.Disc(); dnum > 0 {
|
||||
tags["disc"] = dnum
|
||||
}
|
||||
if v := m.Genre(); v != "" {
|
||||
tags["genre"] = v
|
||||
}
|
||||
|
||||
// Pictures: encode as data URI (base64) so frontend can preview if needed.
|
||||
if pic := m.Picture(); pic != nil {
|
||||
// safe encode image bytes as base64
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, bytes.NewReader(pic.Data)); err == nil {
|
||||
b64 := base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||
dataURI := "data:" + pic.MIMEType + ";base64," + b64
|
||||
tags["picture"] = map[string]interface{}{
|
||||
"mime": pic.MIMEType,
|
||||
"data": dataURI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keep raw metadata map if available (some formats expose additional fields)
|
||||
if raw := m.Raw(); raw != nil {
|
||||
for k, v := range raw {
|
||||
// Skip raw APIC entries (attached picture frame) to avoid
|
||||
// exposing large binary blobs. We already expose a friendly
|
||||
// `picture` key above when a picture exists.
|
||||
if strings.EqualFold(k, "APIC") {
|
||||
continue
|
||||
}
|
||||
// avoid overwriting already set common fields
|
||||
if _, ok := tags[k]; !ok {
|
||||
tags[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attach tags map
|
||||
if len(tags) > 0 {
|
||||
i.Tags = tags
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
7
files/write_mp3.go
Normal file
7
files/write_mp3.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package files
|
||||
|
||||
// This file is a placeholder to avoid accidental module resolution for
|
||||
// non-implemented MP3 metadata writers. The actual implementation is not
|
||||
// required at runtime, and we should not import external packages here.
|
||||
|
||||
// Intentionally left blank.
|
||||
7924
frontend/package-lock.json
generated
Normal file
7924
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -71,5 +71,5 @@
|
||||
"vite-plugin-compression2": "^2.3.1",
|
||||
"vue-tsc": "^3.1.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
|
||||
"packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316"
|
||||
}
|
||||
|
||||
713
frontend/pnpm-lock.yaml
generated
713
frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -188,6 +188,27 @@ export async function checksum(url: string, algo: ChecksumAlg) {
|
||||
return (await data.json()).checksums[algo];
|
||||
}
|
||||
|
||||
export async function metadata(url: string) {
|
||||
// Fetch metadata for a resource. Backend support is required for this to work.
|
||||
const res = await resourceAction(`${url}?metadata=1`, "GET");
|
||||
try {
|
||||
const data = await res.json();
|
||||
// backend returns a FileInfo object; prefer returning the audio tags map when present
|
||||
if (data && typeof data === "object" && data.tags) {
|
||||
return data.tags;
|
||||
}
|
||||
// fallback: if server returned just the tags map or other structure
|
||||
return data;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateMetadata(url: string, content: any) {
|
||||
// Update metadata for a resource. Backend must support PATCH with action=metadata.
|
||||
return resourceAction(`${url}?action=metadata`, "PATCH", JSON.stringify(content));
|
||||
}
|
||||
|
||||
export function getDownloadURL(file: ResourceItem, inline: any) {
|
||||
const params = {
|
||||
...(inline && { inline: "true" }),
|
||||
|
||||
@@ -42,8 +42,14 @@ export async function update(
|
||||
});
|
||||
}
|
||||
|
||||
export async function remove(id: number) {
|
||||
export async function remove(
|
||||
id: number,
|
||||
currentPassword: string | null = null
|
||||
) {
|
||||
await fetchURL(`/api/users/${id}`, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({
|
||||
...(currentPassword != null ? { current_password: currentPassword } : {}),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({ path: this.dest });
|
||||
if (this.user.redirectAfterCopyMove)
|
||||
this.$router.push({ path: this.dest });
|
||||
})
|
||||
.catch((e) => {
|
||||
buttons.done("copy");
|
||||
|
||||
552
frontend/src/components/prompts/ModifyMetadata.vue
Normal file
552
frontend/src/components/prompts/ModifyMetadata.vue
Normal file
@@ -0,0 +1,552 @@
|
||||
<template>
|
||||
<div class="card floating metadata-card">
|
||||
<div class="card-title title-with-actions">
|
||||
<h2>{{ trans('files.metadata','Metadata') }}</h2>
|
||||
<div class="title-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="button button--flat"
|
||||
@click="toggleAddField"
|
||||
:aria-label="trans('buttons.addField','Add field')"
|
||||
:title="trans('buttons.addField','Add field')"
|
||||
>
|
||||
{{ trans('buttons.addField','Add field') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button button--primary"
|
||||
@click.prevent="applyAll"
|
||||
:aria-label="trans('buttons.apply','Apply')"
|
||||
:title="trans('buttons.apply','Apply')"
|
||||
>
|
||||
{{ trans('buttons.apply','Apply') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<p v-if="selectedCount > 1">
|
||||
{{ $t('prompts.filesSelected', { count: selectedCount }) }}
|
||||
</p>
|
||||
|
||||
<template v-if="selectedCount === 0">
|
||||
<p>{{ $t('prompts.noFileSelected') }}</p>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div v-if="addFieldVisible" class="add-field-row">
|
||||
<div class="add-field-controls">
|
||||
<input
|
||||
v-model="addFieldKey"
|
||||
type="text"
|
||||
:placeholder="trans('prompts.newFieldName','Field name')"
|
||||
/>
|
||||
<input
|
||||
v-model="addFieldValue"
|
||||
type="text"
|
||||
:placeholder="trans('prompts.newFieldValue','Value')"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="button button--primary"
|
||||
@click="confirmAddField"
|
||||
:aria-label="trans('buttons.add','Add')"
|
||||
:title="trans('buttons.add','Add')"
|
||||
>
|
||||
{{ trans('buttons.add','Add') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button button--flat"
|
||||
@click="cancelAddField"
|
||||
>
|
||||
{{ trans('buttons.cancel','Cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metadata-table-wrapper">
|
||||
<table class="metadata-table">
|
||||
<colgroup>
|
||||
<col class="col-label" />
|
||||
<col class="col-current" />
|
||||
<col class="col-new" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="hdr-field">{{ trans('prompts.field','Field') }}</th>
|
||||
<th class="hdr-current">{{ trans('prompts.current','Current') }}</th>
|
||||
<th class="hdr-new">{{ trans('prompts.new','New') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="field in fields" :key="field" class="metadata-row">
|
||||
<td class="metadata-title"><strong>{{ fieldLabels[field] || humanize(field) }}</strong></td>
|
||||
<td class="metadata-current">
|
||||
<template v-if="isPicture(field)">
|
||||
<img :src="pictureSrc(field)" alt="cover" class="cover-preview" v-if="pictureSrc(field)" />
|
||||
<span v-else class="metadata-muted">{{ trans('prompts.noCover','No cover') }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ displayCurrent(field) }}
|
||||
</template>
|
||||
</td>
|
||||
<td class="metadata-edit-cell">
|
||||
<input
|
||||
v-model="newValues[field]"
|
||||
:placeholder="placeholders[field] || ''"
|
||||
type="text"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="card-action">
|
||||
<button
|
||||
id="focus-prompt"
|
||||
type="button"
|
||||
@click="closeHovers"
|
||||
class="button button--flat"
|
||||
:aria-label="trans('buttons.ok','OK')"
|
||||
:title="trans('buttons.ok','OK')"
|
||||
>
|
||||
{{ trans('buttons.ok','OK') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="apply-metadata"
|
||||
type="button"
|
||||
@click.prevent="applyAll"
|
||||
class="button button--primary"
|
||||
:aria-label="trans('buttons.apply','Apply')"
|
||||
:title="trans('buttons.apply','Apply')"
|
||||
>
|
||||
{{ trans('buttons.apply','Apply') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from "pinia";
|
||||
import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { metadata as apiMetadata, updateMetadata } from "@/api/files";
|
||||
|
||||
export default {
|
||||
name: "modifyMetadata",
|
||||
inject: ["$showError"],
|
||||
data() {
|
||||
return {
|
||||
// fields will be derived dynamically from metadata across selected files
|
||||
fields: [],
|
||||
fieldLabels: {},
|
||||
placeholders: {},
|
||||
metadataList: [],
|
||||
newValues: {},
|
||||
// add field UI state
|
||||
addFieldVisible: false,
|
||||
addFieldKey: "",
|
||||
addFieldValue: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(useFileStore, ["req", "selected", "selectedCount"]),
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useLayoutStore, ["closeHovers"]),
|
||||
async mountedFetch() {
|
||||
if (!this.req) return;
|
||||
|
||||
const files = this.selected.map((i) => this.req.items[i].url);
|
||||
|
||||
// Fetch metadata for each selected file if possible
|
||||
try {
|
||||
const promises = files.map((u) => apiMetadata(u));
|
||||
this.metadataList = (await Promise.all(promises)).map((m) => m || {});
|
||||
} catch (e) {
|
||||
this.metadataList = [];
|
||||
}
|
||||
|
||||
// Build union of fields
|
||||
const keys = new Set();
|
||||
this.metadataList.forEach((m) => {
|
||||
Object.keys(m).forEach((k) => keys.add(k));
|
||||
});
|
||||
|
||||
// Ensure stable ordering: put common fields first
|
||||
const preferred = ["title", "artist", "album", "track", "genre", "date", "comment", "disc", "composer", "year", "albumartist", "picture", "cover"];
|
||||
const rest = Array.from(keys).filter((k) => !preferred.includes(k)).sort();
|
||||
this.fields = preferred.filter((k) => keys.has(k)).concat(rest);
|
||||
|
||||
// Setup field labels (use translation when available, otherwise humanize)
|
||||
this.fields.forEach((f) => {
|
||||
this.fieldLabels[f] = this.trans(`prompts.${f}`, this.humanize(f));
|
||||
this.newValues[f] = "";
|
||||
});
|
||||
},
|
||||
toggleAddField() {
|
||||
this.addFieldVisible = !this.addFieldVisible;
|
||||
if (this.addFieldVisible) {
|
||||
this.addFieldKey = "";
|
||||
this.addFieldValue = "";
|
||||
}
|
||||
},
|
||||
cancelAddField() {
|
||||
this.addFieldVisible = false;
|
||||
this.addFieldKey = "";
|
||||
this.addFieldValue = "";
|
||||
},
|
||||
confirmAddField() {
|
||||
const key = String(this.addFieldKey || "").trim();
|
||||
const val = String(this.addFieldValue || "").trim();
|
||||
if (!key) return;
|
||||
// If field doesn't exist yet, add it to the top for visibility
|
||||
if (!this.fields.includes(key)) {
|
||||
this.fields.unshift(key);
|
||||
this.fieldLabels[key] = this.trans(`prompts.${key}`, this.humanize(key));
|
||||
}
|
||||
// Initialize newValues entry and set initial value if provided
|
||||
if (!(key in this.newValues)) this.newValues[key] = "";
|
||||
if (val !== "") this.newValues[key] = val;
|
||||
this.cancelAddField();
|
||||
},
|
||||
displayCurrent(field) {
|
||||
if (!this.metadataList || this.metadataList.length === 0) return "";
|
||||
|
||||
const vals = this.metadataList.map((m) => {
|
||||
const v = m[field];
|
||||
if (v === undefined || v === null) return "";
|
||||
if (typeof v === "object") return JSON.stringify(v);
|
||||
return String(v);
|
||||
});
|
||||
|
||||
const nonEmpty = vals.filter((v) => v !== "");
|
||||
if (nonEmpty.length === 0) return "";
|
||||
|
||||
const allEqual = nonEmpty.every((v) => v === nonEmpty[0]);
|
||||
if (allEqual) return nonEmpty[0];
|
||||
|
||||
// Count how many distinct values
|
||||
const distinct = new Set(nonEmpty);
|
||||
// If fields are objects (e.g., picture) avoid returning huge JSON blobs.
|
||||
// Prefer a short summary.
|
||||
const sample = nonEmpty[0];
|
||||
if (typeof sample === 'string') {
|
||||
return this.trans('prompts.multipleValuesCount', `(different on ${distinct.size} files)`).replace('{count}', String(distinct.size));
|
||||
}
|
||||
|
||||
try {
|
||||
const s = JSON.stringify(sample);
|
||||
return s.length > 200 ? s.slice(0, 200) + '…' : s;
|
||||
} catch (e) {
|
||||
return this.trans('prompts.multipleValuesCount', `(different on ${distinct.size} files)`).replace('{count}', String(distinct.size));
|
||||
}
|
||||
},
|
||||
|
||||
isPicture(field) {
|
||||
if (!this.metadataList || this.metadataList.length === 0) return false;
|
||||
for (const m of this.metadataList) {
|
||||
const v = m[field];
|
||||
if (v && typeof v === 'object') {
|
||||
if (v.data && typeof v.data === 'string') return true;
|
||||
if (v.picture && v.picture.data) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
pictureSrc(field) {
|
||||
if (!this.metadataList) return null;
|
||||
for (const m of this.metadataList) {
|
||||
const v = m[field];
|
||||
if (v && typeof v === 'object') {
|
||||
if (v.data && typeof v.data === 'string') return v.data;
|
||||
if (v.picture && v.picture.data) return v.picture.data;
|
||||
// sometimes library stores a raw buffer as base64 directly in 'data'
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
trans(key, fallback) {
|
||||
// Fallback to a human readable string if translation key is missing
|
||||
try {
|
||||
if (this.$te && this.$te(key)) return this.$t(key);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return fallback;
|
||||
},
|
||||
|
||||
humanize(str) {
|
||||
if (!str) return str;
|
||||
// replace camelCase / snake_case / dots with spaces and capitalize
|
||||
const s = String(str)
|
||||
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
||||
.replace(/[_\.\-]+/g, " ");
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
},
|
||||
|
||||
async applyAll() {
|
||||
if (!this.req) return;
|
||||
|
||||
// collect changed fields
|
||||
const changes = {};
|
||||
Object.keys(this.newValues).forEach((k) => {
|
||||
const v = this.newValues[k];
|
||||
if (v !== undefined && v !== null && String(v).trim() !== "") {
|
||||
changes[k] = v;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(changes).length === 0) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
const files = this.selected.map((i) => this.req.items[i].url);
|
||||
|
||||
try {
|
||||
// apply changes to each file
|
||||
await Promise.all(
|
||||
files.map((u) => updateMetadata(u, changes))
|
||||
);
|
||||
// refresh listing
|
||||
const fileStore = useFileStore();
|
||||
fileStore.reload = true;
|
||||
this.closeHovers();
|
||||
} catch (e) {
|
||||
this.$showError(e);
|
||||
}
|
||||
},
|
||||
// per-field apply removed in favor of global applyAll
|
||||
},
|
||||
mounted() {
|
||||
this.mountedFetch();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.metadata-card {
|
||||
max-height: calc(100vh - 120px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
/* prefer a wider layout on large screens but stay responsive */
|
||||
/* increase target width to give more horizontal space */
|
||||
width: min(1400px, 98vw);
|
||||
max-width: 98vw;
|
||||
min-width: 680px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.title-with-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.title-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.add-field-row {
|
||||
padding: 0 1rem 0.5rem 1rem;
|
||||
}
|
||||
.add-field-controls {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.add-field-controls input {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
/* Override global small max-width for floating cards for this metadata modal */
|
||||
.card.floating.metadata-card {
|
||||
/* remove the global max-width:25em constraint */
|
||||
max-width: none !important;
|
||||
width: min(1400px, 98vw) !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
}
|
||||
.metadata-field {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.metadata-title {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
.metadata-current {
|
||||
color: var(--color-muted, #666);
|
||||
margin: 0.25rem 0 0.5rem 0;
|
||||
}
|
||||
.metadata-edit {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.metadata-edit input {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.metadata-table-wrapper {
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
padding: 0 1rem; /* add horizontal padding so left column isn't flush to modal edge */
|
||||
}
|
||||
.metadata-table {
|
||||
border-collapse: separate;
|
||||
width: auto; /* allow table to size to content */
|
||||
/* allow a comfortable minimum width for readable columns on very large screens
|
||||
but let it shrink responsively in smaller viewports */
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
table-layout: auto;
|
||||
border-spacing: 0;
|
||||
border: 1px solid rgba(0,0,0,0.08);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.metadata-table td, .metadata-table th { word-break: break-word; }
|
||||
.metadata-table th,
|
||||
.metadata-table td {
|
||||
border: none;
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* Header styling: subtle background and divider */
|
||||
.metadata-table thead {
|
||||
background: rgba(0,0,0,0.04);
|
||||
}
|
||||
.metadata-table thead th {
|
||||
border-bottom: 1px solid rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
/* extra left padding for the first column so labels don't touch the modal edge */
|
||||
.metadata-table td:first-child,
|
||||
.metadata-table th:first-child,
|
||||
.metadata-title {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
/* Use CSS Grid per row so columns adapt to content without one taking all space */
|
||||
.metadata-table thead tr,
|
||||
.metadata-table tbody tr {
|
||||
display: grid;
|
||||
/* Fix column widths to prevent jitter when a cell contains very long content.
|
||||
First column (labels) is fixed; current/new columns are flexible with a comfortable minimum. */
|
||||
grid-template-columns: 220px minmax(280px, 1fr) minmax(280px, 1fr);
|
||||
gap: 1rem;
|
||||
align-items: start;
|
||||
}
|
||||
.metadata-table thead tr {
|
||||
border-bottom: none;
|
||||
}
|
||||
.metadata-table thead th,
|
||||
.metadata-table tbody td {
|
||||
display: block; /* make cells behave as grid items */
|
||||
}
|
||||
.metadata-table thead th { font-weight: 600; }
|
||||
|
||||
/* column sizing helpers */
|
||||
.metadata-table .col-label { width: 1%; }
|
||||
.metadata-table .col-current { width: auto; }
|
||||
.metadata-table .col-new { width: auto; }
|
||||
.metadata-edit-cell input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(0,0,0,0.12);
|
||||
padding: 0.5rem 0.6rem;
|
||||
}
|
||||
|
||||
/* Ensure long labels wrap inside the first column without expanding it */
|
||||
.metadata-title strong {
|
||||
display: block;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* Row aesthetics: zebra striping and hover */
|
||||
.metadata-table tbody tr {
|
||||
border-top: 1px solid rgba(0,0,0,0.06);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.06);
|
||||
}
|
||||
.metadata-table tbody tr:nth-child(odd) {
|
||||
background: rgba(0,0,0,0.02);
|
||||
}
|
||||
.metadata-table tbody tr:hover {
|
||||
background: rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* Subtle vertical separators between columns */
|
||||
.metadata-table tbody td:not(:last-child) {
|
||||
border-right: 1px solid rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* On small screens, stack rows to improve readability */
|
||||
@media (max-width: 640px) {
|
||||
.metadata-table {
|
||||
min-width: 0;
|
||||
}
|
||||
.metadata-table thead {
|
||||
display: none;
|
||||
}
|
||||
.metadata-table tr {
|
||||
display: block;
|
||||
margin-bottom: 0.75rem;
|
||||
border: 1px solid rgba(0,0,0,0.08);
|
||||
padding: 0.75rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
|
||||
}
|
||||
.metadata-table td {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
.metadata-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
/* On medium screens allow a comfortable min width; on very large screens keep roomy layout */
|
||||
@media (min-width: 1200px) {
|
||||
.metadata-table {
|
||||
min-width: 100ch;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure table cells wrap content and images don't overflow */
|
||||
.metadata-table td, .metadata-table th {
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
hyphens: auto;
|
||||
}
|
||||
.metadata-table img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
.cover-preview {
|
||||
max-width: 160px;
|
||||
max-height: 160px;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.12);
|
||||
}
|
||||
.metadata-muted { color: var(--color-muted, #666); font-size: 0.9em; }
|
||||
.metadata-current-row td {
|
||||
color: var(--color-muted, #666);
|
||||
}
|
||||
.metadata-edit-row td {
|
||||
background: rgba(0,0,0,0.02);
|
||||
}
|
||||
</style>
|
||||
@@ -79,7 +79,7 @@ export default {
|
||||
computed: {
|
||||
...mapState(useFileStore, ["req", "selected"]),
|
||||
...mapState(useAuthStore, ["user"]),
|
||||
...mapWritableState(useFileStore, ["preselect"]),
|
||||
...mapWritableState(useFileStore, ["reload", "preselect"]),
|
||||
excludedFolders() {
|
||||
return this.selected
|
||||
.filter((idx) => this.req.items[idx].isDir)
|
||||
@@ -108,7 +108,9 @@ export default {
|
||||
.then(() => {
|
||||
buttons.success("move");
|
||||
this.preselect = removePrefix(items[0].to);
|
||||
this.$router.push({ path: this.dest });
|
||||
if (this.user.redirectAfterCopyMove)
|
||||
this.$router.push({ path: this.dest });
|
||||
else this.reload = true;
|
||||
})
|
||||
.catch((e) => {
|
||||
buttons.done("move");
|
||||
|
||||
@@ -25,6 +25,7 @@ import Share from "./Share.vue";
|
||||
import ShareDelete from "./ShareDelete.vue";
|
||||
import Upload from "./Upload.vue";
|
||||
import DiscardEditorChanges from "./DiscardEditorChanges.vue";
|
||||
import ModifyMetadata from "./ModifyMetadata.vue";
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
@@ -44,6 +45,7 @@ const components = new Map<string, any>([
|
||||
["replace-rename", ReplaceRename],
|
||||
["share", Share],
|
||||
["upload", Upload],
|
||||
["modifyMetadata", ModifyMetadata],
|
||||
["share-delete", ShareDelete],
|
||||
["deleteUser", DeleteUser],
|
||||
["discardEditorChanges", DiscardEditorChanges],
|
||||
|
||||
@@ -185,3 +185,7 @@ html[dir="rtl"] .breadcrumbs a {
|
||||
.vfm-modal {
|
||||
z-index: 9999999 !important;
|
||||
}
|
||||
|
||||
body > div[style*="z-index: 9990"] {
|
||||
z-index: 10000 !important;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"ok": "موافق",
|
||||
"permalink": "الحصول على رابط دائم",
|
||||
"previous": "السابق",
|
||||
"preview": "Preview",
|
||||
"preview": "معاينة",
|
||||
"publish": "نشر",
|
||||
"rename": "إعادة تسمية",
|
||||
"replace": "استبدال",
|
||||
@@ -43,11 +43,11 @@
|
||||
"upload": "رفع",
|
||||
"openFile": "فتح الملف",
|
||||
"discardChanges": "إلغاء التغييرات",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"stopSearch": "توقف عن البحث",
|
||||
"saveChanges": "حفظ التغييرات",
|
||||
"editAsText": "تعديل على شكل نص",
|
||||
"increaseFontSize": "زيادة حجم الخط",
|
||||
"decreaseFontSize": "تصغير حجم الخط"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "تحميل الملف",
|
||||
@@ -80,7 +80,7 @@
|
||||
"sortByName": "الترتيب باﻹسم",
|
||||
"sortBySize": "الترتيب بالحجم",
|
||||
"noPreview": "لا يوجد عرض مسبق لهذا الملف.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvTooLarge": "حجم الملف اكبر من (<5MB), يرجى تحميل الملف للمعاينة",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
@@ -138,7 +138,7 @@
|
||||
"filesSelected": "تم تحديد {count} ملفات.",
|
||||
"lastModified": "آخر تعديل",
|
||||
"move": "نقل",
|
||||
"moveMessage": "إختر مكان جديد للملفات أو المجلدات المراد نقلها:",
|
||||
"moveMessage": "اختر منزلاً جديداً لملفك (ملفاتك)/مجلدك (مجلداتك):",
|
||||
"newArchetype": "إنشاء منشور من المنشور اﻷصلي. الملف سيتم انشاءه في مجلد المحتويات.",
|
||||
"newDir": "مجلد جديد",
|
||||
"newDirMessage": "أدخل اسم المجلد الجديد.",
|
||||
@@ -189,15 +189,15 @@
|
||||
"commandRunner": "منفذ اﻷوامر",
|
||||
"commandRunnerHelp": "هنا بإمكانك تعيين اﻷوامر التي سيتم تنفيذها في اﻷحداث المسماة. يجب كتابة أمر واحد في كل سطر. ستكون المتغيرات البيئية (env) {0} و {1} متاحة، حيث {0} نسبي لـ {1}. لمزيد من المعلومات حول هذه الميزة و المتغيرات البيئية المتاحة، يرجى قراءة {2}.",
|
||||
"commandsUpdated": "تم تحديث اﻷوامر",
|
||||
"createUserDir": "إنشاء مجلد المستخدم (home) تلقائياً عند إنشاء مستخدم جديد",
|
||||
"createUserDir": "إنشاء مجلد المستخدم الرئيسي تلقائياً عند إنشاء مستخدم جديد",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "التحميلات المتقطعة",
|
||||
"tusUploadsHelp": "يدعم متصفح الملفات تحميل الملفات المتقطعة، مما يسمح بتحميلات الملفات بشكل فعال و موثوق و قابلة للمتابغة و متقطعة حتى على الشبكات غير الموثوقة.",
|
||||
"tusUploadsChunkSize": "يشير إلى الحد اﻷقصى لحجم الطلب (سيتم استخدام التحميل المباشر للتحميلات صغيرة الخحم). يمكنك إدخال عدد صحيح عادي يدل على الحجم بوحدة البايت أو نمظ مثل10MB, 1GB, إلخ.",
|
||||
"tusUploadsRetryCount": "عدد مرات إعادة المحاولة إذا فشلت عملية تحميل القطعة.",
|
||||
"userHomeBasePath": "المسار الرئيسي لمجلد المستخدم (home)",
|
||||
"userHomeBasePath": "المسار الرئيسي لمجلد المستخدم الرئيسي",
|
||||
"userScopeGenerationPlaceholder": "سيتم تعيين نطاق المستخدم تلقائياً",
|
||||
"createUserHomeDirectory": "إنشاء مجلد المستخدم (home)",
|
||||
"createUserHomeDirectory": "إنشاء مجلد المستخدم الرئيسي",
|
||||
"customStylesheet": "ستايل مخصص",
|
||||
"defaultUserDescription": "هذه اﻹعدادات اﻹفتراضية للمستخدمين الجدد.",
|
||||
"disableExternalLinks": "تعطيل الروابط الخارجية (بإسثناء الوثائق)",
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "الصلاحيات",
|
||||
"permissionsHelp": "يمكنك تعيين المستخدم كـ \"مدير\" أو تحديد الصلاحيات بشكل منفرد.\n إذا قمت بتحديد المستخدم كـ \"مدير\"، باقي الخيارات سيتم تحديدها تلقائياً.\n إدارة المستخدمين تبقى صلاحية فريدة للـ \"مدير\" فقط.\n",
|
||||
"profileSettings": "إعدادات الحساب",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "منع الوصول إلى الملفات التي تبدأ بنقطة مثل (.git، و .gitignore) في كل مجلد.\n",
|
||||
"ruleExample2": "منع الوصول إلى الملف المسمى Caddyfile في نطاق الجذر.",
|
||||
"rules": "المجموعات",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "إدارة المستخدمين",
|
||||
"userUpdated": "تم تعديل المستخدم",
|
||||
"username": "إسم المستخدم",
|
||||
"users": "المستخدمين"
|
||||
"users": "المستخدمين",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "مساعدة",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Разрешения",
|
||||
"permissionsHelp": "Можете да зададете потребител да бъде администратор или да изберете разрешения индивидуално. Ако изберете \"Администратор\" всички други опции ще бъдат автоматично отметнати. Управлението на потребителите е привилегия на администратор.\n",
|
||||
"profileSettings": "Настройки на Профила",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "предотвратете достъпа до всеки файл започващ с точка (като .git, .gitignore) във всяка папка.\n",
|
||||
"ruleExample2": "блокира достъпа до файл именуван Caddyfile поставен в началото за обхвата.",
|
||||
"rules": "Правила",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Управление на потребители",
|
||||
"userUpdated": "Потребителя е обновен!",
|
||||
"username": "Потребителско име",
|
||||
"users": "Потребители"
|
||||
"users": "Потребители",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Помощ",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"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",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"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",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Administració d'usuaris",
|
||||
"userUpdated": "Usuari actualitzat!",
|
||||
"username": "Usuari",
|
||||
"users": "Usuaris"
|
||||
"users": "Usuaris",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"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",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"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",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Správa uživatelů",
|
||||
"userUpdated": "Uživatel aktualizován!",
|
||||
"username": "Uživatelské jméno",
|
||||
"users": "Uživatelé"
|
||||
"users": "Uživatelé",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Nápověda",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Abbrechen",
|
||||
"clear": "Schließen",
|
||||
"clear": "Leeren",
|
||||
"close": "Schließen",
|
||||
"continue": "Fortfahren",
|
||||
"copy": "Kopieren",
|
||||
"copyFile": "Kopiere Datei",
|
||||
"copyToClipboard": "In Zwischenablage kopieren",
|
||||
"copyDownloadLinkToClipboard": "Download-Link in die Zwischenablage kopieren",
|
||||
"create": "Neu",
|
||||
"create": "Erstellen",
|
||||
"delete": "Löschen",
|
||||
"download": "Herunterladen",
|
||||
"file": "Datei",
|
||||
@@ -16,17 +16,17 @@
|
||||
"fullScreen": "Vollbildmodus umschalten",
|
||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||
"info": "Info",
|
||||
"more": "mehr",
|
||||
"more": "Mehr",
|
||||
"move": "Verschieben",
|
||||
"moveFile": "Verschiebe Datei",
|
||||
"new": "Neu",
|
||||
"next": "nächste",
|
||||
"next": "Nächste",
|
||||
"ok": "OK",
|
||||
"permalink": "permanenten Verweis anzeigen",
|
||||
"previous": "vorherige",
|
||||
"previous": "Vorherige",
|
||||
"preview": "Vorschau",
|
||||
"publish": "Veröffentlichen",
|
||||
"rename": "umbenennen",
|
||||
"rename": "Umbenennen",
|
||||
"replace": "Ersetzen",
|
||||
"reportIssue": "Fehler melden",
|
||||
"save": "Speichern",
|
||||
@@ -39,19 +39,19 @@
|
||||
"submit": "Absenden",
|
||||
"switchView": "Ansicht wechseln",
|
||||
"toggleSidebar": "Seitenleiste anzeigen",
|
||||
"update": "Update",
|
||||
"upload": "Upload",
|
||||
"update": "Aktualisieren",
|
||||
"upload": "Hochladen",
|
||||
"openFile": "Datei öffnen",
|
||||
"discardChanges": "Verwerfen",
|
||||
"stopSearch": "Stop searching",
|
||||
"stopSearch": "Suche abbrechen",
|
||||
"saveChanges": "Änderungen speichern",
|
||||
"editAsText": "Als Text bearbeiten",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"increaseFontSize": "Schriftgröße vergrößern",
|
||||
"decreaseFontSize": "Schriftgröße verkleinern"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Download Datei",
|
||||
"downloadFolder": "Download Ordner",
|
||||
"downloadFile": "Datei herunterladen",
|
||||
"downloadFolder": "Ordner herunterladen",
|
||||
"downloadSelected": "Auswahl herunterladen"
|
||||
},
|
||||
"upload": {
|
||||
@@ -64,12 +64,12 @@
|
||||
"connection": "Der Server ist nicht erreichbar."
|
||||
},
|
||||
"files": {
|
||||
"body": "Body",
|
||||
"body": "Inhalt",
|
||||
"closePreview": "Vorschau schließen",
|
||||
"files": "Dateien",
|
||||
"folders": "Ordner",
|
||||
"home": "Home",
|
||||
"lastModified": "zuletzt verändert",
|
||||
"home": "Startseite",
|
||||
"lastModified": "Zuletzt geändert",
|
||||
"loading": "Lade...",
|
||||
"lonely": "Hier scheint nichts zu sein...",
|
||||
"metadata": "Metadaten",
|
||||
@@ -82,12 +82,12 @@
|
||||
"noPreview": "Für diese Datei ist keine Vorschau verfügbar.",
|
||||
"csvTooLarge": "Die CSV-Datei ist zu groß für die Vorschau (>5 MB). Bitte herunterladen, um sie anzuzeigen.",
|
||||
"csvLoadFailed": "Fehler beim Laden der CSV-Datei.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"showingRows": "{count} Zeile(n) werden angezeigt",
|
||||
"columnSeparator": "Spaltentrennzeichen",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
"comma": "Komma (,)",
|
||||
"semicolon": "Semikolon (;)",
|
||||
"both": "Sowohl (,) als auch (;)"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -117,7 +117,7 @@
|
||||
"wrongCredentials": "Falsche Zugangsdaten",
|
||||
"passwordTooShort": "Passwort muss mindestens {min} Zeichen lang sein",
|
||||
"logout_reasons": {
|
||||
"inactivity": "Du wurdest aufgrund von Inaktivität abgemeldet."
|
||||
"inactivity": "Sie wurden aufgrund von Inaktivität abgemeldet."
|
||||
}
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
@@ -131,7 +131,7 @@
|
||||
"deleteUser": "Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?",
|
||||
"deleteTitle": "Lösche Dateien",
|
||||
"displayName": "Anzeigename:",
|
||||
"download": "Lade Dateien",
|
||||
"download": "Dateien herunterladen",
|
||||
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
|
||||
"error": "Etwas ist schiefgelaufen",
|
||||
"fileInfo": "Dateiinformation",
|
||||
@@ -149,14 +149,14 @@
|
||||
"rename": "Umbenennen",
|
||||
"renameMessage": "Fügen Sie einen Namen ein für",
|
||||
"replace": "Ersetzen",
|
||||
"replaceMessage": "Eine der Datei mit dem gleichen Namen, wie die Sie hochladen wollen, existiert bereits. Soll die vorhandene Datei übersprungen oder ersetzt werden?\n",
|
||||
"replaceMessage": "Eine Datei mit dem gleichen Namen existiert bereits. Soll die vorhandene Datei übersprungen oder ersetzt werden?",
|
||||
"schedule": "Plan",
|
||||
"scheduleMessage": "Wählen Sie ein Datum und eine Zeit für die Veröffentlichung dieses Beitrags.",
|
||||
"show": "Anzeigen",
|
||||
"size": "Größe",
|
||||
"upload": "Upload",
|
||||
"uploadFiles": "Upload von {files} Dateien...",
|
||||
"uploadMessage": "Wählen Sie eine Upload-Methode",
|
||||
"upload": "Hochladen",
|
||||
"uploadFiles": "{files} Dateien werden hochgeladen...",
|
||||
"uploadMessage": "Wählen Sie eine Methode zum Hochladen",
|
||||
"optionalPassword": "Optionales Passwort",
|
||||
"resolution": "Auflösung",
|
||||
"discardEditorChanges": "Möchten Sie die vorgenommenen Änderungen wirklich verwerfen?"
|
||||
@@ -172,7 +172,7 @@
|
||||
"video": "Video"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace Editor Theme",
|
||||
"aceEditorTheme": "Editor-Farbschema",
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrator",
|
||||
"allowCommands": "Befehle ausführen",
|
||||
@@ -187,35 +187,35 @@
|
||||
"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önnen Sie Befehle eintragen, die bei den benannten Aktionen ausgeführt werden. Geben Sie pro Zeile jeweils einen Befehl ein. Die Umgebungsvariablen {0} und {1} sind verfügbar, wobei {0} relativ zu {1} ist. Für weitere 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": "Mindestlänge für Passwörter",
|
||||
"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.",
|
||||
"tusUploads": "Fortsetzbarer Upload",
|
||||
"tusUploadsHelp": "File Browser unterstützt fortsetzbares Hochladen und ermöglicht so einen effizienten, zuverlässigen 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",
|
||||
"userScopeGenerationPlaceholder": "Geltungsbereich wird automatisch generiert",
|
||||
"createUserHomeDirectory": "Benutzer-Home-Verzeichnis erstellen",
|
||||
"customStylesheet": "Individuelles Stylesheet",
|
||||
"defaultUserDescription": "Das sind die Standardeinstellung für Benutzer",
|
||||
"defaultUserDescription": "Dies sind die Standardeinstellungen für Benutzer",
|
||||
"disableExternalLinks": "Externe Links deaktivieren (außer Dokumentation)",
|
||||
"disableUsedDiskPercentage": "Diagramm zur Festplattennutzung deaktivieren",
|
||||
"documentation": "Dokumentation",
|
||||
"examples": "Beispiele",
|
||||
"executeOnShell": "In Shell ausführen",
|
||||
"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.",
|
||||
"executeOnShellDescription": "Standardmäßig führt der File Browser Befehle direkt aus. Wenn Sie möchten, dass Befehle über eine Kommandozeile (wie Bash oder PowerShell) ausgeführt werden, können Sie diese hier mit allen benötigten Argumenten und Optionen definieren. Der auszuführende Befehl wird als Parameter angehängt. Dies gilt für Benutzerkommandos sowie für Ereignisse.",
|
||||
"globalRules": "Dies ist ein globaler Satz von Regeln, die Aktionen erlauben oder verbieten. Diese gelten für alle Benutzer. In den Benutzereinstellungen können spezielle Regeln definiert werden, die diese überschreiben.",
|
||||
"globalSettings": "Globale Einstellungen",
|
||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||
"insertPath": "Pfad einfügen",
|
||||
"insertRegex": "Regulären Ausdruck (Regex) einfügen",
|
||||
"instanceName": "Instanzname",
|
||||
"language": "Sprache",
|
||||
"lockPassword": "Verhindere, dass der Benutzer sein Passwort ändert",
|
||||
"newPassword": "Ihr neues Passwort.",
|
||||
"newPasswordConfirm": "Bestätigen Sie Ihr neues Passwort",
|
||||
"lockPassword": "Benutzer darf sein Passwort nicht ändern",
|
||||
"newPassword": "Neues Passwort",
|
||||
"newPasswordConfirm": "Neues Passwort bestätigen",
|
||||
"newUser": "Neuer Benutzer",
|
||||
"password": "Passwort",
|
||||
"passwordUpdated": "Passwort aktualisiert!",
|
||||
@@ -232,11 +232,12 @@
|
||||
"permissions": "Berechtigungen",
|
||||
"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",
|
||||
"redirectAfterCopyMove": "Nach Kopieren/Verschieben zum Zielverzeichnis wechseln",
|
||||
"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.",
|
||||
"ruleExample2": "Blockiert den Zugang zu Dateien mit dem Namen Caddyfile im Stammverzeichnis des Geltungsbereichs.",
|
||||
"rules": "Regeln",
|
||||
"rulesHelp": "Hier können Sie erlaubte und verbotene Aktionen für einen einzelnen Benutzer festlegen. Blockierte Dateien werden nicht im Listing angezeigt und sind nicht erreichbar für den Nutzer. Wir unterstützen reguläre Ausdrücke (Regex) und Pfade die relativ zum Benutzerordner sind. \n",
|
||||
"scope": "Scope",
|
||||
"scope": "Geltungsbereich",
|
||||
"setDateFormat": "Exaktes Datumsformat setzen",
|
||||
"settingsUpdated": "Einstellungen aktualisiert!",
|
||||
"shareDuration": "Dauer",
|
||||
@@ -253,12 +254,13 @@
|
||||
"userCommands": "Befehle",
|
||||
"userCommandsHelp": "Eine Liste, mit einem Leerzeichen als Trennung, mit den für diesen Nutzer verfügbaren Befehlen. Beispiel:\n",
|
||||
"userCreated": "Benutzer angelegt!",
|
||||
"userDefaults": "Benutzer Standard Einstellungen",
|
||||
"userDefaults": "Standard-Benutzereinstellungen",
|
||||
"userDeleted": "Benutzer gelöscht!",
|
||||
"userManagement": "Benutzerverwaltung",
|
||||
"userUpdated": "Benutzer aktualisiert!",
|
||||
"username": "Nutzername",
|
||||
"users": "Nutzer"
|
||||
"users": "Nutzer",
|
||||
"currentPassword": "Aktuelles Passwort"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hilfe",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Δικαιώματα",
|
||||
"permissionsHelp": "Μπορείτε να ορίσετε τον χρήστη ως διαχειριστή ή να επιλέξετε τα δικαιώματα μεμονωμένα. Αν επιλέξετε \"Διαχειριστής\", όλες οι υπόλοιπες επιλογές θα είναι αυτόματα επιλεγμένες. Η διαχείριση χρηστών παραμένει προνόμιο ενός χρήστη με τον ρόλο του διαχειριστή.\n",
|
||||
"profileSettings": "Ρυθμίσεις προφίλ",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "αποκλείει την πρόσβαση σε οποιοδήποτε κρυφό αρχείο (όπως .git, .gitignore) σε κάθε φάκελο.\n",
|
||||
"ruleExample2": "αποκλείει την πρόσβαση στο αρχείο με το όνομα Caddyfile στον ριζικό φάκελο της εμβέλειας του κανόνα.",
|
||||
"rules": "Κανόνες",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Διαχείριση χρηστών",
|
||||
"userUpdated": "Ο χρήστης ενημερώθηκε!",
|
||||
"username": "Όνομα χρήστη",
|
||||
"users": "Χρήστες"
|
||||
"users": "Χρήστες",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Βοήθεια",
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
"new": "New",
|
||||
"next": "Next",
|
||||
"ok": "OK",
|
||||
"apply": "Apply",
|
||||
"addField": "Add field",
|
||||
"add": "Add",
|
||||
"permalink": "Get Permanent Link",
|
||||
"previous": "Previous",
|
||||
"preview": "Preview",
|
||||
@@ -159,7 +162,41 @@
|
||||
"uploadMessage": "Select an option to upload.",
|
||||
"optionalPassword": "Optional password",
|
||||
"resolution": "Resolution",
|
||||
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?"
|
||||
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?",
|
||||
"field": "Field",
|
||||
"current": "Current",
|
||||
"new": "New",
|
||||
"multipleValuesCount": "Different on {count} files",
|
||||
"noCover": "No cover",
|
||||
"newFieldName": "Field name",
|
||||
"newFieldValue": "Value",
|
||||
"title": "Title",
|
||||
"artist": "Artist",
|
||||
"album": "Album",
|
||||
"track": "Track",
|
||||
"genre": "Genre",
|
||||
"date": "Date",
|
||||
"comment": "Comment",
|
||||
"disc": "Disc",
|
||||
"composer": "Composer",
|
||||
"year": "Year",
|
||||
"albumartist": "Album artist",
|
||||
"picture": "Cover",
|
||||
"cover": "Cover",
|
||||
"musicbrainz_releasegroupid": "MusicBrainz Release Group ID",
|
||||
"musicbrainz_trackid": "MusicBrainz Track ID",
|
||||
"musicbrainz_albumid": "MusicBrainz Album ID",
|
||||
"musicbrainz_artistid": "MusicBrainz Artist ID",
|
||||
"tsrc": "ISRC",
|
||||
"encoded_by": "Encoded by",
|
||||
"encoder": "Encoder",
|
||||
"copyright": "Copyright"
|
||||
},
|
||||
"metadata": {
|
||||
"field": "Field",
|
||||
"current": "Current",
|
||||
"new": "New",
|
||||
"multipleValuesCount": "Different on {count} files"
|
||||
},
|
||||
"search": {
|
||||
"images": "Images",
|
||||
@@ -232,6 +269,7 @@
|
||||
"permissions": "Permissions",
|
||||
"permissionsHelp": "You can set the user to be an administrator or choose the permissions individually. If you select \"Administrator\", all of the other options will be automatically checked. The management of users remains a privilege of an administrator.\n",
|
||||
"profileSettings": "Profile Settings",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "prevents the access to any dotfile (such as .git, .gitignore) in every folder.\n",
|
||||
"ruleExample2": "blocks the access to the file named Caddyfile on the root of the scope.",
|
||||
"rules": "Rules",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Permisos",
|
||||
"permissionsHelp": "Puedes nombrar al usuario como administrador o elegir los permisos individualmente. Si seleccionas \"Administrador\", todas las otras opciones serán activadas automáticamente. La administración de usuarios es un privilegio de administrador.\n",
|
||||
"profileSettings": "Ajustes del perfil",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "previene el acceso a una extensión de archivo (Como .git) en cada carpeta.\n",
|
||||
"ruleExample2": "bloquea el acceso al archivo llamado Caddyfile en la carpeta raíz.",
|
||||
"rules": "Reglas",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Administración de usuarios",
|
||||
"userUpdated": "¡Usuario actualizado!",
|
||||
"username": "Usuario",
|
||||
"users": "Usuarios"
|
||||
"users": "Usuarios",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ayuda",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "دسترسی ها",
|
||||
"permissionsHelp": "شما میتوانید کاربر را به عنوان مدیر تنظیم کنید یا دسترسیها را به صورت جداگانه انتخاب کنید. اگر \"مدیر\" را انتخاب کنید، تمام گزینههای دیگر به طور خودکار اعمال میشوند. مدیریت کاربران همچنان از اختیارات مدیر است.",
|
||||
"profileSettings": "تنظیمات ناحیه کاربری",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "از دسترسی به هرگونه فایل نقطهای (مانند .git، .gitignore) در هر پوشه جلوگیری میکند.",
|
||||
"ruleExample2": "دسترسی به فایلی به نام Caddyfile را در ریشه دامنه مسدود میکند.",
|
||||
"rules": "قواعد",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "مدیریت کاربران",
|
||||
"userUpdated": "کاربر به روز شد!",
|
||||
"username": "نام کاربری",
|
||||
"users": "کاربران"
|
||||
"users": "کاربران",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "راهنما",
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
"new": "Nouveau",
|
||||
"next": "Suivant",
|
||||
"ok": "OK",
|
||||
"apply": "Appliquer",
|
||||
"addField": "Ajouter un champ",
|
||||
"add": "Ajouter",
|
||||
"permalink": "Obtenir le lien permanent",
|
||||
"previous": "Précédent",
|
||||
"preview": "Prévisualiser",
|
||||
@@ -43,11 +46,11 @@
|
||||
"upload": "Importer",
|
||||
"openFile": "Ouvrir le fichier",
|
||||
"discardChanges": "Annuler",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"stopSearch": "Arrêter recherche",
|
||||
"saveChanges": "Enregistrer changements",
|
||||
"editAsText": "Editer comme Texte",
|
||||
"increaseFontSize": "Augmenter taille police",
|
||||
"decreaseFontSize": "Réduire taille police"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Télécharger le fichier",
|
||||
@@ -80,14 +83,14 @@
|
||||
"sortByName": "Trier par nom",
|
||||
"sortBySize": "Trier par taille",
|
||||
"noPreview": "L'aperçu n'est pas disponible pour ce fichier.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"csvTooLarge": "Le fichier CSV est trop volumineux pour être prévisualisé (>5MB). Veuillez le télécharger pour le voir.",
|
||||
"csvLoadFailed": "Impossible de charger le fichier CSV.",
|
||||
"showingRows": "Affichage de {count} ligne(s)",
|
||||
"columnSeparator": "Séparateur de Colonnes",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
"comma": "Virgule (,)",
|
||||
"semicolon": "Point-virgule (;)",
|
||||
"both": "Les (,) et (;)"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -115,9 +118,9 @@
|
||||
"username": "Utilisateur·ice",
|
||||
"usernameTaken": "Le nom d'utilisateur·ice est déjà pris",
|
||||
"wrongCredentials": "Identifiants incorrects !",
|
||||
"passwordTooShort": "Password must be at least {min} characters",
|
||||
"passwordTooShort": "Le mot de passe doit contenir au moins {min} caractères",
|
||||
"logout_reasons": {
|
||||
"inactivity": "You have been logged out due to inactivity."
|
||||
"inactivity": "Vous avez été déconnecté(e) en raison d'une inactivité prolongée."
|
||||
}
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
@@ -159,7 +162,41 @@
|
||||
"uploadMessage": "Sélectionnez une option d'import.",
|
||||
"optionalPassword": "Mot de passe optionnel",
|
||||
"resolution": "Résolution",
|
||||
"discardEditorChanges": "Êtes-vous sûr de vouloir annuler les modifications apportées ?"
|
||||
"discardEditorChanges": "Êtes-vous sûr de vouloir annuler les modifications apportées ?",
|
||||
"field": "Champ",
|
||||
"current": "Actuel",
|
||||
"new": "Nouveau",
|
||||
"multipleValuesCount": "Différent sur {count} fichiers",
|
||||
"noCover": "Pas de pochette",
|
||||
"newFieldName": "Nom du champ",
|
||||
"newFieldValue": "Valeur",
|
||||
"title": "Titre",
|
||||
"artist": "Artiste",
|
||||
"album": "Album",
|
||||
"track": "Piste",
|
||||
"genre": "Genre",
|
||||
"date": "Date",
|
||||
"comment": "Commentaire",
|
||||
"disc": "Disque",
|
||||
"composer": "Compositeur",
|
||||
"year": "Année",
|
||||
"albumartist": "Artiste de l'album",
|
||||
"picture": "Pochette",
|
||||
"cover": "Pochette",
|
||||
"musicbrainz_releasegroupid": "ID du groupe de publication MusicBrainz",
|
||||
"musicbrainz_trackid": "ID de piste MusicBrainz",
|
||||
"musicbrainz_albumid": "ID d'album MusicBrainz",
|
||||
"musicbrainz_artistid": "ID d'artiste MusicBrainz",
|
||||
"tsrc": "ISRC",
|
||||
"encoded_by": "Encodé par",
|
||||
"encoder": "Encodeur",
|
||||
"copyright": "Copyright"
|
||||
},
|
||||
"metadata": {
|
||||
"field": "Champ",
|
||||
"current": "Actuel",
|
||||
"new": "Nouveau",
|
||||
"multipleValuesCount": "Différent sur {count} fichiers"
|
||||
},
|
||||
"search": {
|
||||
"images": "Images",
|
||||
@@ -172,7 +209,7 @@
|
||||
"video": "Vidéo"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace editor theme",
|
||||
"aceEditorTheme": "Éditeur de Thème Ace",
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrateur·ice",
|
||||
"allowCommands": "Exécuter des commandes",
|
||||
@@ -180,7 +217,7 @@
|
||||
"allowNew": "Créer de nouveaux fichiers et dossiers",
|
||||
"allowPublish": "Publier de nouveaux posts et pages",
|
||||
"allowSignup": "Autoriser les utilisateur·ices à s'inscrire",
|
||||
"hideLoginButton": "Hide the login button from public pages",
|
||||
"hideLoginButton": "Cacher le bouton d’identification sur les pages publiques",
|
||||
"avoidChanges": "(Laisser vide pour conserver l'actuel)",
|
||||
"branding": "Image de marque",
|
||||
"brandingDirectoryPath": "Chemin du dossier d'image de marque",
|
||||
@@ -232,6 +269,7 @@
|
||||
"permissions": "Permissions",
|
||||
"permissionsHelp": "Vous pouvez définir l'utilisateur·ice comme étant administrateur·ice ou encore choisir les permissions individuellement. Si vous sélectionnez \"Administrateur·ice\", toutes les autres options seront automatiquement activées. La gestion des utilisateur·ices est un privilège que seul l'administrateur·ice possède.\n",
|
||||
"profileSettings": "Paramètres du profil",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "Bloque l'accès à tous les fichiers commençant par un point (comme par exemple .git, .gitignore) dans tous les dossiers.\n",
|
||||
"ruleExample2": "Bloque l'accès au fichier nommé \"Caddyfile\" à la racine du dossier utilisateur·ice.",
|
||||
"rules": "Règles",
|
||||
@@ -258,7 +296,8 @@
|
||||
"userManagement": "Gestion des utilisateur·ices",
|
||||
"userUpdated": "Utilisateur·ice mis à jour !",
|
||||
"username": "Nom d'utilisateur·ice",
|
||||
"users": "Utilisateur·ices"
|
||||
"users": "Utilisateur·ices",
|
||||
"currentPassword": "Mot de Passe Actuel"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Aide",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "הרשאות",
|
||||
"permissionsHelp": "אתה יכול להגדיר את המשתמש להיות מנהל מערכת או לבחור את ההרשאות בנפרד. אם תבחר \"מנהל מערכת\", כל ההרשאות יינתנו אוטומטית. ניהול המשתמשים נשאר הרשאה של מנהל מערכת.\n",
|
||||
"profileSettings": "הגדרות פרופיל",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "מנע גישה לקבצים נסתרים (כל קובץ/תיקייה שמתחיל בנקודה, לדוגמא .git)",
|
||||
"ruleExample2": "חסימת גישה לקובץ בשם Caddyfile בהיקף הראשי.",
|
||||
"rules": "חוקים",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "ניהול משתמש",
|
||||
"userUpdated": "המשתמש עודכן!",
|
||||
"username": "שם משתמש",
|
||||
"users": "משתמשים"
|
||||
"users": "משתמשים",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "עזרה",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Dopuštenja",
|
||||
"permissionsHelp": "Korisnika možete postaviti administratorom ili odabrati dopuštenja individualno. Odabirom na \"Administrator\", sve druge opcije bit će automatski odabrane. Upravljanje korisnicima ostaje privilegija administratora.\n",
|
||||
"profileSettings": "Postavke profila",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "onemogućava pristup svakoj datoteci koja započinje točkom (poput .git, .gitignore) u svakoj mapi.\n",
|
||||
"ruleExample2": "blokira pristup datoteci naziva Caddyfile na korijenu opsega.",
|
||||
"rules": "Pravila",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Upravljanje Korisnicima",
|
||||
"userUpdated": "Korisnik ažuriran!",
|
||||
"username": "Korisničko ime",
|
||||
"users": "Korisnici"
|
||||
"users": "Korisnici",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoć",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Jogosultságok",
|
||||
"permissionsHelp": "A felhasználót beállíthatja rendszergazdának, vagy egyénileg is kiválaszthatja a jogosultságokat. Ha a \"Rendszergazda\" lehetőséget választja, az összes többi opció automatikusan be lesz jelölve. A felhasználók kezelése továbbra is a rendszergazda kiváltsága marad.\n",
|
||||
"profileSettings": "Profilbeállítások",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "megakadályozza a hozzáférést bármely rejtett fájlhoz (pl. .git, .gitignore) bármely mappában.\n",
|
||||
"ruleExample2": "blokkolja a hozzáférést a Caddyfile nevű fájlhoz a hatókör gyökerében.",
|
||||
"rules": "Szabályok",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Felhasználókezelés",
|
||||
"userUpdated": "Felhasználó frissítve!",
|
||||
"username": "Felhasználói név",
|
||||
"users": "Felhasználók"
|
||||
"users": "Felhasználók",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Súgó",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Heimildir",
|
||||
"permissionsHelp": "Þú getur stillt notenda sem stjórnanda eða valið einstaklingsbundnar heimildir. Ef þú velur \"Stjórnandi\", þá verða allir aðrir valmöguleikar valdir sjálfrafa. Aðgangstýring notenda er á hendi stjórnenda. \n",
|
||||
"profileSettings": "Stilla prófíl",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "kemur í veg fyrir aðgang að dot-skjali (t.d. .git, .gitignore) í öllum möppum. \n",
|
||||
"ruleExample2": "kemur í veg fyrir aðgang að Caddyfile-skjalinu í root-möppu í sýn notandans. ",
|
||||
"rules": "Reglur",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Notendastýring",
|
||||
"userUpdated": "Notandastillingar vistaðar!",
|
||||
"username": "Notendanafn",
|
||||
"users": "Notendur"
|
||||
"users": "Notendur",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hjálp",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Permessi",
|
||||
"permissionsHelp": "È possibile impostare l'utente come amministratore o scegliere i permessi singolarmente. Se si seleziona \"Amministratore\", tutte le altre opzioni saranno automaticamente assegnate. La gestione degli utenti rimane un privilegio di un amministratore.\n",
|
||||
"profileSettings": "Impostazioni del profilo",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "impedisci l'accesso a qualsiasi file avente come prefisso un punto\n (ad esempio .git, .gitignore) presente in ogni cartella.\n",
|
||||
"ruleExample2": "blocca l'accesso al file denominato Caddyfile nella radice del campo di applicazione.",
|
||||
"rules": "Regole",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Gestione degli utenti",
|
||||
"userUpdated": "Utente aggiornato!",
|
||||
"username": "Nome utente",
|
||||
"users": "Utenti"
|
||||
"users": "Utenti",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Aiuto",
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
"update": "更新",
|
||||
"upload": "アップロード",
|
||||
"openFile": "ファイルを開く",
|
||||
"stopSearch": "検索を停止",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
@@ -233,6 +232,7 @@
|
||||
"permissions": "権限",
|
||||
"permissionsHelp": "ユーザーを管理者に設定するか、その他の権限を個別に選択することができます。「管理者」を選択すると、他のオプションはすべて自動的にチェックされます。ユーザーを管理するには管理者権限が必要です。\n",
|
||||
"profileSettings": "プロフィール設定",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": ".git や .gitignore のようなドットから始まるファイルへのアクセスを禁止します。\n",
|
||||
"ruleExample2": "スコープのルートにある Caddyfile という名前のファイルへのアクセスを禁止します。",
|
||||
"rules": "ルール",
|
||||
@@ -259,7 +259,8 @@
|
||||
"userManagement": "ユーザー管理",
|
||||
"userUpdated": "ユーザーを更新しました!",
|
||||
"username": "ユーザー名",
|
||||
"users": "ユーザー"
|
||||
"users": "ユーザー",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "ヘルプ",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"toggleSidebar": "사이드바 전환",
|
||||
"update": "업데이트",
|
||||
"upload": "업로드",
|
||||
"stopSearch": "검색 중지",
|
||||
"openFile": "파일 열기",
|
||||
"discardChanges": "변경 사항 취소",
|
||||
"stopSearch": "Stop searching",
|
||||
@@ -233,6 +232,7 @@
|
||||
"permissions": "권한",
|
||||
"permissionsHelp": "사용자를 관리자로 만들거나 권한을 부여할 수 있습니다. 관리자를 선택하면, 모든 옵션이 자동으로 선택됩니다. 사용자 관리는 현재 관리자만 할 수 있습니다.\n",
|
||||
"profileSettings": "프로필 설정",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "점(.)으로 시작하는 모든 파일의 접근을 방지합니다.(예 .git, .gitignore)\n",
|
||||
"ruleExample2": "Caddyfile파일의 접근을 방지합니다.",
|
||||
"rules": "룰",
|
||||
@@ -259,7 +259,8 @@
|
||||
"userManagement": "사용자 관리",
|
||||
"userUpdated": "사용자 수정됨!",
|
||||
"username": "사용자 이름",
|
||||
"users": "사용자"
|
||||
"users": "사용자",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "도움말",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Atļaujas",
|
||||
"permissionsHelp": "Varat iestatīt lietotāju kā administratoru vai izvēlēties atļaujas individuāli. Ja atlasīsiet “Administrators”, visas pārējās opcijas tiks automātiski atzīmētas. Lietotāju pārvaldība joprojām ir administratora privilēģija.\n",
|
||||
"profileSettings": "Profila iestatījumi",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "neļauj piekļūt jebkuram dotfile failam (piemēram, .git, .gitignore) katrā mapē.\n",
|
||||
"ruleExample2": "bloķē piekļuvi failam ar nosaukumu Caddyfile darbības jomas saknē.",
|
||||
"rules": "Noteikumi",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Lietotāju pārvaldība",
|
||||
"userUpdated": "Lietotājs atjaunināts!",
|
||||
"username": "Lietotājvārds",
|
||||
"users": "Lietotāji"
|
||||
"users": "Lietotāji",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Palīdzība",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"upload": "Augšupielādēt",
|
||||
"openFile": "Atvērt failu",
|
||||
"discardChanges": "Izmest",
|
||||
"stopSearch": "Stop searching",
|
||||
"stopSearch": "Beigt meklēšanu",
|
||||
"saveChanges": "Saglabāt izmaiņas",
|
||||
"editAsText": "Rediģēt kā tekstu",
|
||||
"increaseFontSize": "Palieliniet fonta lielumu",
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Atļaujas",
|
||||
"permissionsHelp": "Varat iestatīt lietotāju kā administratoru vai izvēlēties atļaujas individuāli. Ja atlasīsiet “Administrators”, visas pārējās opcijas tiks automātiski atzīmētas. Lietotāju pārvaldība joprojām ir administratora privilēģija.\n",
|
||||
"profileSettings": "Profila iestatījumi",
|
||||
"redirectAfterCopyMove": "Pārvirzīt uz galapunktu pēc kopēšanas/pārvietošanas",
|
||||
"ruleExample1": "neļauj piekļūt jebkuram dotfile failam (piemēram, .git, .gitignore) katrā mapē.\n",
|
||||
"ruleExample2": "bloķē piekļuvi failam ar nosaukumu Caddyfile darbības jomas saknē.",
|
||||
"rules": "Noteikumi",
|
||||
@@ -241,7 +242,7 @@
|
||||
"settingsUpdated": "Iestatījumi atjaunināti!",
|
||||
"shareDuration": "Kopīgošanas ilgums",
|
||||
"shareManagement": "Kopīgošanas pārvaldība",
|
||||
"shareDeleted": "Kopīgošana ir izdzēsta!",
|
||||
"shareDeleted": "Kopīgojums izdzēsts!",
|
||||
"singleClick": "Failu un direktoriju atvēršanai izmantojiet vienus klikšķi",
|
||||
"themes": {
|
||||
"default": "Sistēmas noklusējums",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Lietotāju pārvaldība",
|
||||
"userUpdated": "Lietotājs atjaunināts!",
|
||||
"username": "Lietotājvārds",
|
||||
"users": "Lietotāji"
|
||||
"users": "Lietotāji",
|
||||
"currentPassword": "Esošā Parole"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Palīdzība",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Permissies",
|
||||
"permissionsHelp": "U kunt de gebruiker instellen als beheerder of de machtigingen afzonderlijk kiezen. Als u \"Beheerder\" selecteert, worden alle andere opties automatisch gecontroleerd. Het beheer van gebruikers blijft een privilege van een beheerder.\n",
|
||||
"profileSettings": "Profielinstellingen",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "voorkomt de toegang tot elk puntbestand (zoals .git, .gitignore) in elke map.\n",
|
||||
"ruleExample2": "blokkeert de toegang tot het bestand met de naam Caddyfile in de hoofdmap van het bereik.",
|
||||
"rules": "Regels",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Gebruikersbeheer",
|
||||
"userUpdated": "Gebruiker bijgewerkt!",
|
||||
"username": "Gebruikersnaam",
|
||||
"users": "Gebruikers"
|
||||
"users": "Gebruikers",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Help",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Tilaterser",
|
||||
"permissionsHelp": "Du kan angi brukeren som administrator eller velge tillatelsene individuelt. Hvis du velger «Administrator», vil alle de andre alternativene bli automatisk avkrysset. Administrasjon av brukere er fortsatt et privilegium for en administrator.\n",
|
||||
"profileSettings": "Profil Innstilinger",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "forhindrer tilgang til noen dotfiler (som .git, .gitignore) i alle mapper.\n",
|
||||
"ruleExample2": "blokkerer tilgangen til filen med navnet Caddyfile på roten av omfanget.",
|
||||
"rules": "Regler",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Brukeradministrasjon",
|
||||
"userUpdated": "Bruker opprettet!",
|
||||
"username": "Brukernavn",
|
||||
"users": "Bruker"
|
||||
"users": "Bruker",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hjelp",
|
||||
|
||||
@@ -231,7 +231,8 @@
|
||||
},
|
||||
"permissions": "Uprawnienia",
|
||||
"permissionsHelp": "Możesz ustawić użytkownika jako administratora lub wybrać uprawnienia indywidualnie. Jeśli wybierzesz „Administrator”, wszystkie pozostałe opcje zostaną automatycznie zaznaczone. Zarządzanie użytkownikami pozostaje przywilejem administratora.\n",
|
||||
"profileSettings": "Twój profil",
|
||||
"profileSettings": "Ustawienia profilu",
|
||||
"redirectAfterCopyMove": "Przekieruj do miejsca docelowego po skopiowaniu lub przeniesieniu",
|
||||
"ruleExample1": "uniemożliwia dostęp do plików poprzedzonych kropką (takich jak .git, .gitignore) we wszystkich folderach.\n",
|
||||
"ruleExample2": "blokuje dostęp do pliku o nazwie Caddyfile w katalogu głównym zakresu.",
|
||||
"rules": "Uprawnienia",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Zarządzanie użytkownikami",
|
||||
"userUpdated": "Użytkownik zapisany!",
|
||||
"username": "Nazwa użytkownika",
|
||||
"users": "Użytkownicy"
|
||||
"users": "Użytkownicy",
|
||||
"currentPassword": "Twoje aktualne hasło"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoc",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Permissões",
|
||||
"permissionsHelp": "Pode definir o usuário como administrador ou escolher as permissões manualmente. Se selecionar a opção \"Administrador\", todas as outras opções serão automaticamente selecionadas. A gestão dos usuários é um privilégio restringido aos administradores.\n",
|
||||
"profileSettings": "Configurações do usuário",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "previne o acesso a qualquer \"dotfile\" (como .git, .gitignore) em qualquer pasta\n",
|
||||
"ruleExample2": "bloqueia o acesso ao arquivo chamado Caddyfile.",
|
||||
"rules": "Regras",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Gerenciamento de usuários",
|
||||
"userUpdated": "Usuário atualizado!",
|
||||
"username": "Nome do usuário",
|
||||
"users": "Usuários"
|
||||
"users": "Usuários",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Permissões",
|
||||
"permissionsHelp": "Pode definir o utilizador como administrador ou escolher as permissões manualmente. Se selecionar a opção \"Administrador\", todas as outras opções serão automaticamente selecionadas. A gestão dos utilizadores é um privilégio restringido aos administradores.\n",
|
||||
"profileSettings": "Configurações do utilizador",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "previne o acesso a qualquer \"dotfile\" (como .git, .gitignore) em qualquer pasta\n",
|
||||
"ruleExample2": "bloqueia o acesso ao ficheiro chamado Caddyfile na raiz.",
|
||||
"rules": "Regras",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Gestão de utilizadores",
|
||||
"userUpdated": "Utilizador atualizado!",
|
||||
"username": "Nome de utilizador",
|
||||
"users": "Utilizadores"
|
||||
"users": "Utilizadores",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Permisiuni",
|
||||
"permissionsHelp": "Poți alege ca un utilizator să fie administrator sau să-i alegi permisiunile individual. Dacă alegi \"Administrator\", toate celelalte opțiuni vor fi bifate automat. Gestionarea utilizatorilor rămâne un privilegiu exclusiv al administratorilor.\n",
|
||||
"profileSettings": "Setări profil",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "împiedică accesul la fisiere cu punct in față (.), cum ar fi .git, .gitignore în orice director.\n",
|
||||
"ruleExample2": "împiedică accesul la fișierul Caddyfile din rădăcina domeniului.",
|
||||
"rules": "Reguli",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Gestionare utilizatori",
|
||||
"userUpdated": "Utilizator actualizat!",
|
||||
"username": "Utilizator",
|
||||
"users": "Utilizatori"
|
||||
"users": "Utilizatori",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajutor",
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
"update": "Обновить",
|
||||
"upload": "Загрузить",
|
||||
"openFile": "Открыть файл",
|
||||
"stopSearch": "Прекратить поиск",
|
||||
"discardChanges": "Отказаться",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Сохранить",
|
||||
@@ -233,6 +232,7 @@
|
||||
"permissions": "Права доступа",
|
||||
"permissionsHelp": "Можно настроить пользователя как администратора или выбрать разрешения индивидуально. При выборе \"Администратор\", все остальные параметры будут автоматически выбраны. Управление пользователями - привилегия администратора.\n",
|
||||
"profileSettings": "Настройки профиля",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "предотвратить доступ к любому скрытому файлу (например: .git, .gitignore) в каждой папке.\n",
|
||||
"ruleExample2": "блокирует доступ к файлу с именем Caddyfile в корневой области.",
|
||||
"rules": "Права",
|
||||
@@ -259,7 +259,8 @@
|
||||
"userManagement": "Управление пользователями",
|
||||
"userUpdated": "Пользователь изменен!",
|
||||
"username": "Имя пользователя",
|
||||
"users": "Пользователи"
|
||||
"users": "Пользователи",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Помощь",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Práva",
|
||||
"permissionsHelp": "Môžete nastaviť používateľa, aby bol administrátorom alebo vybrať práva jednotlivo. Ak zvolíte \"Administrator\", všetky ďalšie budú automaticky zaškrtnuté. Manažment používateľov ostáva v správe administrátora.\n",
|
||||
"profileSettings": "Nastavenia profilu",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "blokuje prístup ku všetkým súborom začínajúcim bodkou (napríklad .git, .gitignore) v každom priečinku.\n",
|
||||
"ruleExample2": "blokuje prístup k súborom s názvom Caddyfile v koreňovom priečinku.",
|
||||
"rules": "Pravidlá",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Správa používateľov",
|
||||
"userUpdated": "Používateľ upravený!",
|
||||
"username": "Meno používateľa",
|
||||
"users": "Používatelia"
|
||||
"users": "Používatelia",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoc",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Rättigheter",
|
||||
"permissionsHelp": "Du kan ange att användaren ska vara administratör eller välja behörigheterna individuellt. Om du väljer \"administratör \" kommer alla andra alternativ att kontrolleras automatiskt. Hanteringen av användare är fortfarande ett privilegium för en administratör.\n",
|
||||
"profileSettings": "Profil inställningar",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "förhindrar åtkomst till en dot-fil (till exempel. git,. gitignore) i varje mapp.\n",
|
||||
"ruleExample2": "blockerar åtkomsten till filen som heter Caddyfilen i roten av scopet.",
|
||||
"rules": "Regler",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Användarehantering",
|
||||
"userUpdated": "Användare uppdaterad!",
|
||||
"username": "Användarnamn",
|
||||
"users": "Användare"
|
||||
"users": "Användare",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hjälp",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "İzinler",
|
||||
"permissionsHelp": "Kullanıcıyı yönetici olarak ayarlayabilir veya izinleri ayrı ayrı seçebilirsiniz. \"Yönetici\"yi seçerseniz, diğer tüm seçenekler otomatik olarak kontrol edilecektir. Kullanıcıların yönetimi, bir yöneticinin yetkisi olarak kalır.\n",
|
||||
"profileSettings": "Profil ayarları",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "her klasördeki herhangi bir noktalı dosyaya (.git, .gitignore gibi) erişimi engeller.\n",
|
||||
"ruleExample2": "Root erişimidenki CaddyFile dosyalarına erişimi engelle.",
|
||||
"rules": "Kurallar",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Kullanıcı yönetimi",
|
||||
"userUpdated": "Kullanıcı güncellendi!",
|
||||
"username": "Kullanıcı adı",
|
||||
"users": "Kullanıcılar"
|
||||
"users": "Kullanıcılar",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Yardım",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Дозволи",
|
||||
"permissionsHelp": "Можна налаштувати користувача як адміністратора чи вибрати індивідуальні дозволи. При виборі \"Адміністратор\" всі інші параметри будуть автоматично вибрані. Керування користувачами - привілей адміністратора.\n",
|
||||
"profileSettings": "Налаштування профілю",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "запобігти доступу до будь-якого прихованого файлу (наприклад: .git, .gitignore) у кожній папці.\n",
|
||||
"ruleExample2": "блокує доступ до файлу з ім'ям Caddyfile у кореневій області.",
|
||||
"rules": "Права",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Керування користувачами",
|
||||
"userUpdated": "Користувача змінено!",
|
||||
"username": "Ім'я користувача",
|
||||
"users": "Користувачі"
|
||||
"users": "Користувачі",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Допомога",
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
"permissions": "Quyền",
|
||||
"permissionsHelp": "Bạn có thể đặt người dùng làm quản trị viên hoặc chọn quyền riêng lẻ. Nếu chọn \"Người quản trị\", tất cả các tùy chọn khác sẽ tự động được chọn. Việc quản lý người dùng vẫn là đặc quyền của quản trị viên.\n",
|
||||
"profileSettings": "Cài đặt hồ sơ",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "ngăn truy cập vào bất kỳ tệp ẩn nào (chẳng hạn như .git, .gitignore) trong mọi thư mục.\n",
|
||||
"ruleExample2": "chặn truy cập vào tệp có tên Caddyfile trong thư mục gốc của phạm vi.",
|
||||
"rules": "Quy tắc",
|
||||
@@ -258,7 +259,8 @@
|
||||
"userManagement": "Quản lý người dùng",
|
||||
"userUpdated": "Người dùng đã được cập nhật!",
|
||||
"username": "Tên người dùng",
|
||||
"users": "Người dùng"
|
||||
"users": "Người dùng",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Trợ giúp",
|
||||
|
||||
@@ -42,9 +42,8 @@
|
||||
"update": "更新",
|
||||
"upload": "上传",
|
||||
"openFile": "打开文件",
|
||||
"stopSearch": "停止搜索",
|
||||
"discardChanges": "放弃更改",
|
||||
"stopSearch": "Stop searching",
|
||||
"stopSearch": "停止搜索",
|
||||
"saveChanges": "保存更改",
|
||||
"editAsText": "以文本形式编辑",
|
||||
"increaseFontSize": "增大字体大小",
|
||||
@@ -233,6 +232,7 @@
|
||||
"permissions": "权限",
|
||||
"permissionsHelp": "你可以将该用户设置为管理员或单独选择各项权限。如果你选择了“管理员”,则其他的选项会被自动选中,同时该用户可以管理其他用户。\n",
|
||||
"profileSettings": "个人设置",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "阻止用户访问所有文件夹下任何以 . 开头的文件(隐藏文件, 例如: .git, .gitignore)。\n",
|
||||
"ruleExample2": "阻止用户访问其目录范围的根目录下名为 Caddyfile 的文件。",
|
||||
"rules": "规则",
|
||||
@@ -259,7 +259,8 @@
|
||||
"userManagement": "用户管理",
|
||||
"userUpdated": "用户已更新!",
|
||||
"username": "用户名",
|
||||
"users": "用户"
|
||||
"users": "用户",
|
||||
"currentPassword": "您当前的密码"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "帮助",
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
"update": "更新",
|
||||
"upload": "上傳",
|
||||
"openFile": "開啟檔案",
|
||||
"stopSearch": "停止搜尋",
|
||||
"discardChanges": "放棄變更",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
@@ -233,6 +232,7 @@
|
||||
"permissions": "權限",
|
||||
"permissionsHelp": "您可以將該使用者設置為管理員,也可以單獨選擇各項權限。如果選擇了“管理員”,則其他的選項會被自動勾上,同時該使用者可以管理其他使用者。",
|
||||
"profileSettings": "個人設定",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "封鎖使用者存取所有資料夾下任何以 . 開頭的檔案(隱藏文件, 例如: .git, .gitignore)。",
|
||||
"ruleExample2": "封鎖使用者存取其目錄範圍的根目錄下名為 Caddyfile 的檔案。",
|
||||
"rules": "規則",
|
||||
@@ -259,7 +259,8 @@
|
||||
"userManagement": "使用者管理",
|
||||
"userUpdated": "使用者已更新!",
|
||||
"username": "使用者名稱",
|
||||
"users": "使用者"
|
||||
"users": "使用者",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "幫助",
|
||||
|
||||
1
frontend/src/types/settings.d.ts
vendored
1
frontend/src/types/settings.d.ts
vendored
@@ -18,6 +18,7 @@ interface SettingsDefaults {
|
||||
locale: string;
|
||||
viewMode: ViewModeType;
|
||||
singleClick: boolean;
|
||||
redirectAfterCopyMove: boolean;
|
||||
sorting: Sorting;
|
||||
perm: Permissions;
|
||||
commands: any[];
|
||||
|
||||
2
frontend/src/types/user.d.ts
vendored
2
frontend/src/types/user.d.ts
vendored
@@ -10,6 +10,7 @@ interface IUser {
|
||||
lockPassword: boolean;
|
||||
hideDotfiles: boolean;
|
||||
singleClick: boolean;
|
||||
redirectAfterCopyMove: boolean;
|
||||
dateFormat: boolean;
|
||||
viewMode: ViewModeType;
|
||||
sorting?: Sorting;
|
||||
@@ -30,6 +31,7 @@ interface IUserForm {
|
||||
lockPassword?: boolean;
|
||||
hideDotfiles?: boolean;
|
||||
singleClick?: boolean;
|
||||
redirectAfterCopyMove?: boolean;
|
||||
dateFormat?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,20 @@ export function copy(data: ClipboardArgs, opts?: ClipboardOpts) {
|
||||
});
|
||||
}
|
||||
|
||||
export function read() {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (
|
||||
// Clipboard API requires secure context
|
||||
window.isSecureContext &&
|
||||
typeof navigator.clipboard !== "undefined"
|
||||
) {
|
||||
navigator.clipboard.readText().then(resolve).catch(reject);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getPermission(name: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
typeof navigator.permissions !== "undefined" &&
|
||||
|
||||
@@ -41,7 +41,30 @@
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<Breadcrumbs base="/files" noLink />
|
||||
<div class="editor-header">
|
||||
<Breadcrumbs base="/files" noLink />
|
||||
|
||||
<div>
|
||||
<button
|
||||
:disabled="isSelectionEmpty"
|
||||
@click="executeEditorCommand('copy')"
|
||||
>
|
||||
<span><i class="material-icons">content_copy</i></span>
|
||||
</button>
|
||||
<button
|
||||
:disabled="isSelectionEmpty"
|
||||
@click="executeEditorCommand('cut')"
|
||||
>
|
||||
<span><i class="material-icons">content_cut</i></span>
|
||||
</button>
|
||||
<button @click="executeEditorCommand('paste')">
|
||||
<span><i class="material-icons">content_paste</i></span>
|
||||
</button>
|
||||
<button @click="executeEditorCommand('openCommandPalette')">
|
||||
<span><i class="material-icons">more_vert</i></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="isPreview && isMarkdownFile"
|
||||
@@ -74,6 +97,7 @@ import { marked } from "marked";
|
||||
import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
||||
import { read, copy } from "@/utils/clipboard";
|
||||
|
||||
const $showError = inject<IToastError>("$showError")!;
|
||||
|
||||
@@ -95,6 +119,35 @@ const isMarkdownFile =
|
||||
fileStore.req?.name.endsWith(".md") ||
|
||||
fileStore.req?.name.endsWith(".markdown");
|
||||
|
||||
const isSelectionEmpty = ref(true);
|
||||
|
||||
const executeEditorCommand = (name: string) => {
|
||||
if (name == "paste") {
|
||||
read()
|
||||
.then((data) => {
|
||||
editor.value?.execCommand("paste", {
|
||||
text: data,
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
if (
|
||||
document.queryCommandSupported &&
|
||||
document.queryCommandSupported("paste")
|
||||
) {
|
||||
document.execCommand("paste");
|
||||
} else {
|
||||
console.warn("the clipboard api is not supported", e);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (name == "copy" || name == "cut") {
|
||||
const selectedText = editor.value?.getCopyText();
|
||||
copy({ text: selectedText });
|
||||
}
|
||||
editor.value?.execCommand(name);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("keydown", keyEvent);
|
||||
window.addEventListener("beforeunload", handlePageChange);
|
||||
@@ -132,6 +185,11 @@ onMounted(() => {
|
||||
|
||||
editor.value.setFontSize(fontSize.value);
|
||||
editor.value.focus();
|
||||
|
||||
editor.value.getSelection().on("changeSelection", () => {
|
||||
isSelectionEmpty.value =
|
||||
editor.value == null || editor.value.getSelectedText().length == 0;
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -236,7 +294,6 @@ const close = () => {
|
||||
};
|
||||
|
||||
const finishClose = () => {
|
||||
fileStore.updateRequest(null);
|
||||
const uri = url.removeLastDir(route.path) + "/";
|
||||
router.push({ path: uri });
|
||||
};
|
||||
@@ -251,4 +308,32 @@ const preview = () => {
|
||||
margin: 0 0.5em;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.editor-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor-header > div > button {
|
||||
background: transparent;
|
||||
color: var(--action);
|
||||
border: none;
|
||||
outline: none;
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.editor-header > div > button:hover:not(:disabled) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.editor-header > div > button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.editor-header > div > button > span > i {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -72,6 +72,12 @@
|
||||
:label="t('buttons.upload')"
|
||||
@action="uploadFunc"
|
||||
/>
|
||||
<action
|
||||
v-if="headerButtons.metadata"
|
||||
icon="library_music"
|
||||
:label="t('metadata')"
|
||||
@action="openMetadata"
|
||||
/>
|
||||
<action icon="info" :label="t('buttons.info')" show="info" />
|
||||
<action
|
||||
icon="check_circle"
|
||||
@@ -81,7 +87,13 @@
|
||||
</template>
|
||||
</header-bar>
|
||||
|
||||
<div v-if="isMobile" id="file-selection">
|
||||
<div
|
||||
v-if="isMobile"
|
||||
id="file-selection"
|
||||
:class="{
|
||||
'file-selection-margin-bottom': fileStore.multiple,
|
||||
}"
|
||||
>
|
||||
<span v-if="fileStore.selectedCount > 0">
|
||||
{{ t("prompts.filesSelected", fileStore.selectedCount) }}
|
||||
</span>
|
||||
@@ -158,7 +170,9 @@
|
||||
id="listing"
|
||||
ref="listing"
|
||||
class="file-icons"
|
||||
data-clear-on-click="true"
|
||||
:class="authStore.user?.viewMode ?? ''"
|
||||
@click="handleEmptyAreaClick"
|
||||
>
|
||||
<div>
|
||||
<div class="item header">
|
||||
@@ -204,11 +218,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 v-if="fileStore.req?.numDirs ?? false">
|
||||
<h2 data-clear-on-click="true" v-if="fileStore.req?.numDirs ?? false">
|
||||
{{ t("files.folders") }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="fileStore.req?.numDirs ?? false"
|
||||
data-clear-on-click="true"
|
||||
@contextmenu="showContextMenu"
|
||||
>
|
||||
<item
|
||||
@@ -226,11 +241,12 @@
|
||||
</item>
|
||||
</div>
|
||||
|
||||
<h2 v-if="fileStore.req?.numFiles ?? false">
|
||||
<h2 data-clear-on-click="true" v-if="fileStore.req?.numFiles ?? false">
|
||||
{{ t("files.files") }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="fileStore.req?.numFiles ?? false"
|
||||
data-clear-on-click="true"
|
||||
@contextmenu="showContextMenu"
|
||||
>
|
||||
<item
|
||||
@@ -292,6 +308,12 @@
|
||||
@action="download"
|
||||
:counter="fileStore.selectedCount"
|
||||
/>
|
||||
<action
|
||||
v-if="headerButtons.metadata"
|
||||
icon="library_music"
|
||||
:label="t('metadata')"
|
||||
@action="openMetadata"
|
||||
/>
|
||||
<action icon="info" :label="t('buttons.info')" show="info" />
|
||||
</context-menu>
|
||||
|
||||
@@ -473,9 +495,29 @@ const headerButtons = computed(() => {
|
||||
share: fileStore.selectedCount === 1 && authStore.user?.perm.share,
|
||||
move: fileStore.selectedCount > 0 && authStore.user?.perm.rename,
|
||||
copy: fileStore.selectedCount > 0 && authStore.user?.perm.create,
|
||||
metadata:
|
||||
fileStore.selectedCount > 0 &&
|
||||
fileStore.req &&
|
||||
fileStore.selected.every((i) => {
|
||||
const name = fileStore.req!.items[i].name || "";
|
||||
const idx = name.lastIndexOf(".");
|
||||
const ext = idx === -1 ? "" : name.substring(idx).toLowerCase();
|
||||
return [".mp3", ".flac"].includes(ext);
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const openMetadata = () => {
|
||||
if (!fileStore.req) return;
|
||||
|
||||
const files: string[] = [];
|
||||
for (const i of fileStore.selected) {
|
||||
files.push(fileStore.req.items[i].url);
|
||||
}
|
||||
|
||||
layoutStore.showHover({ prompt: "modifyMetadata", props: { files } });
|
||||
};
|
||||
|
||||
const isMobile = computed(() => {
|
||||
return width.value <= 736;
|
||||
});
|
||||
@@ -1051,4 +1093,22 @@ const showContextMenu = (event: MouseEvent) => {
|
||||
const hideContextMenu = () => {
|
||||
isContextMenuVisible.value = false;
|
||||
};
|
||||
|
||||
const handleEmptyAreaClick = (e: MouseEvent) => {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLElement)) return;
|
||||
|
||||
if (target.dataset.clearOnClick === "true") {
|
||||
fileStore.selected = [];
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
#listing {
|
||||
min-height: calc(100vh - 8rem);
|
||||
}
|
||||
|
||||
.file-selection-margin-bottom {
|
||||
margin-bottom: 3.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
<input type="checkbox" name="singleClick" v-model="singleClick" />
|
||||
{{ t("settings.singleClick") }}
|
||||
</p>
|
||||
<p>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="redirectAfterCopyMove"
|
||||
v-model="redirectAfterCopyMove"
|
||||
/>
|
||||
{{ t("settings.redirectAfterCopyMove") }}
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" name="dateFormat" v-model="dateFormat" />
|
||||
{{ t("settings.setDateFormat") }}
|
||||
@@ -44,7 +52,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div v-if="!noAuth" class="column">
|
||||
<form
|
||||
class="card"
|
||||
v-if="!authStore.user?.lockPassword"
|
||||
@@ -96,11 +104,12 @@
|
||||
<script setup lang="ts">
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { users as api, settings } from "@/api";
|
||||
import { users as api } from "@/api";
|
||||
import AceEditorTheme from "@/components/settings/AceEditorTheme.vue";
|
||||
import Languages from "@/components/settings/Languages.vue";
|
||||
import { computed, inject, onMounted, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { authMethod, noAuth } from "@/utils/constants";
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
const authStore = useAuthStore();
|
||||
@@ -115,6 +124,7 @@ const currentPassword = ref<string>("");
|
||||
const isCurrentPasswordRequired = ref<boolean>(false);
|
||||
const hideDotfiles = ref<boolean>(false);
|
||||
const singleClick = ref<boolean>(false);
|
||||
const redirectAfterCopyMove = ref<boolean>(false);
|
||||
const dateFormat = ref<boolean>(false);
|
||||
const locale = ref<string>("");
|
||||
const aceEditorTheme = ref<string>("");
|
||||
@@ -139,10 +149,10 @@ onMounted(async () => {
|
||||
locale.value = authStore.user.locale;
|
||||
hideDotfiles.value = authStore.user.hideDotfiles;
|
||||
singleClick.value = authStore.user.singleClick;
|
||||
redirectAfterCopyMove.value = authStore.user.redirectAfterCopyMove;
|
||||
dateFormat.value = authStore.user.dateFormat;
|
||||
aceEditorTheme.value = authStore.user.aceEditorTheme;
|
||||
layoutStore.loading = false;
|
||||
const { authMethod } = await settings.get();
|
||||
isCurrentPasswordRequired.value = authMethod == "json";
|
||||
|
||||
return true;
|
||||
@@ -187,6 +197,7 @@ const updateSettings = async (event: Event) => {
|
||||
locale: locale.value,
|
||||
hideDotfiles: hideDotfiles.value,
|
||||
singleClick: singleClick.value,
|
||||
redirectAfterCopyMove: redirectAfterCopyMove.value,
|
||||
dateFormat: dateFormat.value,
|
||||
aceEditorTheme: aceEditorTheme.value,
|
||||
};
|
||||
@@ -195,6 +206,7 @@ const updateSettings = async (event: Event) => {
|
||||
"locale",
|
||||
"hideDotfiles",
|
||||
"singleClick",
|
||||
"redirectAfterCopyMove",
|
||||
"dateFormat",
|
||||
"aceEditorTheme",
|
||||
]);
|
||||
|
||||
@@ -71,6 +71,7 @@ import { computed, inject, onMounted, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { StatusError } from "@/api/utils";
|
||||
import { authMethod } from "@/utils/constants";
|
||||
|
||||
const error = ref<StatusError>();
|
||||
const originalUser = ref<IUser>();
|
||||
@@ -105,11 +106,7 @@ const fetchData = async () => {
|
||||
|
||||
try {
|
||||
if (isNew.value) {
|
||||
const {
|
||||
authMethod,
|
||||
defaults,
|
||||
createUserDir: _createUserDir,
|
||||
} = await settings.get();
|
||||
const { defaults, createUserDir: _createUserDir } = await settings.get();
|
||||
isCurrentPasswordRequired.value = authMethod == "json";
|
||||
createUserDir.value = _createUserDir;
|
||||
user.value = {
|
||||
@@ -146,7 +143,7 @@ const deleteUser = async (e: Event) => {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await api.remove(user.value.id);
|
||||
await api.remove(user.value.id, currentPassword.value);
|
||||
router.push({ path: "/settings/users" });
|
||||
$showSuccess(t("settings.userDeleted"));
|
||||
} catch (err) {
|
||||
|
||||
12
go.mod
12
go.mod
@@ -24,9 +24,9 @@ require (
|
||||
github.com/spf13/viper v1.21.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||
golang.org/x/crypto v0.46.0
|
||||
golang.org/x/image v0.34.0
|
||||
golang.org/x/text v0.32.0
|
||||
golang.org/x/crypto v0.47.0
|
||||
golang.org/x/image v0.35.0
|
||||
golang.org/x/text v0.33.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
@@ -41,6 +41,8 @@ require (
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 // indirect
|
||||
github.com/bogem/id3v2/v2 v2.0.9
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
|
||||
@@ -73,9 +75,9 @@ require (
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
464
go.sum
464
go.sum
@@ -1,464 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=
|
||||
github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
|
||||
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM=
|
||||
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac=
|
||||
github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
|
||||
github.com/asticode/go-astikit v0.20.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
|
||||
github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
|
||||
github.com/asticode/go-astikit v0.56.0 h1:DmD2p7YnvxiPdF0h+dRmos3bsejNEXbycENsY5JfBqw=
|
||||
github.com/asticode/go-astikit v0.56.0/go.mod h1:fV43j20UZYfXzP9oBn33udkvCvDvCDhzjVqoLFuuYZE=
|
||||
github.com/asticode/go-astisub v0.38.0 h1:Qh3IO8Cotn0wwok5maid7xqsIJTwn2DtABT1UajKJaI=
|
||||
github.com/asticode/go-astisub v0.38.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8=
|
||||
github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ=
|
||||
github.com/asticode/go-astits v1.13.0 h1:XOgkaadfZODnyZRR5Y0/DWkA9vrkLLPLeeOvDwfKZ1c=
|
||||
github.com/asticode/go-astits v1.13.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
|
||||
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
|
||||
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
||||
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
|
||||
github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=
|
||||
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20221003160559-cf5cd88aa559/go.mod h1:rW6DMEv25U9zCtE5ukC7ttBRllXj7g7TAHl7tQrT5No=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20221003171958-de6cb6e380a8/go.mod h1:akyZEJZ/k5bmbC9gA612ZLQkcED8enS9vuTiuAkENr0=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.1 h1:/IE4iW7gvY7BablV1XY0unqhMv26EYpOquVMwoBo/wc=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.1/go.mod h1:10HkA1Wz3h398cDP66L+Is9kKDmlqlIJGPv8pk4EWvc=
|
||||
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
|
||||
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
|
||||
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003142440-7a1927d49d9d/go.mod h1:LVjRU0RNUuMDqkPTxcALio0LWPFPXxxFCvVGVAwEpFc=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003160719-7bc88537c05e/go.mod h1:VZ7cB0pTjm1ADBWhJUOHESu4ZYy9JN+ZPqjfiW09EPU=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje0z+3UQ5YjYiSRRzVdtamFpvBQXKwMglWqw=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20250707181242-c5087ca84cf4 h1:vCeHcs8N7MOccOOsOVIy1xcYu+kBkA4J5urTgigww7c=
|
||||
github.com/golang/geo v0.0.0-20250707181242-c5087ca84cf4/go.mod h1:AN0OjM34c3PbjAsX+QNma1nYtJtRxl+s9MZNV7S+efw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/maruel/natural v1.3.0 h1:VsmCsBmEyrR46RomtgHs5hbKADGRVtliHTyCOLFBpsg=
|
||||
github.com/maruel/natural v1.3.0/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
|
||||
github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM=
|
||||
github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ=
|
||||
github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=
|
||||
github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4=
|
||||
github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
|
||||
github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
|
||||
github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=
|
||||
github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
|
||||
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||
github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY=
|
||||
github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||
github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=
|
||||
github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
|
||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
|
||||
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
|
||||
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
46
http/auth.go
46
http/auth.go
@@ -23,17 +23,18 @@ const (
|
||||
)
|
||||
|
||||
type userInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
Username string `json:"username"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
ID uint `json:"id"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
RedirectAfterCopyMove bool `json:"redirectAfterCopyMove"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
Username string `json:"username"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
}
|
||||
|
||||
type authToken struct {
|
||||
@@ -204,17 +205,18 @@ func renewHandler(tokenExpireTime time.Duration) handleFunc {
|
||||
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) {
|
||||
claims := &authToken{
|
||||
User: userInfo{
|
||||
ID: user.ID,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
Perm: user.Perm,
|
||||
LockPassword: user.LockPassword,
|
||||
Commands: user.Commands,
|
||||
HideDotfiles: user.HideDotfiles,
|
||||
DateFormat: user.DateFormat,
|
||||
Username: user.Username,
|
||||
AceEditorTheme: user.AceEditorTheme,
|
||||
ID: user.ID,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
RedirectAfterCopyMove: user.RedirectAfterCopyMove,
|
||||
Perm: user.Perm,
|
||||
LockPassword: user.LockPassword,
|
||||
Commands: user.Commands,
|
||||
HideDotfiles: user.HideDotfiles,
|
||||
DateFormat: user.DateFormat,
|
||||
Username: user.Username,
|
||||
AceEditorTheme: user.AceEditorTheme,
|
||||
},
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
|
||||
127
http/resource.go
127
http/resource.go
@@ -2,6 +2,7 @@ package fbhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -10,9 +11,11 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
"github.com/spf13/afero"
|
||||
@@ -54,6 +57,13 @@ var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
||||
file.Content = ""
|
||||
}
|
||||
|
||||
// If metadata requested, attempt to read audio tags and attach them
|
||||
if r.URL.Query().Get("metadata") == "1" {
|
||||
if err := file.ReadAudioTags(); err != nil {
|
||||
log.Printf("warning: failed reading audio tags for %s: %v", file.Path, err)
|
||||
}
|
||||
}
|
||||
|
||||
return renderJSON(w, r, file)
|
||||
})
|
||||
|
||||
@@ -201,14 +211,20 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
|
||||
err = checkParent(src, dst)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
// Only check parent relationship when a destination was provided.
|
||||
// Some actions (like metadata) don't provide a destination and calling
|
||||
// filepath.Rel with an empty dst returns an error "can't make relative to ...".
|
||||
if dst != "" {
|
||||
err = checkParent(src, dst)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
}
|
||||
|
||||
override := r.URL.Query().Get("override") == "true"
|
||||
rename := r.URL.Query().Get("rename") == "true"
|
||||
if !override && !rename {
|
||||
// Only check destination existence when a destination was provided.
|
||||
if dst != "" && !override && !rename {
|
||||
if _, err = d.user.Fs.Stat(dst); err == nil {
|
||||
return http.StatusConflict, nil
|
||||
}
|
||||
@@ -222,6 +238,28 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
|
||||
// Special-case metadata action because it needs the request body
|
||||
if action == "metadata" {
|
||||
if !d.user.Perm.Modify {
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
|
||||
var tags map[string]string
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
if err := json.Unmarshal(body, &tags); err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
err = d.RunHook(func() error {
|
||||
return applyMetadataWithFFmpeg(r.Context(), d, src, tags)
|
||||
}, action, src, dst, d.user)
|
||||
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
err = d.RunHook(func() error {
|
||||
return patchAction(r.Context(), action, src, dst, d, fileCache)
|
||||
}, action, src, dst, d.user)
|
||||
@@ -230,6 +268,81 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
|
||||
})
|
||||
}
|
||||
|
||||
// applyMetadataWithFFmpeg attempts to write metadata using ffmpeg by creating
|
||||
// a temporary file and replacing the original. This requires that the
|
||||
// underlying filesystem exposes a real path (see FileInfo.RealPath()).
|
||||
func applyMetadataWithFFmpeg(ctx context.Context, d *data, src string, tags map[string]string) error {
|
||||
fi, err := files.NewFileInfo(&files.FileOptions{
|
||||
Fs: d.user.Fs,
|
||||
Path: src,
|
||||
Modify: d.user.Perm.Modify,
|
||||
Expand: false,
|
||||
ReadHeader: false,
|
||||
Checker: d,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
real := fi.RealPath()
|
||||
// If RealPath returns the same virtual path, we cannot run ffmpeg on it.
|
||||
if real == "" || real == fi.Path {
|
||||
return fmt.Errorf("unable to obtain underlying real file path for %s: %w", fi.Path, fberrors.ErrInvalidRequestParams)
|
||||
}
|
||||
|
||||
// Ensure ffmpeg is available
|
||||
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||
return fmt.Errorf("ffmpeg not found: %w", err)
|
||||
}
|
||||
|
||||
dir := filepath.Dir(real)
|
||||
|
||||
// Create a unique temporary filename in the same directory and keep the
|
||||
// same extension as the original so ffmpeg can infer the output format.
|
||||
ext := filepath.Ext(real)
|
||||
tmp := filepath.Join(dir, fmt.Sprintf(".metadata_tmp_%d%s", time.Now().UnixNano(), ext))
|
||||
|
||||
// Ensure the temp file is removed on error
|
||||
defer func() {
|
||||
if _, statErr := os.Stat(tmp); statErr == nil {
|
||||
_ = os.Remove(tmp)
|
||||
}
|
||||
}()
|
||||
|
||||
// Build ffmpeg args to preserve existing metadata and override only the
|
||||
// provided non-empty fields. We explicitly map input global metadata (0)
|
||||
// to output, and avoid `-map_metadata -1` which would clear everything.
|
||||
args := []string{"-y", "-i", real, "-map_metadata", "0", "-c", "copy"}
|
||||
changes := 0
|
||||
for k, v := range tags {
|
||||
if strings.TrimSpace(v) == "" {
|
||||
continue
|
||||
}
|
||||
args = append(args, "-metadata", fmt.Sprintf("%s=%s", k, v))
|
||||
changes++
|
||||
}
|
||||
|
||||
// If no non-empty changes were requested, do nothing
|
||||
if changes == 0 {
|
||||
return nil
|
||||
}
|
||||
args = append(args, tmp)
|
||||
|
||||
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
|
||||
// Capture combined output to provide actionable errors when ffmpeg fails
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ffmpeg error: %w: %s", err, strings.TrimSpace(string(out)))
|
||||
}
|
||||
|
||||
// replace original
|
||||
if err := os.Rename(tmp, real); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkParent(src, dst string) error {
|
||||
rel, err := filepath.Rel(src, dst)
|
||||
if err != nil {
|
||||
@@ -280,6 +393,12 @@ func writeFile(afs afero.Fs, dst string, in io.Reader, fileMode, dirMode fs.File
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sync the file to ensure all data is written to storage.
|
||||
// to prevent file corruption.
|
||||
if err := file.Sync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Gets the info about the file.
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
|
||||
@@ -256,6 +256,12 @@ func tusPatchHandler() handleFunc {
|
||||
return http.StatusInternalServerError, fmt.Errorf("could not write to file: %w", err)
|
||||
}
|
||||
|
||||
// Sync the file to ensure all data is written to storage
|
||||
// to prevent file corruption.
|
||||
if err := openFile.Sync(); err != nil {
|
||||
return http.StatusInternalServerError, fmt.Errorf("could not sync file: %w", err)
|
||||
}
|
||||
|
||||
newOffset := uploadOffset + bytesWritten
|
||||
w.Header().Set("Upload-Offset", strconv.FormatInt(newOffset, 10))
|
||||
|
||||
|
||||
@@ -103,7 +103,25 @@ var userGetHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
|
||||
return renderJSON(w, r, u)
|
||||
})
|
||||
|
||||
var userDeleteHandler = withSelfOrAdmin(func(_ http.ResponseWriter, _ *http.Request, d *data) (int, error) {
|
||||
var userDeleteHandler = withSelfOrAdmin(func(_ http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
if r.Body == nil {
|
||||
return http.StatusBadRequest, fberrors.ErrEmptyRequest
|
||||
}
|
||||
|
||||
var body struct {
|
||||
CurrentPassword string `json:"current_password"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
if d.settings.AuthMethod == auth.MethodJSONAuth {
|
||||
if !users.CheckPwd(body.CurrentPassword, d.user.Password) {
|
||||
return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect
|
||||
}
|
||||
}
|
||||
|
||||
err := d.store.Users.Delete(d.raw.(uint))
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "filebrowser",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
@@ -8,16 +8,17 @@ import (
|
||||
// UserDefaults is a type that holds the default values
|
||||
// for some fields on User.
|
||||
type UserDefaults struct {
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
RedirectAfterCopyMove bool `json:"redirectAfterCopyMove"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
}
|
||||
|
||||
// Apply applies the default options to a user.
|
||||
@@ -26,6 +27,7 @@ func (d *UserDefaults) Apply(u *users.User) {
|
||||
u.Locale = d.Locale
|
||||
u.ViewMode = d.ViewMode
|
||||
u.SingleClick = d.SingleClick
|
||||
u.RedirectAfterCopyMove = d.RedirectAfterCopyMove
|
||||
u.Perm = d.Perm
|
||||
u.Sorting = d.Sorting
|
||||
u.Commands = d.Commands
|
||||
|
||||
75
start-dev.sh
Executable file
75
start-dev.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||
export PATH="$HOME/.local/go/bin:$PATH"
|
||||
|
||||
echo "Project root: $PROJECT_ROOT"
|
||||
|
||||
# Stop any existing dev servers first
|
||||
if [ -x "$PROJECT_ROOT/stop-dev.sh" ]; then
|
||||
echo "Stopping existing dev servers..."
|
||||
"$PROJECT_ROOT/stop-dev.sh" || true
|
||||
fi
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
echo "Starting backend..."
|
||||
if [ -f filebrowser.log ]; then
|
||||
mv filebrowser.log filebrowser.log.$(date +%s)
|
||||
fi
|
||||
nohup go run main.go > filebrowser.log 2>&1 &
|
||||
backend_pid=$!
|
||||
echo $backend_pid > filebrowser.pid
|
||||
echo "Backend pid: $backend_pid"
|
||||
|
||||
echo "Waiting for backend to listen on 127.0.0.1:8080..."
|
||||
for i in $(seq 1 15); do
|
||||
if ss -ltn | grep -q "127.0.0.1:8080"; then
|
||||
echo "Backend listening."
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Starting frontend (Vite)..."
|
||||
if [ ! -d "$PROJECT_ROOT/frontend" ]; then
|
||||
echo "ERROR: frontend directory not found: $PROJECT_ROOT/frontend"
|
||||
exit 1
|
||||
fi
|
||||
cd "$PROJECT_ROOT/frontend"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
if command -v pnpm >/dev/null 2>&1; then
|
||||
pnpm install --no-audit --no-fund
|
||||
else
|
||||
npm install --no-audit --no-fund
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$PROJECT_ROOT/frontend-dev.log" ]; then
|
||||
mv "$PROJECT_ROOT/frontend-dev.log" "$PROJECT_ROOT/frontend-dev.log.$(date +%s)"
|
||||
fi
|
||||
|
||||
if command -v pnpm >/dev/null 2>&1; then
|
||||
nohup pnpm run dev > "$PROJECT_ROOT/frontend-dev.log" 2>&1 &
|
||||
frontend_pid=$!
|
||||
else
|
||||
nohup npm run dev > "$PROJECT_ROOT/frontend-dev.log" 2>&1 &
|
||||
frontend_pid=$!
|
||||
fi
|
||||
echo $frontend_pid > "$PROJECT_ROOT/frontend.pid"
|
||||
echo "Frontend pid: $frontend_pid"
|
||||
|
||||
echo "Waiting for frontend on 5173..."
|
||||
for i in $(seq 1 10); do
|
||||
if ss -ltn | grep -q ":5173"; then
|
||||
echo "Frontend listening."
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Started. Backend logs: $PROJECT_ROOT/filebrowser.log"
|
||||
echo "Frontend logs: $PROJECT_ROOT/frontend-dev.log"
|
||||
echo "Open http://localhost:5173/ to use the dev UI"
|
||||
51
stop-dev.sh
Executable file
51
stop-dev.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
echo "Stopping dev servers (project root: $PROJECT_ROOT)"
|
||||
|
||||
# Kill backend from pid file
|
||||
if [ -f "$PROJECT_ROOT/filebrowser.pid" ]; then
|
||||
pid=$(cat "$PROJECT_ROOT/filebrowser.pid")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo "Killing backend pid $pid"
|
||||
kill "$pid" || true
|
||||
sleep 1
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill -9 "$pid" || true
|
||||
fi
|
||||
fi
|
||||
rm -f "$PROJECT_ROOT/filebrowser.pid"
|
||||
fi
|
||||
|
||||
# Kill frontend from pid file
|
||||
if [ -f "$PROJECT_ROOT/frontend.pid" ]; then
|
||||
pid=$(cat "$PROJECT_ROOT/frontend.pid")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo "Killing frontend pid $pid"
|
||||
kill "$pid" || true
|
||||
sleep 1
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill -9 "$pid" || true
|
||||
fi
|
||||
fi
|
||||
rm -f "$PROJECT_ROOT/frontend.pid"
|
||||
fi
|
||||
|
||||
# Also attempt to free ports 8080 and 5173 by killing processes listening on them (best-effort)
|
||||
pids=$(ss -ltnp | grep -E '127\.0\.0\.1:8080|:5173' | grep -oP 'pid=\K[0-9]+' | sort -u || true)
|
||||
for p in $pids; do
|
||||
if [ -n "$p" ]; then
|
||||
if kill -0 "$p" 2>/dev/null; then
|
||||
echo "Killing leftover pid $p"
|
||||
kill "$p" || true
|
||||
sleep 1
|
||||
if kill -0 "$p" 2>/dev/null; then
|
||||
kill -9 "$p" || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Stopped."
|
||||
@@ -20,22 +20,23 @@ const (
|
||||
|
||||
// User describes a user.
|
||||
type User struct {
|
||||
ID uint `storm:"id,increment" json:"id"`
|
||||
Username string `storm:"unique" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Fs afero.Fs `json:"-" yaml:"-"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
ID uint `storm:"id,increment" json:"id"`
|
||||
Username string `storm:"unique" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
RedirectAfterCopyMove bool `json:"redirectAfterCopyMove"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Fs afero.Fs `json:"-" yaml:"-"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
}
|
||||
|
||||
// GetRules implements rules.Provider.
|
||||
|
||||
@@ -61,6 +61,7 @@ filebrowser config init [flags]
|
||||
--recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
|
||||
--recaptcha.key string ReCaptcha site key
|
||||
--recaptcha.secret string ReCaptcha secret
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
-r, --root string root to prepend to relative paths (default ".")
|
||||
--scope string scope for users (default ".")
|
||||
--shell string shell command to which other commands should be appended
|
||||
|
||||
@@ -58,6 +58,7 @@ filebrowser config set [flags]
|
||||
--recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
|
||||
--recaptcha.key string ReCaptcha site key
|
||||
--recaptcha.secret string ReCaptcha secret
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
-r, --root string root to prepend to relative paths (default ".")
|
||||
--scope string scope for users (default ".")
|
||||
--shell string shell command to which other commands should be appended
|
||||
|
||||
@@ -28,6 +28,7 @@ filebrowser users add <username> <password> [flags]
|
||||
--perm.modify modify perm for users (default true)
|
||||
--perm.rename rename perm for users (default true)
|
||||
--perm.share share perm for users (default true)
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
--scope string scope for users (default ".")
|
||||
--singleClick use single clicks only
|
||||
--sorting.asc sorting by ascending order
|
||||
|
||||
@@ -30,6 +30,7 @@ filebrowser users update <id|username> [flags]
|
||||
--perm.modify modify perm for users (default true)
|
||||
--perm.rename rename perm for users (default true)
|
||||
--perm.share share perm for users (default true)
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
--scope string scope for users (default ".")
|
||||
--singleClick use single clicks only
|
||||
--sorting.asc sorting by ascending order
|
||||
|
||||
Reference in New Issue
Block a user