Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
61391ff2a5
|
|||
|
3b90ad56d6
|
|||
|
ec0dad00ef
|
|||
|
c09e230972
|
34
.drone.yml
34
.drone.yml
@@ -1,34 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: default
|
|
||||||
|
|
||||||
clone:
|
|
||||||
depth: 1
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: frontend-web
|
|
||||||
image: node:19
|
|
||||||
commands:
|
|
||||||
- cd web
|
|
||||||
- npm install
|
|
||||||
- npm run build
|
|
||||||
|
|
||||||
- name: backend
|
|
||||||
image: golang:1.19
|
|
||||||
commands:
|
|
||||||
- go build -v .
|
|
||||||
environment:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
GOPROXY: goproxy.cn
|
|
||||||
|
|
||||||
- name: upload
|
|
||||||
image: plugins/s3-sync
|
|
||||||
settings:
|
|
||||||
bucket: msw-artifacts-public
|
|
||||||
region: ap-southeast-1
|
|
||||||
access_key:
|
|
||||||
from_secret: access_key
|
|
||||||
secret_key:
|
|
||||||
from_secret: secret_key
|
|
||||||
source: msw-open-music
|
|
||||||
target: /msw-open-music/${DRONE_COMMIT}/
|
|
||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 18
|
||||||
- name: Build web front end
|
- name: Build web front end
|
||||||
run: |
|
run: |
|
||||||
make web
|
make web
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -4,7 +4,7 @@ web:
|
|||||||
cd web && npm run build
|
cd web && npm run build
|
||||||
|
|
||||||
linux:
|
linux:
|
||||||
CGO_ENABLED=0 go build -v -ldflags '-extldflags=-static'
|
go build -v -ldflags '-linkmode=external -extldflags=-static' -tags sqlite_omit_load_extension,netgo
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -v
|
CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -v
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"api": {
|
"api": {
|
||||||
"secret": "CHANGE_YOUR_SECRET_HERE",
|
"secret": "CHANGE_YOUR_SECRET_HERE",
|
||||||
"database_name": "postgres://postgres:woshimima@localhost/postgres?sslmode=disable",
|
"database_name": "music.sqlite3",
|
||||||
"single_thread": true,
|
"single_thread": true,
|
||||||
"addr": ":8080",
|
"addr": ":8080",
|
||||||
"ffmpeg_threads": 1,
|
"ffmpeg_threads": 1,
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/sessions v1.2.1
|
github.com/gorilla/sessions v1.2.1
|
||||||
github.com/lib/pq v1.10.7
|
github.com/mattn/go-sqlite3 v1.14.14
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
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/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 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
||||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
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=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
|||||||
14
main.go
14
main.go
@@ -1,10 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"io/fs"
|
|
||||||
"log"
|
"log"
|
||||||
"msw-open-music/pkg/api"
|
"msw-open-music/pkg/api"
|
||||||
"msw-open-music/pkg/commonconfig"
|
"msw-open-music/pkg/commonconfig"
|
||||||
@@ -17,21 +15,11 @@ func init() {
|
|||||||
flag.StringVar(&ConfigFilePath, "config", "config.json", "backend config file path")
|
flag.StringVar(&ConfigFilePath, "config", "config.json", "backend config file path")
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:embed web/build
|
|
||||||
var WEBFILES embed.FS
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
var err error
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
WEBFS, err := fs.Sub(WEBFILES, "web/build")
|
config := commonconfig.Config{}
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := commonconfig.Config{
|
|
||||||
WEBFS: WEBFS,
|
|
||||||
}
|
|
||||||
configFile, err := os.Open(ConfigFilePath)
|
configFile, err := os.Open(ConfigFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
"msw-open-music/pkg/commonconfig"
|
"msw-open-music/pkg/commonconfig"
|
||||||
"msw-open-music/pkg/database"
|
"msw-open-music/pkg/database"
|
||||||
"msw-open-music/pkg/tmpfs"
|
"msw-open-music/pkg/tmpfs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
@@ -60,7 +59,6 @@ func NewAPI(config commonconfig.Config) (*API, error) {
|
|||||||
apiMux.HandleFunc("/get_file_info", api.HandleGetFileInfo)
|
apiMux.HandleFunc("/get_file_info", api.HandleGetFileInfo)
|
||||||
apiMux.HandleFunc("/get_file_ffprobe_info", api.HandleGetFileFfprobeInfo)
|
apiMux.HandleFunc("/get_file_ffprobe_info", api.HandleGetFileFfprobeInfo)
|
||||||
apiMux.HandleFunc("/get_file_stream_direct", api.HandleGetFileStreamDirect)
|
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("/prepare_file_stream_direct", api.HandlePrepareFileStreamDirect)
|
||||||
apiMux.HandleFunc("/delete_file", api.HandleDeleteFile)
|
apiMux.HandleFunc("/delete_file", api.HandleDeleteFile)
|
||||||
apiMux.HandleFunc("/update_filename", api.HandleUpdateFilename)
|
apiMux.HandleFunc("/update_filename", api.HandleUpdateFilename)
|
||||||
@@ -104,7 +102,7 @@ func NewAPI(config commonconfig.Config) (*API, error) {
|
|||||||
apiMux.HandleFunc("/reset", api.HandleReset)
|
apiMux.HandleFunc("/reset", api.HandleReset)
|
||||||
|
|
||||||
mux.Handle("/api/v1/", http.StripPrefix("/api/v1", api.PermissionMiddleware(apiMux)))
|
mux.Handle("/api/v1/", http.StripPrefix("/api/v1", api.PermissionMiddleware(apiMux)))
|
||||||
mux.Handle("/", http.StripPrefix("/", http.FileServer(http.FS(config.WEBFS))))
|
mux.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("web/build"))))
|
||||||
|
|
||||||
return api, nil
|
return api, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
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,7 +2,6 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
|
||||||
"msw-open-music/pkg/database"
|
"msw-open-music/pkg/database"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@@ -36,12 +35,6 @@ 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)
|
err = api.Db.RecordPlayback(recordPlaybackRequest.Playback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleError(w, r, err)
|
api.HandleError(w, r, err)
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
package commonconfig
|
package commonconfig
|
||||||
|
|
||||||
import "io/fs"
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
APIConfig APIConfig `json:"api"`
|
APIConfig APIConfig `json:"api"`
|
||||||
TmpfsConfig TmpfsConfig `json:"tmpfs"`
|
TmpfsConfig TmpfsConfig `json:"tmpfs"`
|
||||||
WEBFS fs.FS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIConfig struct {
|
type APIConfig struct {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
@@ -41,7 +41,7 @@ func NewDatabase(dbName string, singleThread bool) (*Database, error) {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
// open database
|
// open database
|
||||||
sqlConn, err := sql.Open("postgres", dbName)
|
sqlConn, err := sql.Open("sqlite3", dbName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,6 @@ func (database *Database) Walk(root string, pattern []string, tagIDs []int64, us
|
|||||||
insertFileStmt := tx.Stmt(database.stmt.insertFile)
|
insertFileStmt := tx.Stmt(database.stmt.insertFile)
|
||||||
putTagOnFileStmt := tx.Stmt(database.stmt.putTagOnFile)
|
putTagOnFileStmt := tx.Stmt(database.stmt.putTagOnFile)
|
||||||
findFolderStmt := tx.Stmt(database.stmt.findFolder)
|
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 {
|
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -195,42 +194,23 @@ func (database *Database) Walk(root string, pattern []string, tagIDs []int64, us
|
|||||||
folder, filename := filepath.Split(path)
|
folder, filename := filepath.Split(path)
|
||||||
err = findFolderStmt.QueryRow(folder).Scan(&folderID)
|
err = findFolderStmt.QueryRow(folder).Scan(&folderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result, err := insertFolderStmt.Query(folder, filepath.Base(folder))
|
result, err := insertFolderStmt.Exec(folder, filepath.Base(folder))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for result.Next() {
|
folderID, err = result.LastInsertId()
|
||||||
err = result.Scan(&folderID)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result, err := insertFileStmt.Exec(folderID, filename, filename, info.Size())
|
||||||
// try find file id
|
|
||||||
var fileID int64
|
|
||||||
result, err := findFileStmt.Query(folderID, filename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for result.Next() {
|
fileID, err := result.LastInsertId()
|
||||||
err = result.Scan(&fileID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert new file
|
|
||||||
result, err = insertFileStmt.Query(folderID, filename, filename, info.Size())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for result.Next() {
|
|
||||||
err = result.Scan(&fileID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
_, err := putTagOnFileStmt.Exec(tag.ID, fileID, userID)
|
_, err := putTagOnFileStmt.Exec(tag.ID, fileID, userID)
|
||||||
|
|||||||
@@ -6,17 +6,11 @@ func (database *Database) InsertTag(tag *Tag) (int64, error) {
|
|||||||
database.singleThreadLock.Lock()
|
database.singleThreadLock.Lock()
|
||||||
defer database.singleThreadLock.Unlock()
|
defer database.singleThreadLock.Unlock()
|
||||||
|
|
||||||
result, err := database.stmt.insertTag.Query(tag.Name, tag.Description, tag.CreatedByUserId)
|
result, err := database.stmt.insertTag.Exec(tag.Name, tag.Description, tag.CreatedByUserId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
var id int64
|
id, err := result.LastInsertId()
|
||||||
for result.Next() {
|
|
||||||
err = result.Scan(&id)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var initFilesTableQuery = `CREATE TABLE IF NOT EXISTS files (
|
var initFilesTableQuery = `CREATE TABLE IF NOT EXISTS files (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
folder_id INTEGER NOT NULL REFERENCES folders(id),
|
folder_id INTEGER NOT NULL,
|
||||||
realname TEXT NOT NULL,
|
realname TEXT NOT NULL,
|
||||||
filename TEXT NOT NULL,
|
filename TEXT NOT NULL,
|
||||||
filesize INTEGER NOT NULL,
|
filesize INTEGER NOT NULL,
|
||||||
UNIQUE (folder_id, realname)
|
FOREIGN KEY(folder_id) REFERENCES folders(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initFoldersTableQuery = `CREATE TABLE IF NOT EXISTS folders (
|
var initFoldersTableQuery = `CREATE TABLE IF NOT EXISTS folders (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
folder TEXT NOT NULL UNIQUE,
|
folder TEXT NOT NULL,
|
||||||
foldername TEXT NOT NULL
|
foldername TEXT NOT NULL
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks (
|
var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
time INTEGER NOT NULL,
|
time INTEGER NOT NULL,
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
@@ -30,101 +30,108 @@ var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks (
|
|||||||
|
|
||||||
// User table schema definition
|
// User table schema definition
|
||||||
// role: 0 - Anonymous User, 1 - Admin, 2 - User
|
// role: 0 - Anonymous User, 1 - Admin, 2 - User
|
||||||
// postgres avatar references problem
|
|
||||||
var initUsersTableQuery = `CREATE TABLE IF NOT EXISTS users (
|
var initUsersTableQuery = `CREATE TABLE IF NOT EXISTS users (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username TEXT NOT NULL UNIQUE,
|
username TEXT NOT NULL UNIQUE,
|
||||||
password TEXT NOT NULL,
|
password TEXT NOT NULL,
|
||||||
role INTEGER NOT NULL,
|
role INTEGER NOT NULL,
|
||||||
active BOOLEAN NOT NULL,
|
active BOOLEAN NOT NULL,
|
||||||
avatar_id INTEGER NOT NULL DEFAULT 0
|
avatar_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(avatar_id) REFERENCES avatars(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initAvatarsTableQuery = `CREATE TABLE IF NOT EXISTS avatars (
|
var initAvatarsTableQuery = `CREATE TABLE IF NOT EXISTS avatars (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
avatarname TEXT NOT NULL,
|
avatarname TEXT NOT NULL,
|
||||||
avatar BYTEA NOT NULL
|
avatar BLOB NOT NULL
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initTagsTableQuery = `CREATE TABLE IF NOT EXISTS tags (
|
var initTagsTableQuery = `CREATE TABLE IF NOT EXISTS tags (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL UNIQUE,
|
name TEXT NOT NULL UNIQUE,
|
||||||
description TEXT NOT NULL,
|
description TEXT NOT NULL,
|
||||||
created_by_user_id INTEGER NOT NULL REFERENCES users(id)
|
created_by_user_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(created_by_user_id) REFERENCES users(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initFileHasTagTableQuery = `CREATE TABLE IF NOT EXISTS file_has_tag (
|
var initFileHasTagTableQuery = `CREATE TABLE IF NOT EXISTS file_has_tag (
|
||||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
file_id INTEGER NOT NULL,
|
||||||
tag_id INTEGER NOT NULL REFERENCES tags(id),
|
tag_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
user_id INTEGER NOT NULL,
|
||||||
PRIMARY KEY (file_id, tag_id)
|
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)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initLikesTableQuery = `CREATE TABLE IF NOT EXISTS likes (
|
var initLikesTableQuery = `CREATE TABLE IF NOT EXISTS likes (
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
user_id INTEGER NOT NULL,
|
||||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
file_id INTEGER NOT NULL,
|
||||||
PRIMARY KEY (user_id, file_id)
|
PRIMARY KEY (user_id, file_id),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initReviewsTableQuery = `CREATE TABLE IF NOT EXISTS reviews (
|
var initReviewsTableQuery = `CREATE TABLE IF NOT EXISTS reviews (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
user_id INTEGER NOT NULL,
|
||||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
file_id INTEGER NOT NULL,
|
||||||
created_at INTEGER NOT NULL,
|
created_at INTEGER NOT NULL,
|
||||||
updated_at INTEGER NOT NULL DEFAULT 0,
|
updated_at INTEGER NOT NULL DEFAULT 0,
|
||||||
content TEXT NOT NULL
|
content TEXT NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initPlaybacksTableQuery = `CREATE TABLE IF NOT EXISTS playbacks (
|
var initPlaybacksTableQuery = `CREATE TABLE IF NOT EXISTS playbacks (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
user_id INTEGER NOT NULL,
|
||||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
file_id INTEGER NOT NULL,
|
||||||
time TIMESTAMP NOT NULL,
|
time INTEGER NOT NULL,
|
||||||
method INTEGER NOT NULL,
|
method INTEGER NOT NULL,
|
||||||
duration INTERVAL NOT NULL
|
duration INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initLogsTableQuery = `CREATE TABLE IF NOT EXISTS logs (
|
var initLogsTableQuery = `CREATE TABLE IF NOT EXISTS logs (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
time INTEGER NOT NULL,
|
time INTEGER NOT NULL,
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id)
|
user_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var initTmpfsTableQuery = `CREATE TABLE IF NOT EXISTS tmpfs (
|
var initTmpfsTableQuery = `CREATE TABLE IF NOT EXISTS tmpfs (
|
||||||
id SERIAL PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
path TEXT NOT NULL,
|
path TEXT NOT NULL,
|
||||||
size INTEGER NOT NULL,
|
size INTEGER NOT NULL,
|
||||||
file_id INTEGER NOT NULL REFERENCES files(id),
|
file_id INTEGER NOT NULL,
|
||||||
ffmpeg_config TEXT NOT NULL,
|
ffmpeg_config TEXT NOT NULL,
|
||||||
created_time INTEGER NOT NULL,
|
created_time INTEGER NOT NULL,
|
||||||
accessed_time INTEGER NOT NULL
|
accessed_time INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (file_id) REFERENCES files(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
var insertFolderQuery = `INSERT INTO folders (folder, foldername)
|
var insertFolderQuery = `INSERT INTO folders (folder, foldername)
|
||||||
VALUES ($1, $2)
|
VALUES (?, ?);`
|
||||||
ON CONFLICT DO NOTHING
|
|
||||||
RETURNING id;
|
|
||||||
;`
|
|
||||||
|
|
||||||
var findFolderQuery = `SELECT id FROM folders WHERE folder = $1 LIMIT 1;`
|
var findFolderQuery = `SELECT id FROM folders WHERE folder = ? LIMIT 1;`
|
||||||
|
|
||||||
var findFileQuery = `SELECT id FROM files WHERE folder_id = $1 AND realname = $2 LIMIT 1;`
|
var findFileQuery = `SELECT id FROM files WHERE folder_id = ? AND realname = ? LIMIT 1;`
|
||||||
|
|
||||||
var insertFileQuery = `INSERT INTO files (folder_id, realname, filename, filesize)
|
var insertFileQuery = `INSERT INTO files (folder_id, realname, filename, filesize)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES (?, ?, ?, ?);`
|
||||||
ON CONFLICT DO NOTHING
|
|
||||||
RETURNING id;`
|
|
||||||
|
|
||||||
var searchFilesQuery = `SELECT
|
var searchFilesQuery = `SELECT
|
||||||
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
||||||
FROM files
|
FROM files
|
||||||
JOIN folders ON files.folder_id = folders.id
|
JOIN folders ON files.folder_id = folders.id
|
||||||
WHERE filename ILIKE $1
|
WHERE filename LIKE ?
|
||||||
ORDER BY folders.foldername, files.filename
|
ORDER BY folders.foldername, files.filename
|
||||||
LIMIT $2 OFFSET $3;`
|
LIMIT ? OFFSET ?;`
|
||||||
|
|
||||||
var getFolderQuery = `SELECT folder FROM folders WHERE id = $1 LIMIT 1;`
|
var getFolderQuery = `SELECT folder FROM folders WHERE id = ? LIMIT 1;`
|
||||||
|
|
||||||
var dropFilesQuery = `DROP TABLE files;`
|
var dropFilesQuery = `DROP TABLE files;`
|
||||||
|
|
||||||
@@ -134,42 +141,42 @@ var getFileQuery = `SELECT
|
|||||||
files.id, files.folder_id, files.realname, files.filename, folders.foldername, files.filesize
|
files.id, files.folder_id, files.realname, files.filename, folders.foldername, files.filesize
|
||||||
FROM files
|
FROM files
|
||||||
JOIN folders ON files.folder_id = folders.id
|
JOIN folders ON files.folder_id = folders.id
|
||||||
WHERE files.id = $1
|
WHERE files.id = ?
|
||||||
LIMIT 1;`
|
LIMIT 1;`
|
||||||
|
|
||||||
var searchFoldersQuery = `SELECT
|
var searchFoldersQuery = `SELECT
|
||||||
id, folder, foldername
|
id, folder, foldername
|
||||||
FROM folders
|
FROM folders
|
||||||
WHERE foldername ILIKE $1
|
WHERE foldername LIKE ?
|
||||||
ORDER BY foldername
|
ORDER BY foldername
|
||||||
LIMIT $2 OFFSET $3;`
|
LIMIT ? OFFSET ?;`
|
||||||
|
|
||||||
var getFilesInFolderQuery = `SELECT
|
var getFilesInFolderQuery = `SELECT
|
||||||
files.id, files.filename, files.filesize, folders.foldername, folders.folder
|
files.id, files.filename, files.filesize, folders.foldername, folders.folder
|
||||||
FROM files
|
FROM files
|
||||||
JOIN folders ON files.folder_id = folders.id
|
JOIN folders ON files.folder_id = folders.id
|
||||||
WHERE folder_id = $1
|
WHERE folder_id = ?
|
||||||
ORDER BY files.filename
|
ORDER BY files.filename
|
||||||
LIMIT $2 OFFSET $3;`
|
LIMIT ? OFFSET ?;`
|
||||||
|
|
||||||
var getRandomFilesQuery = `SELECT
|
var getRandomFilesQuery = `SELECT
|
||||||
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
||||||
FROM files
|
FROM files
|
||||||
JOIN folders ON files.folder_id = folders.id
|
JOIN folders ON files.folder_id = folders.id
|
||||||
ORDER BY RANDOM()
|
ORDER BY RANDOM()
|
||||||
LIMIT $1;`
|
LIMIT ?;`
|
||||||
|
|
||||||
var getRandomFilesWithTagQuery = `SELECT
|
var getRandomFilesWithTagQuery = `SELECT
|
||||||
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
files.id, files.folder_id, files.filename, folders.foldername, files.filesize
|
||||||
FROM file_has_tag
|
FROM file_has_tag
|
||||||
JOIN files ON file_has_tag.file_id = files.id
|
JOIN files ON file_has_tag.file_id = files.id
|
||||||
JOIN folders ON files.folder_id = folders.id
|
JOIN folders ON files.folder_id = folders.id
|
||||||
WHERE file_has_tag.tag_id = $1
|
WHERE file_has_tag.tag_id = ?
|
||||||
ORDER BY RANDOM()
|
ORDER BY RANDOM()
|
||||||
LIMIT $2;`
|
LIMIT ?;`
|
||||||
|
|
||||||
var insertFeedbackQuery = `INSERT INTO feedbacks (time, content, user_id, header)
|
var insertFeedbackQuery = `INSERT INTO feedbacks (time, content, user_id, header)
|
||||||
VALUES ($1, $2, $3, $4);`
|
VALUES (?, ?, ?, ?);`
|
||||||
|
|
||||||
var getFeedbacksQuery = `SELECT
|
var getFeedbacksQuery = `SELECT
|
||||||
feedbacks.id, feedbacks.time, feedbacks.content, feedbacks.header,
|
feedbacks.id, feedbacks.time, feedbacks.content, feedbacks.header,
|
||||||
@@ -179,39 +186,39 @@ JOIN users ON feedbacks.user_id = users.id
|
|||||||
ORDER BY feedbacks.time
|
ORDER BY feedbacks.time
|
||||||
;`
|
;`
|
||||||
|
|
||||||
var deleteFeedbackQuery = `DELETE FROM feedbacks WHERE id = $1;`
|
var deleteFeedbackQuery = `DELETE FROM feedbacks WHERE id = ?;`
|
||||||
|
|
||||||
var insertUserQuery = `INSERT INTO users (username, password, role, active, avatar_id)
|
var insertUserQuery = `INSERT INTO users (username, password, role, active, avatar_id)
|
||||||
VALUES ($1, $2, $3, $4, $5);`
|
VALUES (?, ?, ?, ?, ?);`
|
||||||
|
|
||||||
var countUserQuery = `SELECT count(*) FROM users;`
|
var countUserQuery = `SELECT count(*) FROM users;`
|
||||||
|
|
||||||
var countAdminQuery = `SELECT count(*) FROM users WHERE role= 1;`
|
var countAdminQuery = `SELECT count(*) FROM users WHERE role= 1;`
|
||||||
|
|
||||||
var getUserQuery = `SELECT id, username, password, role, active, avatar_id FROM users WHERE username = $1 LIMIT 1;`
|
var getUserQuery = `SELECT id, username, password, role, active, avatar_id FROM users WHERE username = ? LIMIT 1;`
|
||||||
|
|
||||||
var getUsersQuery = `SELECT id, username, role, active, avatar_id FROM users;`
|
var getUsersQuery = `SELECT id, username, role, active, avatar_id FROM users;`
|
||||||
|
|
||||||
var getUserByIdQuery = `SELECT id, username, role, active, avatar_id FROM users WHERE id = $1 LIMIT 1;`
|
var getUserByIdQuery = `SELECT id, username, role, active, avatar_id FROM users WHERE id = ? LIMIT 1;`
|
||||||
|
|
||||||
var updateUserActiveQuery = `UPDATE users SET active = $1 WHERE id = $2;`
|
var updateUserActiveQuery = `UPDATE users SET active = ? WHERE id = ?;`
|
||||||
|
|
||||||
var updateUsernameQuery = `UPDATE users SET username = $1 WHERE id = $2;`
|
var updateUsernameQuery = `UPDATE users SET username = ? WHERE id = ?;`
|
||||||
|
|
||||||
var updateUserPasswordQuery = `UPDATE users SET password = $1 WHERE id = $2;`
|
var updateUserPasswordQuery = `UPDATE users SET password = ? WHERE id = ?;`
|
||||||
|
|
||||||
var getAnonymousUserQuery = `SELECT id, username, role, avatar_id FROM users WHERE role = 0 LIMIT 1;`
|
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 ($1, $2, $3) RETURNING id;`
|
var insertTagQuery = `INSERT INTO tags (name, description, created_by_user_id) VALUES (?, ?, ?);`
|
||||||
|
|
||||||
var deleteTagQuery = `DELETE FROM tags WHERE id = $1;`
|
var deleteTagQuery = `DELETE FROM tags WHERE id = ?;`
|
||||||
|
|
||||||
var getTagQuery = `SELECT
|
var getTagQuery = `SELECT
|
||||||
tags.id, tags.name, tags.description,
|
tags.id, tags.name, tags.description,
|
||||||
users.id, users.username, users.role, users.avatar_id
|
users.id, users.username, users.role, users.avatar_id
|
||||||
FROM tags
|
FROM tags
|
||||||
JOIN users ON tags.created_by_user_id = users.id
|
JOIN users ON tags.created_by_user_id = users.id
|
||||||
WHERE tags.id = $1 LIMIT 1;`
|
WHERE tags.id = ? LIMIT 1;`
|
||||||
|
|
||||||
var getTagsQuery = `SELECT
|
var getTagsQuery = `SELECT
|
||||||
tags.id, tags.name, tags.description,
|
tags.id, tags.name, tags.description,
|
||||||
@@ -221,27 +228,26 @@ JOIN users ON tags.created_by_user_id = users.id
|
|||||||
ORDER BY tags.name
|
ORDER BY tags.name
|
||||||
;`
|
;`
|
||||||
|
|
||||||
var updateTagQuery = `UPDATE tags SET name = $1, description = $2 WHERE id = $3;`
|
var updateTagQuery = `UPDATE tags SET name = ?, description = ? WHERE id = ?;`
|
||||||
|
|
||||||
// postgres INSERT IGNORE
|
var putTagOnFileQuery = `INSERT OR IGNORE INTO file_has_tag (tag_id, file_id, user_id) VALUES (?, ?, ?);`
|
||||||
var putTagOnFileQuery = `INSERT INTO file_has_tag (tag_id, file_id, user_id) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;`
|
|
||||||
|
|
||||||
var getTagsOnFileQuery = `SELECT
|
var getTagsOnFileQuery = `SELECT
|
||||||
tags.id, tags.name, tags.description, tags.created_by_user_id
|
tags.id, tags.name, tags.description, tags.created_by_user_id
|
||||||
FROM file_has_tag
|
FROM file_has_tag
|
||||||
JOIN tags ON file_has_tag.tag_id = tags.id
|
JOIN tags ON file_has_tag.tag_id = tags.id
|
||||||
WHERE file_has_tag.file_id = $1
|
WHERE file_has_tag.file_id = ?
|
||||||
ORDER BY tags.name
|
ORDER BY tags.name
|
||||||
;`
|
;`
|
||||||
|
|
||||||
var deleteTagOnFileQuery = `DELETE FROM file_has_tag WHERE tag_id = $1 AND file_id = $2;`
|
var deleteTagOnFileQuery = `DELETE FROM file_has_tag WHERE tag_id = ? AND file_id = ?;`
|
||||||
|
|
||||||
var deleteTagReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE tag_id = $1;`
|
var deleteTagReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE tag_id = ?;`
|
||||||
|
|
||||||
var updateFoldernameQuery = `UPDATE folders SET foldername = $1 WHERE id = $2;`
|
var updateFoldernameQuery = `UPDATE folders SET foldername = ? WHERE id = ?;`
|
||||||
|
|
||||||
var insertReviewQuery = `INSERT INTO reviews (user_id, file_id, created_at, content)
|
var insertReviewQuery = `INSERT INTO reviews (user_id, file_id, created_at, content)
|
||||||
VALUES ($1, $2, $3, $4);`
|
VALUES (?, ?, ?, ?);`
|
||||||
|
|
||||||
var getReviewsOnFileQuery = `SELECT
|
var getReviewsOnFileQuery = `SELECT
|
||||||
reviews.id, reviews.created_at, reviews.updated_at, reviews.content,
|
reviews.id, reviews.created_at, reviews.updated_at, reviews.content,
|
||||||
@@ -250,15 +256,15 @@ files.id, files.filename
|
|||||||
FROM reviews
|
FROM reviews
|
||||||
JOIN users ON reviews.user_id = users.id
|
JOIN users ON reviews.user_id = users.id
|
||||||
JOIN files ON reviews.file_id = files.id
|
JOIN files ON reviews.file_id = files.id
|
||||||
WHERE reviews.file_id = $1
|
WHERE reviews.file_id = ?
|
||||||
ORDER BY reviews.created_at
|
ORDER BY reviews.created_at
|
||||||
;`
|
;`
|
||||||
|
|
||||||
var getReviewQuery = `SELECT id, file_id, user_id, created_at, updated_at, content FROM reviews WHERE id = $1 LIMIT 1;`
|
var getReviewQuery = `SELECT id, file_id, user_id, created_at, updated_at, content FROM reviews WHERE id = ? LIMIT 1;`
|
||||||
|
|
||||||
var updateReviewQuery = `UPDATE reviews SET content = $1, updated_at = $2 WHERE id = $3;`
|
var updateReviewQuery = `UPDATE reviews SET content = ?, updated_at = ? WHERE id = ?;`
|
||||||
|
|
||||||
var deleteReviewQuery = `DELETE FROM reviews WHERE id = $1;`
|
var deleteReviewQuery = `DELETE FROM reviews WHERE id = ?;`
|
||||||
|
|
||||||
var getReviewsByUserQuery = `SELECT
|
var getReviewsByUserQuery = `SELECT
|
||||||
reviews.id, reviews.created_at, reviews.updated_at, reviews.content,
|
reviews.id, reviews.created_at, reviews.updated_at, reviews.content,
|
||||||
@@ -267,19 +273,19 @@ files.id, files.filename
|
|||||||
FROM reviews
|
FROM reviews
|
||||||
JOIN users ON reviews.user_id = users.id
|
JOIN users ON reviews.user_id = users.id
|
||||||
JOIN files ON reviews.file_id = files.id
|
JOIN files ON reviews.file_id = files.id
|
||||||
WHERE reviews.user_id = $1
|
WHERE reviews.user_id = ?
|
||||||
ORDER BY reviews.created_at
|
ORDER BY reviews.created_at
|
||||||
;`
|
;`
|
||||||
|
|
||||||
var deleteFileQuery = `DELETE FROM files WHERE id = $1;`
|
var deleteFileQuery = `DELETE FROM files WHERE id = ?;`
|
||||||
|
|
||||||
var deleteFileReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE file_id = $1;`
|
var deleteFileReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE file_id = ?;`
|
||||||
|
|
||||||
var deleteFileReferenceInReviewsQuery = `DELETE FROM reviews WHERE file_id = $1;`
|
var deleteFileReferenceInReviewsQuery = `DELETE FROM reviews WHERE file_id = ?;`
|
||||||
|
|
||||||
var updateFilenameQuery = `UPDATE files SET filename = $1 WHERE id = $2;`
|
var updateFilenameQuery = `UPDATE files SET filename = ? WHERE id = ?;`
|
||||||
|
|
||||||
var resetFilenameQuery = `UPDATE files SET filename = realname WHERE id = $1;`
|
var resetFilenameQuery = `UPDATE files SET filename = realname WHERE id = ?;`
|
||||||
|
|
||||||
var recordPlaybackQuery = `INSERT INTO playbacks (user_id, file_id, time, method, duration) VALUES ($1, $2, $3, $4, $5);`
|
var recordPlaybackQuery = `INSERT INTO playbacks (user_id, file_id, time, method, duration) VALUES ($1, $2, $3, $4, $5);`
|
||||||
|
|
||||||
@@ -351,42 +357,14 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
|||||||
|
|
||||||
stmt := &Stmt{}
|
stmt := &Stmt{}
|
||||||
|
|
||||||
// init folders table
|
|
||||||
stmt.initFoldersTable, err = sqlConn.Prepare(initFoldersTableQuery)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = stmt.initFoldersTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init files table
|
// init files table
|
||||||
stmt.initFilesTable, err = sqlConn.Prepare(initFilesTableQuery)
|
stmt.initFilesTable, err = sqlConn.Prepare(initFilesTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initFilesTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init avatars table
|
// init folders table
|
||||||
stmt.initAvatarsTable, err = sqlConn.Prepare(initAvatarsTableQuery)
|
stmt.initFoldersTable, err = sqlConn.Prepare(initFoldersTableQuery)
|
||||||
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -396,7 +374,15 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initFeedbacksTable.Exec()
|
|
||||||
|
// init users table
|
||||||
|
stmt.initUsersTable, err = sqlConn.Prepare(initUsersTableQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// init avatars table
|
||||||
|
stmt.initAvatarsTable, err = sqlConn.Prepare(initAvatarsTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -406,73 +392,93 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initTagsTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init file_has_tag table
|
// init file_has_tag table
|
||||||
stmt.initFileHasTag, err = sqlConn.Prepare(initFileHasTagTableQuery)
|
stmt.initFileHasTag, err = sqlConn.Prepare(initFileHasTagTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initFileHasTag.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init likes table
|
// init likes table
|
||||||
stmt.initLikesTable, err = sqlConn.Prepare(initLikesTableQuery)
|
stmt.initLikesTable, err = sqlConn.Prepare(initLikesTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initLikesTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init reviews table
|
// init reviews table
|
||||||
stmt.initReviewsTable, err = sqlConn.Prepare(initReviewsTableQuery)
|
stmt.initReviewsTable, err = sqlConn.Prepare(initReviewsTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initReviewsTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init playbacks table
|
// init playbacks table
|
||||||
stmt.initPlaybacksTable, err = sqlConn.Prepare(initPlaybacksTableQuery)
|
stmt.initPlaybacksTable, err = sqlConn.Prepare(initPlaybacksTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initPlaybacksTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init logs table
|
// init logs table
|
||||||
stmt.initLogsTable, err = sqlConn.Prepare(initLogsTableQuery)
|
stmt.initLogsTable, err = sqlConn.Prepare(initLogsTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = stmt.initLogsTable.Exec()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// init tmpfs table
|
// init tmpfs table
|
||||||
stmt.initTmpfsTable, err = sqlConn.Prepare(initTmpfsTableQuery)
|
stmt.initTmpfsTable, err = sqlConn.Prepare(initTmpfsTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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()
|
_, err = stmt.initTmpfsTable.Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Init tables finished")
|
|
||||||
|
|
||||||
// init insert folder statement
|
// init insert folder statement
|
||||||
stmt.insertFolder, err = sqlConn.Prepare(insertFolderQuery)
|
stmt.insertFolder, err = sqlConn.Prepare(insertFolderQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
Db *Database `json:"-"`
|
Db *Database `json:"-"`
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Folder_id int64 `json:"folder_id"`
|
Folder_id int64 `json:"folder_id"`
|
||||||
Foldername string `json:"foldername"`
|
Foldername string `json:"foldername"`
|
||||||
Realname string `json:"-"`
|
Realname string `json:"-"`
|
||||||
Filename string `json:"filename"`
|
Filename string `json:"filename"`
|
||||||
Filesize int64 `json:"filesize"`
|
Filesize int64 `json:"filesize"`
|
||||||
folderCache *Folder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Folder struct {
|
type Folder struct {
|
||||||
@@ -76,23 +75,9 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *File) Path() (string, error) {
|
func (f *File) Path() (string, error) {
|
||||||
var err error
|
folder, err := f.Db.GetFolder(f.Folder_id)
|
||||||
if f.folderCache == nil {
|
|
||||||
f.folderCache, err = f.Db.GetFolder(f.Folder_id)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return filepath.Join(f.folderCache.Folder, f.Realname), nil
|
return filepath.Join(folder.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
|
|
||||||
}
|
}
|
||||||
|
|||||||
20
web/build.js
20
web/build.js
@@ -1,20 +0,0 @@
|
|||||||
const fs = require("fs");
|
|
||||||
const esbuild = require("esbuild");
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
fs.rmSync("build", { recursive: true, force: true });
|
|
||||||
fs.cpSync("public", "build", { recursive: true });
|
|
||||||
|
|
||||||
const result = await esbuild.build({
|
|
||||||
entryPoints: ["src/index.jsx"],
|
|
||||||
bundle: true,
|
|
||||||
outfile: "build/msw-open-music.js",
|
|
||||||
sourcemap: true,
|
|
||||||
minify: true,
|
|
||||||
metafile: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const text = await esbuild.analyzeMetafile(result.metafile);
|
|
||||||
console.log(text);
|
|
||||||
console.log("Build done, output files udner ./build directory");
|
|
||||||
})();
|
|
||||||
6
web/build.sh
Executable file
6
web/build.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
rm -rf build
|
||||||
|
cp -raf public build
|
||||||
|
./node_modules/.bin/esbuild src/index.jsx --bundle --outfile=build/msw-open-music.js --alias:react=preact/compat --alias:react-dom=preact/compat --minify --analyze
|
||||||
|
cat public/index.html | sed "s/%PUBLIC_URL%/$PUBLIC_URL/" > build/index.html
|
||||||
|
|
||||||
|
echo "Build done, output files under ./build directory"
|
||||||
@@ -9,6 +9,6 @@
|
|||||||
"water.css": "^2.1.1"
|
"water.css": "^2.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node build.js"
|
"build": "bash ./build.sh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="./favicon.png" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="Personal music streaming platform" />
|
<meta name="description" content="Personal music streaming platform" />
|
||||||
<link rel="apple-touch-icon" href="./favicon.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.png" />
|
||||||
<link rel="manifest" href="./manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<link rel="stylesheet" href="./msw-open-music.css" />
|
<link rel="stylesheet" href="%PUBLIC_URL%/msw-open-music.css" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<title>MSW Open Music</title>
|
<title>MSW Open Music</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="./msw-open-music.js"></script>
|
<script type="module" src="%PUBLIC_URL%/msw-open-music.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
|
html {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
.base {
|
.base {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-row-gap: 1em;
|
grid-row-gap: 1em;
|
||||||
max-width: 800px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
color: white;
|
color: white;
|
||||||
@@ -35,10 +40,54 @@
|
|||||||
color: rgb(229, 232, 245);
|
color: rgb(229, 232, 245);
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
a.unset {
|
||||||
|
color: unset;
|
||||||
|
text-decoration: unset;
|
||||||
|
}
|
||||||
|
a.active {
|
||||||
|
color: deeppink;
|
||||||
|
background-color: lightgray;
|
||||||
|
border-radius: 0.39em 0.39em 0 0;
|
||||||
|
}
|
||||||
.audio-player {
|
.audio-player {
|
||||||
height: 39px;
|
height: 39px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
td.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
div.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
div.page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
div.search_toolbar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
div.feedback {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
button.refresh {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
}
|
||||||
|
dialog {
|
||||||
|
border: solid;
|
||||||
|
}
|
||||||
.player-options {
|
.player-options {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,27 +28,6 @@ function App() {
|
|||||||
const [user, setUser] = useState({});
|
const [user, setUser] = useState({});
|
||||||
const [langCode, setLangCode] = useState("en_US");
|
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
|
// select language
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const browserCode = window.navigator.language;
|
const browserCode = window.navigator.language;
|
||||||
@@ -62,7 +41,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fallback to english
|
// fallback to english
|
||||||
setLangCode("en-US");
|
setLangCode('en-US');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {useNavigate} from "react-router";
|
|||||||
import {CalcReadableFilesizeDetail} from "./Common";
|
import {CalcReadableFilesizeDetail} from "./Common";
|
||||||
import FfmpegConfig from "./FfmpegConfig";
|
import FfmpegConfig from "./FfmpegConfig";
|
||||||
import FileDialog from "./FileDialog";
|
import FileDialog from "./FileDialog";
|
||||||
import {Tr} from "../translate";
|
import { Tr } from "../translate";
|
||||||
|
|
||||||
function AudioPlayer(props) {
|
function AudioPlayer(props) {
|
||||||
// props.playingFile
|
// props.playingFile
|
||||||
@@ -22,50 +22,25 @@ function AudioPlayer(props) {
|
|||||||
const [isPreparing, setIsPreparing] = useState(false);
|
const [isPreparing, setIsPreparing] = useState(false);
|
||||||
const [timerCount, setTimerCount] = useState(0);
|
const [timerCount, setTimerCount] = useState(0);
|
||||||
const [timerID, setTimerID] = useState(null);
|
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
|
// init mediaSession API
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (navigator.mediaSession) {
|
navigator.mediaSession.setActionHandler("stop", () => {
|
||||||
navigator.mediaSession.setActionHandler("stop", () => {
|
props.setPlayingFile({});
|
||||||
props.setPlayingFile({});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const updatePlayMode = () => {
|
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
|
||||||
if (props.playingFile.id === undefined) {
|
if (props.playingFile.id === undefined) {
|
||||||
return
|
setPlayingURL("");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (raw) {
|
if (raw) {
|
||||||
console.log("Play raw file");
|
console.log("Play raw file");
|
||||||
@@ -76,7 +51,7 @@ function AudioPlayer(props) {
|
|||||||
setIsPreparing(true);
|
setIsPreparing(true);
|
||||||
fetch("/api/v1/prepare_file_stream_direct", {
|
fetch("/api/v1/prepare_file_stream_direct", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id: props.playingFile.id,
|
id: props.playingFile.id,
|
||||||
config_name: selectedFfmpegConfig.name,
|
config_name: selectedFfmpegConfig.name,
|
||||||
@@ -101,39 +76,7 @@ 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();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
@@ -249,26 +192,16 @@ function AudioPlayer(props) {
|
|||||||
id="dom-player"
|
id="dom-player"
|
||||||
controls
|
controls
|
||||||
autoPlay
|
autoPlay
|
||||||
|
loop={loop}
|
||||||
className="audio-player"
|
className="audio-player"
|
||||||
src={playingURL}
|
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>
|
></audio>
|
||||||
|
|
||||||
<FfmpegConfig
|
<FfmpegConfig
|
||||||
selectedFfmpegConfig={selectedFfmpegConfig}
|
selectedFfmpegConfig={selectedFfmpegConfig}
|
||||||
setSelectedFfmpegConfig={setSelectedFfmpegConfig}
|
setSelectedFfmpegConfig={setSelectedFfmpegConfig}
|
||||||
/>
|
/>
|
||||||
</footer >
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +1,13 @@
|
|||||||
#root {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
html {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
margin: auto;
|
margin: 0;
|
||||||
padding-top: 1rem;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
max-width: none;
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
min-height: 100vh;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
|
||||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
|
||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
a.unset {
|
|
||||||
color: unset;
|
|
||||||
text-decoration: unset;
|
|
||||||
}
|
|
||||||
a.active {
|
|
||||||
color: deeppink;
|
|
||||||
background-color: lightgray;
|
|
||||||
border-radius: 0.39em 0.39em 0 0;
|
|
||||||
}
|
|
||||||
td.clickable {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
div.clickable {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
div.page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
div.search_toolbar {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-end;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
div.feedback {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
button.refresh {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
padding-bottom: 0.5em;
|
|
||||||
padding-top: 0.5em;
|
|
||||||
}
|
|
||||||
dialog {
|
|
||||||
border: solid;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import 'water.css';
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
import 'water.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
|
|||||||
Reference in New Issue
Block a user