Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3e31f8822e
|
|||
|
6cff4247a8
|
|||
|
90ff1382a8
|
|||
|
1450357b91
|
|||
|
7a31c36c10
|
|||
|
5271c12525
|
|||
|
d278e4009d
|
|||
|
e3d80ffc2a
|
|||
|
30a8fbad4e
|
|||
|
e7bc625b6d
|
|||
|
2d71e7b0cb
|
|||
|
2297f87fa3
|
|||
|
271c7e5c13
|
|||
|
9fdea6b169
|
|||
|
38e20044e2
|
|||
|
830cbae17a
|
|||
|
51fee5bfe0
|
|||
|
e40fd2625f
|
|||
|
061ef9bdc9
|
|||
|
d478923ce0
|
|||
|
e4032069a5
|
|||
|
73da4f8dc5
|
|||
|
89ff2bf452
|
|||
|
d0f6d19a7e
|
|||
|
977b3e02e9
|
|||
|
a6d82c1f47
|
18
.drone.yml
Normal file
18
.drone.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: frontend-web
|
||||
image: node:19
|
||||
commands:
|
||||
- cd web
|
||||
- npm install
|
||||
- npm run build
|
||||
|
||||
- name: release
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
api_key: da966507c259aa32ccc2d434e930af4a580de785
|
||||
base_url: https://yongyuancv.cn/git/
|
||||
files: build/*
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 16
|
||||
- name: Build web front end
|
||||
run: |
|
||||
make web
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"api": {
|
||||
"secret": "CHANGE_YOUR_SECRET_HERE",
|
||||
"database_name": "music.sqlite3",
|
||||
"database_name": "postgres://postgres:woshimima@localhost/postgres?sslmode=disable",
|
||||
"single_thread": true,
|
||||
"addr": ":8080",
|
||||
"ffmpeg_threads": 1,
|
||||
|
||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/mattn/go-sqlite3 v1.14.14
|
||||
github.com/lib/pq v1.10.7
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
)
|
||||
|
||||
|
||||
4
go.sum
4
go.sum
@@ -2,7 +2,7 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
|
||||
@@ -59,6 +59,7 @@ func NewAPI(config commonconfig.Config) (*API, error) {
|
||||
apiMux.HandleFunc("/get_file_info", api.HandleGetFileInfo)
|
||||
apiMux.HandleFunc("/get_file_ffprobe_info", api.HandleGetFileFfprobeInfo)
|
||||
apiMux.HandleFunc("/get_file_stream_direct", api.HandleGetFileStreamDirect)
|
||||
apiMux.HandleFunc("/get_file_avatar", api.HandelGetFileAvatar)
|
||||
apiMux.HandleFunc("/prepare_file_stream_direct", api.HandlePrepareFileStreamDirect)
|
||||
apiMux.HandleFunc("/delete_file", api.HandleDeleteFile)
|
||||
apiMux.HandleFunc("/update_filename", api.HandleUpdateFilename)
|
||||
|
||||
108
pkg/api/handle_avatar.go
Normal file
108
pkg/api/handle_avatar.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"msw-open-music/pkg/database"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (api *API) HandelGetFileAvatar(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
q := r.URL.Query()
|
||||
ids := q["id"]
|
||||
if len(ids) == 0 {
|
||||
err = errors.New(`parameter "id" can't be empty`)
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
id, err := strconv.Atoi(ids[0])
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
file, err := api.Db.GetFile(int64(id))
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
path, err := file.Path()
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
log.Println("[api] Get avatar of file", path)
|
||||
buff := make([]byte, 0)
|
||||
cache := bytes.NewBuffer(buff)
|
||||
cmd := exec.Command("ffmpeg", "-i", path, "-c:v", "libwebp_anim", "-update", "1", "-frames:v", "1", "-f", "image2pipe", "-")
|
||||
cmd.Stdout = cache
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
api.HandleGetAlternativeFileAvatar(w, r, file)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "image/webp")
|
||||
io.Copy(w, cache)
|
||||
}
|
||||
|
||||
func (api *API) HandleGetAlternativeFileAvatar(w http.ResponseWriter, r *http.Request, f *database.File) {
|
||||
var err error
|
||||
dir, err := f.Dir()
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
log.Println("[api] Get alternative avatar in dir", dir)
|
||||
files, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
avatar, err := findAvatarFile(files)
|
||||
avatarPath := path.Join(dir, avatar)
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
cmd := exec.Command("ffmpeg", "-i", avatarPath, "-c:v", "libwebp_anim", "-f", "image2pipe", "-")
|
||||
cmd.Stdout = w
|
||||
w.Header().Set("Content-Type", "image/webp")
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func findAvatarFile(files []os.DirEntry) (string, error) {
|
||||
for _, file := range files {
|
||||
if isAvatarType(file.Name()) {
|
||||
return file.Name(), nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("Cannot find avatar file")
|
||||
}
|
||||
|
||||
var avatarFileTypes = []string{
|
||||
".jpg",
|
||||
".png",
|
||||
}
|
||||
|
||||
func isAvatarType(filename string) bool {
|
||||
for _, t := range avatarFileTypes {
|
||||
if strings.HasSuffix(strings.ToLower(filename), t) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"msw-open-music/pkg/database"
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -35,6 +36,12 @@ func (api *API) HandleRecordPlayback(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("[api] Record playback history",
|
||||
recordPlaybackRequest.Playback.UserID,
|
||||
recordPlaybackRequest.Playback.FileID,
|
||||
recordPlaybackRequest.Playback.Duration,
|
||||
recordPlaybackRequest.Playback.Method)
|
||||
|
||||
err = api.Db.RecordPlayback(recordPlaybackRequest.Playback)
|
||||
if err != nil {
|
||||
api.HandleError(w, r, err)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"sync"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
@@ -41,7 +41,7 @@ func NewDatabase(dbName string, singleThread bool) (*Database, error) {
|
||||
var err error
|
||||
|
||||
// open database
|
||||
sqlConn, err := sql.Open("sqlite3", dbName)
|
||||
sqlConn, err := sql.Open("postgres", dbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ func (database *Database) Walk(root string, pattern []string, tagIDs []int64, us
|
||||
insertFileStmt := tx.Stmt(database.stmt.insertFile)
|
||||
putTagOnFileStmt := tx.Stmt(database.stmt.putTagOnFile)
|
||||
findFolderStmt := tx.Stmt(database.stmt.findFolder)
|
||||
findFileStmt := tx.Stmt(database.stmt.findFile)
|
||||
|
||||
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
@@ -194,22 +195,41 @@ func (database *Database) Walk(root string, pattern []string, tagIDs []int64, us
|
||||
folder, filename := filepath.Split(path)
|
||||
err = findFolderStmt.QueryRow(folder).Scan(&folderID)
|
||||
if err != nil {
|
||||
result, err := insertFolderStmt.Exec(folder, filepath.Base(folder))
|
||||
result, err := insertFolderStmt.Query(folder, filepath.Base(folder))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
folderID, err = result.LastInsertId()
|
||||
for result.Next() {
|
||||
err = result.Scan(&folderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try find file id
|
||||
var fileID int64
|
||||
result, err := findFileStmt.Query(folderID, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for result.Next() {
|
||||
err = result.Scan(&fileID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
result, err := insertFileStmt.Exec(folderID, filename, filename, info.Size())
|
||||
|
||||
// insert new file
|
||||
result, err = insertFileStmt.Query(folderID, filename, filename, info.Size())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileID, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
for result.Next() {
|
||||
err = result.Scan(&fileID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
|
||||
@@ -6,11 +6,17 @@ func (database *Database) InsertTag(tag *Tag) (int64, error) {
|
||||
database.singleThreadLock.Lock()
|
||||
defer database.singleThreadLock.Unlock()
|
||||
|
||||
result, err := database.stmt.insertTag.Exec(tag.Name, tag.Description, tag.CreatedByUserId)
|
||||
result, err := database.stmt.insertTag.Query(tag.Name, tag.Description, tag.CreatedByUserId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id, err := result.LastInsertId()
|
||||
var id int64
|
||||
for result.Next() {
|
||||
err = result.Scan(&id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -6,22 +6,22 @@ import (
|
||||
)
|
||||
|
||||
var initFilesTableQuery = `CREATE TABLE IF NOT EXISTS files (
|
||||
id INTEGER PRIMARY KEY,
|
||||
folder_id INTEGER NOT NULL,
|
||||
id SERIAL PRIMARY KEY,
|
||||
folder_id INTEGER NOT NULL REFERENCES folders(id),
|
||||
realname TEXT NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filesize INTEGER NOT NULL,
|
||||
FOREIGN KEY(folder_id) REFERENCES folders(id)
|
||||
UNIQUE (folder_id, realname)
|
||||
);`
|
||||
|
||||
var initFoldersTableQuery = `CREATE TABLE IF NOT EXISTS folders (
|
||||
id INTEGER PRIMARY KEY,
|
||||
folder TEXT NOT NULL,
|
||||
id SERIAL PRIMARY KEY,
|
||||
folder TEXT NOT NULL UNIQUE,
|
||||
foldername TEXT NOT NULL
|
||||
);`
|
||||
|
||||
var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id SERIAL PRIMARY KEY,
|
||||
time INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
@@ -30,108 +30,101 @@ var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks (
|
||||
|
||||
// User table schema definition
|
||||
// role: 0 - Anonymous User, 1 - Admin, 2 - User
|
||||
// postgres avatar references problem
|
||||
var initUsersTableQuery = `CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id SERIAL PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password TEXT NOT NULL,
|
||||
role INTEGER NOT NULL,
|
||||
active BOOLEAN NOT NULL,
|
||||
avatar_id INTEGER NOT NULL,
|
||||
FOREIGN KEY(avatar_id) REFERENCES avatars(id)
|
||||
avatar_id INTEGER NOT NULL DEFAULT 0
|
||||
);`
|
||||
|
||||
var initAvatarsTableQuery = `CREATE TABLE IF NOT EXISTS avatars (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id SERIAL PRIMARY KEY,
|
||||
avatarname TEXT NOT NULL,
|
||||
avatar BLOB NOT NULL
|
||||
avatar BYTEA NOT NULL
|
||||
);`
|
||||
|
||||
var initTagsTableQuery = `CREATE TABLE IF NOT EXISTS tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT NOT NULL,
|
||||
created_by_user_id INTEGER NOT NULL,
|
||||
FOREIGN KEY(created_by_user_id) REFERENCES users(id)
|
||||
created_by_user_id INTEGER NOT NULL REFERENCES users(id)
|
||||
);`
|
||||
|
||||
var initFileHasTagTableQuery = `CREATE TABLE IF NOT EXISTS file_has_tag (
|
||||
file_id INTEGER NOT NULL,
|
||||
tag_id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (file_id, tag_id),
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
FOREIGN KEY (file_id) REFERENCES files(id),
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(id)
|
||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
||||
tag_id INTEGER NOT NULL REFERENCES tags(id),
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
PRIMARY KEY (file_id, tag_id)
|
||||
);`
|
||||
|
||||
var initLikesTableQuery = `CREATE TABLE IF NOT EXISTS likes (
|
||||
user_id INTEGER NOT NULL,
|
||||
file_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (user_id, file_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
||||
PRIMARY KEY (user_id, file_id)
|
||||
);`
|
||||
|
||||
var initReviewsTableQuery = `CREATE TABLE IF NOT EXISTS reviews (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
file_id INTEGER NOT NULL,
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL DEFAULT 0,
|
||||
content TEXT NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||
content TEXT NOT NULL
|
||||
);`
|
||||
|
||||
var initPlaybacksTableQuery = `CREATE TABLE IF NOT EXISTS playbacks (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
file_id INTEGER NOT NULL,
|
||||
time INTEGER NOT NULL,
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
||||
time TIMESTAMP NOT NULL,
|
||||
method INTEGER NOT NULL,
|
||||
duration INTEGER NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||
duration INTERVAL NOT NULL
|
||||
);`
|
||||
|
||||
var initLogsTableQuery = `CREATE TABLE IF NOT EXISTS logs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id SERIAL PRIMARY KEY,
|
||||
time INTEGER NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
user_id INTEGER NOT NULL REFERENCES users(id)
|
||||
);`
|
||||
|
||||
var initTmpfsTableQuery = `CREATE TABLE IF NOT EXISTS tmpfs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id SERIAL PRIMARY KEY,
|
||||
path TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
file_id INTEGER NOT NULL,
|
||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
||||
ffmpeg_config TEXT NOT NULL,
|
||||
created_time INTEGER NOT NULL,
|
||||
accessed_time INTEGER NOT NULL,
|
||||
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||
accessed_time INTEGER NOT NULL
|
||||
);`
|
||||
|
||||
var insertFolderQuery = `INSERT INTO folders (folder, foldername)
|
||||
VALUES (?, ?);`
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id;
|
||||
;`
|
||||
|
||||
var findFolderQuery = `SELECT id FROM folders WHERE folder = ? LIMIT 1;`
|
||||
var findFolderQuery = `SELECT id FROM folders WHERE folder = $1 LIMIT 1;`
|
||||
|
||||
var findFileQuery = `SELECT id FROM files WHERE folder_id = ? AND realname = ? LIMIT 1;`
|
||||
var findFileQuery = `SELECT id FROM files WHERE folder_id = $1 AND realname = $2 LIMIT 1;`
|
||||
|
||||
var insertFileQuery = `INSERT INTO files (folder_id, realname, filename, filesize)
|
||||
VALUES (?, ?, ?, ?);`
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id;`
|
||||
|
||||
var searchFilesQuery = `SELECT
|
||||
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
||||
FROM files
|
||||
JOIN folders ON files.folder_id = folders.id
|
||||
WHERE filename LIKE ?
|
||||
WHERE filename ILIKE $1
|
||||
ORDER BY folders.foldername, files.filename
|
||||
LIMIT ? OFFSET ?;`
|
||||
LIMIT $2 OFFSET $3;`
|
||||
|
||||
var getFolderQuery = `SELECT folder FROM folders WHERE id = ? LIMIT 1;`
|
||||
var getFolderQuery = `SELECT folder FROM folders WHERE id = $1 LIMIT 1;`
|
||||
|
||||
var dropFilesQuery = `DROP TABLE files;`
|
||||
|
||||
@@ -141,42 +134,42 @@ var getFileQuery = `SELECT
|
||||
files.id, files.folder_id, files.realname, files.filename, folders.foldername, files.filesize
|
||||
FROM files
|
||||
JOIN folders ON files.folder_id = folders.id
|
||||
WHERE files.id = ?
|
||||
WHERE files.id = $1
|
||||
LIMIT 1;`
|
||||
|
||||
var searchFoldersQuery = `SELECT
|
||||
id, folder, foldername
|
||||
FROM folders
|
||||
WHERE foldername LIKE ?
|
||||
WHERE foldername ILIKE $1
|
||||
ORDER BY foldername
|
||||
LIMIT ? OFFSET ?;`
|
||||
LIMIT $2 OFFSET $3;`
|
||||
|
||||
var getFilesInFolderQuery = `SELECT
|
||||
files.id, files.filename, files.filesize, folders.foldername, folders.folder
|
||||
FROM files
|
||||
JOIN folders ON files.folder_id = folders.id
|
||||
WHERE folder_id = ?
|
||||
WHERE folder_id = $1
|
||||
ORDER BY files.filename
|
||||
LIMIT ? OFFSET ?;`
|
||||
LIMIT $2 OFFSET $3;`
|
||||
|
||||
var getRandomFilesQuery = `SELECT
|
||||
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
||||
FROM files
|
||||
JOIN folders ON files.folder_id = folders.id
|
||||
ORDER BY RANDOM()
|
||||
LIMIT ?;`
|
||||
LIMIT $1;`
|
||||
|
||||
var getRandomFilesWithTagQuery = `SELECT
|
||||
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
||||
FROM file_has_tag
|
||||
JOIN files ON file_has_tag.file_id = files.id
|
||||
JOIN folders ON files.folder_id = folders.id
|
||||
WHERE file_has_tag.tag_id = ?
|
||||
WHERE file_has_tag.tag_id = $1
|
||||
ORDER BY RANDOM()
|
||||
LIMIT ?;`
|
||||
LIMIT $2;`
|
||||
|
||||
var insertFeedbackQuery = `INSERT INTO feedbacks (time, content, user_id, header)
|
||||
VALUES (?, ?, ?, ?);`
|
||||
VALUES ($1, $2, $3, $4);`
|
||||
|
||||
var getFeedbacksQuery = `SELECT
|
||||
feedbacks.id, feedbacks.time, feedbacks.content, feedbacks.header,
|
||||
@@ -186,39 +179,39 @@ JOIN users ON feedbacks.user_id = users.id
|
||||
ORDER BY feedbacks.time
|
||||
;`
|
||||
|
||||
var deleteFeedbackQuery = `DELETE FROM feedbacks WHERE id = ?;`
|
||||
var deleteFeedbackQuery = `DELETE FROM feedbacks WHERE id = $1;`
|
||||
|
||||
var insertUserQuery = `INSERT INTO users (username, password, role, active, avatar_id)
|
||||
VALUES (?, ?, ?, ?, ?);`
|
||||
VALUES ($1, $2, $3, $4, $5);`
|
||||
|
||||
var countUserQuery = `SELECT count(*) FROM users;`
|
||||
|
||||
var countAdminQuery = `SELECT count(*) FROM users WHERE role= 1;`
|
||||
|
||||
var getUserQuery = `SELECT id, username, password, role, active, avatar_id FROM users WHERE username = ? LIMIT 1;`
|
||||
var getUserQuery = `SELECT id, username, password, role, active, avatar_id FROM users WHERE username = $1 LIMIT 1;`
|
||||
|
||||
var getUsersQuery = `SELECT id, username, role, active, avatar_id FROM users;`
|
||||
|
||||
var getUserByIdQuery = `SELECT id, username, role, active, avatar_id FROM users WHERE id = ? LIMIT 1;`
|
||||
var getUserByIdQuery = `SELECT id, username, role, active, avatar_id FROM users WHERE id = $1 LIMIT 1;`
|
||||
|
||||
var updateUserActiveQuery = `UPDATE users SET active = ? WHERE id = ?;`
|
||||
var updateUserActiveQuery = `UPDATE users SET active = $1 WHERE id = $2;`
|
||||
|
||||
var updateUsernameQuery = `UPDATE users SET username = ? WHERE id = ?;`
|
||||
var updateUsernameQuery = `UPDATE users SET username = $1 WHERE id = $2;`
|
||||
|
||||
var updateUserPasswordQuery = `UPDATE users SET password = ? WHERE id = ?;`
|
||||
var updateUserPasswordQuery = `UPDATE users SET password = $1 WHERE id = $2;`
|
||||
|
||||
var getAnonymousUserQuery = `SELECT id, username, role, avatar_id FROM users WHERE role = 0 LIMIT 1;`
|
||||
|
||||
var insertTagQuery = `INSERT INTO tags (name, description, created_by_user_id) VALUES (?, ?, ?);`
|
||||
var insertTagQuery = `INSERT INTO tags (name, description, created_by_user_id) VALUES ($1, $2, $3) RETURNING id;`
|
||||
|
||||
var deleteTagQuery = `DELETE FROM tags WHERE id = ?;`
|
||||
var deleteTagQuery = `DELETE FROM tags WHERE id = $1;`
|
||||
|
||||
var getTagQuery = `SELECT
|
||||
tags.id, tags.name, tags.description,
|
||||
users.id, users.username, users.role, users.avatar_id
|
||||
FROM tags
|
||||
JOIN users ON tags.created_by_user_id = users.id
|
||||
WHERE tags.id = ? LIMIT 1;`
|
||||
WHERE tags.id = $1 LIMIT 1;`
|
||||
|
||||
var getTagsQuery = `SELECT
|
||||
tags.id, tags.name, tags.description,
|
||||
@@ -228,26 +221,27 @@ JOIN users ON tags.created_by_user_id = users.id
|
||||
ORDER BY tags.name
|
||||
;`
|
||||
|
||||
var updateTagQuery = `UPDATE tags SET name = ?, description = ? WHERE id = ?;`
|
||||
var updateTagQuery = `UPDATE tags SET name = $1, description = $2 WHERE id = $3;`
|
||||
|
||||
var putTagOnFileQuery = `INSERT OR IGNORE INTO file_has_tag (tag_id, file_id, user_id) VALUES (?, ?, ?);`
|
||||
// postgres INSERT IGNORE
|
||||
var putTagOnFileQuery = `INSERT INTO file_has_tag (tag_id, file_id, user_id) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;`
|
||||
|
||||
var getTagsOnFileQuery = `SELECT
|
||||
tags.id, tags.name, tags.description, tags.created_by_user_id
|
||||
FROM file_has_tag
|
||||
JOIN tags ON file_has_tag.tag_id = tags.id
|
||||
WHERE file_has_tag.file_id = ?
|
||||
WHERE file_has_tag.file_id = $1
|
||||
ORDER BY tags.name
|
||||
;`
|
||||
|
||||
var deleteTagOnFileQuery = `DELETE FROM file_has_tag WHERE tag_id = ? AND file_id = ?;`
|
||||
var deleteTagOnFileQuery = `DELETE FROM file_has_tag WHERE tag_id = $1 AND file_id = $2;`
|
||||
|
||||
var deleteTagReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE tag_id = ?;`
|
||||
var deleteTagReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE tag_id = $1;`
|
||||
|
||||
var updateFoldernameQuery = `UPDATE folders SET foldername = ? WHERE id = ?;`
|
||||
var updateFoldernameQuery = `UPDATE folders SET foldername = $1 WHERE id = $2;`
|
||||
|
||||
var insertReviewQuery = `INSERT INTO reviews (user_id, file_id, created_at, content)
|
||||
VALUES (?, ?, ?, ?);`
|
||||
VALUES ($1, $2, $3, $4);`
|
||||
|
||||
var getReviewsOnFileQuery = `SELECT
|
||||
reviews.id, reviews.created_at, reviews.updated_at, reviews.content,
|
||||
@@ -256,15 +250,15 @@ files.id, files.filename
|
||||
FROM reviews
|
||||
JOIN users ON reviews.user_id = users.id
|
||||
JOIN files ON reviews.file_id = files.id
|
||||
WHERE reviews.file_id = ?
|
||||
WHERE reviews.file_id = $1
|
||||
ORDER BY reviews.created_at
|
||||
;`
|
||||
|
||||
var getReviewQuery = `SELECT id, file_id, user_id, created_at, updated_at, content FROM reviews WHERE id = ? LIMIT 1;`
|
||||
var getReviewQuery = `SELECT id, file_id, user_id, created_at, updated_at, content FROM reviews WHERE id = $1 LIMIT 1;`
|
||||
|
||||
var updateReviewQuery = `UPDATE reviews SET content = ?, updated_at = ? WHERE id = ?;`
|
||||
var updateReviewQuery = `UPDATE reviews SET content = $1, updated_at = $2 WHERE id = $3;`
|
||||
|
||||
var deleteReviewQuery = `DELETE FROM reviews WHERE id = ?;`
|
||||
var deleteReviewQuery = `DELETE FROM reviews WHERE id = $1;`
|
||||
|
||||
var getReviewsByUserQuery = `SELECT
|
||||
reviews.id, reviews.created_at, reviews.updated_at, reviews.content,
|
||||
@@ -273,19 +267,19 @@ files.id, files.filename
|
||||
FROM reviews
|
||||
JOIN users ON reviews.user_id = users.id
|
||||
JOIN files ON reviews.file_id = files.id
|
||||
WHERE reviews.user_id = ?
|
||||
WHERE reviews.user_id = $1
|
||||
ORDER BY reviews.created_at
|
||||
;`
|
||||
|
||||
var deleteFileQuery = `DELETE FROM files WHERE id = ?;`
|
||||
var deleteFileQuery = `DELETE FROM files WHERE id = $1;`
|
||||
|
||||
var deleteFileReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE file_id = ?;`
|
||||
var deleteFileReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE file_id = $1;`
|
||||
|
||||
var deleteFileReferenceInReviewsQuery = `DELETE FROM reviews WHERE file_id = ?;`
|
||||
var deleteFileReferenceInReviewsQuery = `DELETE FROM reviews WHERE file_id = $1;`
|
||||
|
||||
var updateFilenameQuery = `UPDATE files SET filename = ? WHERE id = ?;`
|
||||
var updateFilenameQuery = `UPDATE files SET filename = $1 WHERE id = $2;`
|
||||
|
||||
var resetFilenameQuery = `UPDATE files SET filename = realname WHERE id = ?;`
|
||||
var resetFilenameQuery = `UPDATE files SET filename = realname WHERE id = $1;`
|
||||
|
||||
var recordPlaybackQuery = `INSERT INTO playbacks (user_id, file_id, time, method, duration) VALUES ($1, $2, $3, $4, $5);`
|
||||
|
||||
@@ -357,26 +351,22 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
||||
|
||||
stmt := &Stmt{}
|
||||
|
||||
// init files table
|
||||
stmt.initFilesTable, err = sqlConn.Prepare(initFilesTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init folders table
|
||||
stmt.initFoldersTable, err = sqlConn.Prepare(initFoldersTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init feedbacks tables
|
||||
stmt.initFeedbacksTable, err = sqlConn.Prepare(initFeedbacksTableQuery)
|
||||
_, err = stmt.initFoldersTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init users table
|
||||
stmt.initUsersTable, err = sqlConn.Prepare(initUsersTableQuery)
|
||||
// init files table
|
||||
stmt.initFilesTable, err = sqlConn.Prepare(initFilesTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initFilesTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -386,99 +376,103 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initAvatarsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init users table
|
||||
stmt.initUsersTable, err = sqlConn.Prepare(initUsersTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initUsersTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init feedbacks tables
|
||||
stmt.initFeedbacksTable, err = sqlConn.Prepare(initFeedbacksTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initFeedbacksTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init tags table
|
||||
stmt.initTagsTable, err = sqlConn.Prepare(initTagsTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initTagsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init file_has_tag table
|
||||
stmt.initFileHasTag, err = sqlConn.Prepare(initFileHasTagTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initFileHasTag.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init likes table
|
||||
stmt.initLikesTable, err = sqlConn.Prepare(initLikesTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initLikesTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init reviews table
|
||||
stmt.initReviewsTable, err = sqlConn.Prepare(initReviewsTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initReviewsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init playbacks table
|
||||
stmt.initPlaybacksTable, err = sqlConn.Prepare(initPlaybacksTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initPlaybacksTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init logs table
|
||||
stmt.initLogsTable, err = sqlConn.Prepare(initLogsTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initLogsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init tmpfs table
|
||||
stmt.initTmpfsTable, err = sqlConn.Prepare(initTmpfsTableQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// run init statement
|
||||
_, err = stmt.initFilesTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initFoldersTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initFeedbacksTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initUsersTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initAvatarsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initTagsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initFileHasTag.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initLikesTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initReviewsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initPlaybacksTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initLogsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.initTmpfsTable.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("Init tables finished")
|
||||
|
||||
// init insert folder statement
|
||||
stmt.insertFolder, err = sqlConn.Prepare(insertFolderQuery)
|
||||
if err != nil {
|
||||
|
||||
@@ -6,13 +6,14 @@ import (
|
||||
)
|
||||
|
||||
type File struct {
|
||||
Db *Database `json:"-"`
|
||||
ID int64 `json:"id"`
|
||||
Folder_id int64 `json:"folder_id"`
|
||||
Foldername string `json:"foldername"`
|
||||
Realname string `json:"-"`
|
||||
Filename string `json:"filename"`
|
||||
Filesize int64 `json:"filesize"`
|
||||
Db *Database `json:"-"`
|
||||
ID int64 `json:"id"`
|
||||
Folder_id int64 `json:"folder_id"`
|
||||
Foldername string `json:"foldername"`
|
||||
Realname string `json:"-"`
|
||||
Filename string `json:"filename"`
|
||||
Filesize int64 `json:"filesize"`
|
||||
folderCache *Folder
|
||||
}
|
||||
|
||||
type Folder struct {
|
||||
@@ -75,9 +76,23 @@ var (
|
||||
)
|
||||
|
||||
func (f *File) Path() (string, error) {
|
||||
folder, err := f.Db.GetFolder(f.Folder_id)
|
||||
var err error
|
||||
if f.folderCache == nil {
|
||||
f.folderCache, err = f.Db.GetFolder(f.Folder_id)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(folder.Folder, f.Realname), nil
|
||||
return filepath.Join(f.folderCache.Folder, f.Realname), nil
|
||||
}
|
||||
|
||||
func (f *File) Dir() (string, error) {
|
||||
var err error
|
||||
if f.folderCache == nil {
|
||||
f.folderCache, err = f.Db.GetFolder(f.Folder_id)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return f.folderCache.Folder, nil
|
||||
}
|
||||
|
||||
@@ -3,11 +3,19 @@ html {
|
||||
}
|
||||
body {
|
||||
margin: auto;
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
max-width: unset;
|
||||
min-height: 100vh;
|
||||
}
|
||||
#root {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.base {
|
||||
display: grid;
|
||||
grid-row-gap: 1em;
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
}
|
||||
.header {
|
||||
color: white;
|
||||
|
||||
@@ -28,6 +28,27 @@ function App() {
|
||||
const [user, setUser] = useState({});
|
||||
const [langCode, setLangCode] = useState("en_US");
|
||||
|
||||
useEffect(() => {
|
||||
if (playingFile.id === undefined) {
|
||||
return;
|
||||
}
|
||||
const html = document.getElementsByTagName("html")[0];
|
||||
const retStyle = html.style;
|
||||
const bodyRetStyle = document.body.style
|
||||
html.style = `
|
||||
backdrop-filter: blur(10px);
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
background-position: center;
|
||||
background-image: url("/api/v1/get_file_avatar?id=${playingFile.id}");
|
||||
`;
|
||||
document.body.style.opacity = 0.88;
|
||||
return () => {
|
||||
html.style = retStyle;
|
||||
document.body.style = bodyRetStyle;
|
||||
};
|
||||
}, [playingFile.id]);
|
||||
|
||||
// select language
|
||||
useEffect(() => {
|
||||
const browserCode = window.navigator.language;
|
||||
@@ -41,7 +62,7 @@ function App() {
|
||||
}
|
||||
}
|
||||
// fallback to english
|
||||
setLangCode('en-US');
|
||||
setLangCode("en-US");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,7 @@ import {useNavigate} from "react-router";
|
||||
import {CalcReadableFilesizeDetail} from "./Common";
|
||||
import FfmpegConfig from "./FfmpegConfig";
|
||||
import FileDialog from "./FileDialog";
|
||||
import { Tr } from "../translate";
|
||||
import {Tr} from "../translate";
|
||||
|
||||
function AudioPlayer(props) {
|
||||
// props.playingFile
|
||||
@@ -22,25 +22,50 @@ function AudioPlayer(props) {
|
||||
const [isPreparing, setIsPreparing] = useState(false);
|
||||
const [timerCount, setTimerCount] = useState(0);
|
||||
const [timerID, setTimerID] = useState(null);
|
||||
const [beginPlayTime, setBeginPlayTime] = useState(null);
|
||||
const [lastID, setLastID] = useState(null);
|
||||
|
||||
const recordPlaybackHistory = async (file_id, method) => {
|
||||
if (file_id === null) {
|
||||
return
|
||||
}
|
||||
const player = document.getElementById('dom-player')
|
||||
const endPlayTime = new Date()
|
||||
let duration = parseInt((endPlayTime - beginPlayTime) / 1000)
|
||||
const maxDuration = parseInt(player.duration)
|
||||
// treat 85% of duration as finished
|
||||
if (duration / maxDuration >= 0.85) {
|
||||
method = 1
|
||||
}
|
||||
duration = duration < maxDuration ? duration : maxDuration
|
||||
setBeginPlayTime(endPlayTime)
|
||||
await fetch('/api/v1/record_playback', {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
playback: {
|
||||
file_id,
|
||||
method,
|
||||
duration,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// init mediaSession API
|
||||
useEffect(() => {
|
||||
navigator.mediaSession.setActionHandler("stop", () => {
|
||||
props.setPlayingFile({});
|
||||
});
|
||||
if (navigator.mediaSession) {
|
||||
navigator.mediaSession.setActionHandler("stop", () => {
|
||||
props.setPlayingFile({});
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// media session related staff
|
||||
navigator.mediaSession.metadata = new window.MediaMetadata({
|
||||
title: props.playingFile.filename,
|
||||
album: props.playingFile.foldername,
|
||||
artwork: [{ src: "/favicon.png", type: "image/png" }],
|
||||
});
|
||||
// no playing file
|
||||
const updatePlayMode = () => {
|
||||
if (props.playingFile.id === undefined) {
|
||||
setPlayingURL("");
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (raw) {
|
||||
console.log("Play raw file");
|
||||
@@ -51,7 +76,7 @@ function AudioPlayer(props) {
|
||||
setIsPreparing(true);
|
||||
fetch("/api/v1/prepare_file_stream_direct", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({
|
||||
id: props.playingFile.id,
|
||||
config_name: selectedFfmpegConfig.name,
|
||||
@@ -76,7 +101,39 @@ function AudioPlayer(props) {
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [props.playingFile.id, raw, prepare, selectedFfmpegConfig]);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// media session related staff
|
||||
if (navigator.mediaSession) {
|
||||
navigator.mediaSession.metadata = new window.MediaMetadata({
|
||||
title: props.playingFile.filename,
|
||||
album: props.playingFile.foldername,
|
||||
artwork: [{src: "/favicon.png", type: "image/png"}],
|
||||
});
|
||||
}
|
||||
// no playing file
|
||||
if (props.playingFile.id === undefined) {
|
||||
// 3 music stopped
|
||||
recordPlaybackHistory(lastID, 3)
|
||||
setPlayingURL("");
|
||||
return;
|
||||
}
|
||||
// crrently playing file, record interupt
|
||||
if (playingURL) {
|
||||
// 2 music changed
|
||||
recordPlaybackHistory(lastID, 2)
|
||||
}
|
||||
setLastID(props.playingFile.id)
|
||||
// have playingFile, record begin time
|
||||
setBeginPlayTime(new Date())
|
||||
updatePlayMode()
|
||||
}, [props.playingFile.id]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
updatePlayMode()
|
||||
}, [raw, prepare, selectedFfmpegConfig])
|
||||
|
||||
let navigate = useNavigate();
|
||||
|
||||
@@ -192,16 +249,26 @@ function AudioPlayer(props) {
|
||||
id="dom-player"
|
||||
controls
|
||||
autoPlay
|
||||
loop={loop}
|
||||
className="audio-player"
|
||||
src={playingURL}
|
||||
onEnded={async () => {
|
||||
const player = document.getElementById('dom-player')
|
||||
if (loop) {
|
||||
player.play()
|
||||
}
|
||||
// 1 music finished
|
||||
recordPlaybackHistory(props.playingFile.id, 1)
|
||||
}}
|
||||
onPlay={async () => {
|
||||
setBeginPlayTime(new Date());
|
||||
}}
|
||||
></audio>
|
||||
|
||||
<FfmpegConfig
|
||||
selectedFfmpegConfig={selectedFfmpegConfig}
|
||||
setSelectedFfmpegConfig={setSelectedFfmpegConfig}
|
||||
/>
|
||||
</footer>
|
||||
</footer >
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user