Add: support select ramdom files by tag
This commit is contained in:
@@ -72,6 +72,7 @@ func NewAPI(config Config) (*API, error) {
|
|||||||
apiMux.HandleFunc("/search_folders", api.HandleSearchFolders)
|
apiMux.HandleFunc("/search_folders", api.HandleSearchFolders)
|
||||||
apiMux.HandleFunc("/get_files_in_folder", api.HandleGetFilesInFolder)
|
apiMux.HandleFunc("/get_files_in_folder", api.HandleGetFilesInFolder)
|
||||||
apiMux.HandleFunc("/get_random_files", api.HandleGetRandomFiles)
|
apiMux.HandleFunc("/get_random_files", api.HandleGetRandomFiles)
|
||||||
|
apiMux.HandleFunc("/get_random_files_with_tag", api.HandleGetRandomFilesWithTag)
|
||||||
apiMux.HandleFunc("/get_file_stream", api.HandleGetFileStream)
|
apiMux.HandleFunc("/get_file_stream", api.HandleGetFileStream)
|
||||||
apiMux.HandleFunc("/get_ffmpeg_config_list", api.HandleGetFfmpegConfigs)
|
apiMux.HandleFunc("/get_ffmpeg_config_list", api.HandleGetFfmpegConfigs)
|
||||||
apiMux.HandleFunc("/feedback", api.HandleFeedback)
|
apiMux.HandleFunc("/feedback", api.HandleFeedback)
|
||||||
|
|||||||
@@ -23,3 +23,29 @@ func (api *API) HandleGetRandomFiles(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Println("[api] Get random files")
|
log.Println("[api] Get random files")
|
||||||
json.NewEncoder(w).Encode(getRandomFilesResponse)
|
json.NewEncoder(w).Encode(getRandomFilesResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetRandomFilesWithTagRequest struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) HandleGetRandomFilesWithTag(w http.ResponseWriter, r *http.Request) {
|
||||||
|
req := &GetRandomFilesWithTagRequest{}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(req)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := api.Db.GetRandomFilesWithTag(req.ID, 10)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomFilesResponse := &GetRandomFilesResponse{
|
||||||
|
Files: &files,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("[api] Get random files with tag", req.ID)
|
||||||
|
json.NewEncoder(w).Encode(getRandomFilesResponse)
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,28 @@ func (database *Database) GetRandomFiles(limit int64) ([]File, error) {
|
|||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (database *Database) GetRandomFilesWithTag(tagID, limit int64) ([]File, error) {
|
||||||
|
rows, err := database.stmt.getRandomFilesWithTag.Query(tagID, limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
files := make([]File, 0)
|
||||||
|
for rows.Next() {
|
||||||
|
file := File{
|
||||||
|
Db: database,
|
||||||
|
}
|
||||||
|
err = rows.Scan(&file.ID, &file.Folder_id, &file.Filename, &file.Foldername, &file.Filesize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
files = append(files, file)
|
||||||
|
log.Println("[db] GetRandomFilesWithTag", file.ID, file.Filename, file.Foldername, file.Filesize)
|
||||||
|
}
|
||||||
|
log.Println("[db] GetRandomFilesWithTag", files)
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (database *Database) GetFilesInFolder(folder_id int64, limit int64, offset int64) ([]File, error) {
|
func (database *Database) GetFilesInFolder(folder_id int64, limit int64, offset int64) ([]File, error) {
|
||||||
rows, err := database.stmt.getFilesInFolder.Query(folder_id, limit, offset)
|
rows, err := database.stmt.getFilesInFolder.Query(folder_id, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -158,6 +158,15 @@ JOIN folders ON files.folder_id = folders.id
|
|||||||
ORDER BY RANDOM()
|
ORDER BY RANDOM()
|
||||||
LIMIT ?;`
|
LIMIT ?;`
|
||||||
|
|
||||||
|
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 = ?
|
||||||
|
ORDER BY RANDOM()
|
||||||
|
LIMIT ?;`
|
||||||
|
|
||||||
var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback, header)
|
var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback, header)
|
||||||
VALUES (?, ?, ?);`
|
VALUES (?, ?, ?);`
|
||||||
|
|
||||||
@@ -236,51 +245,52 @@ ORDER BY reviews.created_at
|
|||||||
;`
|
;`
|
||||||
|
|
||||||
type Stmt struct {
|
type Stmt struct {
|
||||||
initFilesTable *sql.Stmt
|
initFilesTable *sql.Stmt
|
||||||
initFoldersTable *sql.Stmt
|
initFoldersTable *sql.Stmt
|
||||||
initFeedbacksTable *sql.Stmt
|
initFeedbacksTable *sql.Stmt
|
||||||
initUsersTable *sql.Stmt
|
initUsersTable *sql.Stmt
|
||||||
initAvatarsTable *sql.Stmt
|
initAvatarsTable *sql.Stmt
|
||||||
initTagsTable *sql.Stmt
|
initTagsTable *sql.Stmt
|
||||||
initFileHasTag *sql.Stmt
|
initFileHasTag *sql.Stmt
|
||||||
initLikesTable *sql.Stmt
|
initLikesTable *sql.Stmt
|
||||||
initReviewsTable *sql.Stmt
|
initReviewsTable *sql.Stmt
|
||||||
initPlaybacksTable *sql.Stmt
|
initPlaybacksTable *sql.Stmt
|
||||||
initLogsTable *sql.Stmt
|
initLogsTable *sql.Stmt
|
||||||
initTmpfsTable *sql.Stmt
|
initTmpfsTable *sql.Stmt
|
||||||
insertFolder *sql.Stmt
|
insertFolder *sql.Stmt
|
||||||
insertFile *sql.Stmt
|
insertFile *sql.Stmt
|
||||||
findFolder *sql.Stmt
|
findFolder *sql.Stmt
|
||||||
findFile *sql.Stmt
|
findFile *sql.Stmt
|
||||||
searchFiles *sql.Stmt
|
searchFiles *sql.Stmt
|
||||||
getFolder *sql.Stmt
|
getFolder *sql.Stmt
|
||||||
dropFiles *sql.Stmt
|
dropFiles *sql.Stmt
|
||||||
dropFolder *sql.Stmt
|
dropFolder *sql.Stmt
|
||||||
getFile *sql.Stmt
|
getFile *sql.Stmt
|
||||||
searchFolders *sql.Stmt
|
searchFolders *sql.Stmt
|
||||||
getFilesInFolder *sql.Stmt
|
getFilesInFolder *sql.Stmt
|
||||||
getRandomFiles *sql.Stmt
|
getRandomFiles *sql.Stmt
|
||||||
insertFeedback *sql.Stmt
|
getRandomFilesWithTag *sql.Stmt
|
||||||
insertUser *sql.Stmt
|
insertFeedback *sql.Stmt
|
||||||
countUser *sql.Stmt
|
insertUser *sql.Stmt
|
||||||
countAdmin *sql.Stmt
|
countUser *sql.Stmt
|
||||||
getUser *sql.Stmt
|
countAdmin *sql.Stmt
|
||||||
getUserById *sql.Stmt
|
getUser *sql.Stmt
|
||||||
getAnonymousUser *sql.Stmt
|
getUserById *sql.Stmt
|
||||||
insertTag *sql.Stmt
|
getAnonymousUser *sql.Stmt
|
||||||
getTag *sql.Stmt
|
insertTag *sql.Stmt
|
||||||
getTags *sql.Stmt
|
getTag *sql.Stmt
|
||||||
updateTag *sql.Stmt
|
getTags *sql.Stmt
|
||||||
putTagOnFile *sql.Stmt
|
updateTag *sql.Stmt
|
||||||
getTagsOnFile *sql.Stmt
|
putTagOnFile *sql.Stmt
|
||||||
deleteTagOnFile *sql.Stmt
|
getTagsOnFile *sql.Stmt
|
||||||
updateFoldername *sql.Stmt
|
deleteTagOnFile *sql.Stmt
|
||||||
insertReview *sql.Stmt
|
updateFoldername *sql.Stmt
|
||||||
getReviewsOnFile *sql.Stmt
|
insertReview *sql.Stmt
|
||||||
getReview *sql.Stmt
|
getReviewsOnFile *sql.Stmt
|
||||||
updateReview *sql.Stmt
|
getReview *sql.Stmt
|
||||||
deleteReview *sql.Stmt
|
updateReview *sql.Stmt
|
||||||
getReviewsByUser *sql.Stmt
|
deleteReview *sql.Stmt
|
||||||
|
getReviewsByUser *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
||||||
@@ -482,6 +492,12 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init getRandomFilesWithTag
|
||||||
|
stmt.getRandomFilesWithTag, err = sqlConn.Prepare(getRandomFilesWithTagQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// init insertFeedback
|
// init insertFeedback
|
||||||
stmt.insertFeedback, err = sqlConn.Prepare(insertFeedbackQuery)
|
stmt.insertFeedback, err = sqlConn.Prepare(insertFeedbackQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import FilesTable from "./FilesTable";
|
|||||||
function GetRandomFiles(props) {
|
function GetRandomFiles(props) {
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [tags, setTags] = useState([]);
|
||||||
|
const [selectedTag, setSelectedTag] = useState("");
|
||||||
|
|
||||||
function refresh(setFiles) {
|
function getRandomFiles() {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
fetch("/api/v1/get_random_files")
|
fetch("/api/v1/get_random_files")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
@@ -20,15 +22,79 @@ function GetRandomFiles(props) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRandomFilesWithTag() {
|
||||||
|
setIsLoading(true);
|
||||||
|
fetch("/api/v1/get_random_files_with_tag", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: parseInt(selectedTag),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
alert(data.error);
|
||||||
|
} else {
|
||||||
|
setFiles(data.files);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
alert("get_random_files_with_tag error: " + error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
if (selectedTag === "") {
|
||||||
|
getRandomFiles();
|
||||||
|
} else {
|
||||||
|
getRandomFilesWithTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTags() {
|
||||||
|
fetch("/api/v1/get_tags")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
setTags(data.tags);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
alert("get_tags error: " + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refresh(setFiles);
|
getTags();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
}, [selectedTag]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<div className="search_toolbar">
|
<div className="search_toolbar">
|
||||||
<button className="refresh" onClick={() => refresh(setFiles)}>
|
<button className="refresh" onClick={() => refresh(setFiles)}>
|
||||||
{isLoading ? "Loading..." : "Refresh"}
|
{isLoading ? "Loading..." : "Refresh"}
|
||||||
</button>
|
</button>
|
||||||
|
<select
|
||||||
|
className="tag_select"
|
||||||
|
onChange={(event) => {
|
||||||
|
setSelectedTag(event.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="">All</option>
|
||||||
|
{tags.map((tag) => (
|
||||||
|
<option key={tag.id} value={tag.id}>
|
||||||
|
{tag.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<FilesTable setPlayingFile={props.setPlayingFile} files={files} />
|
<FilesTable setPlayingFile={props.setPlayingFile} files={files} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user