mirror of
https://github.com/wgh136/nysoure.git
synced 2025-12-16 07:51:14 +00:00
Compare commits
9 Commits
ecfea63edd
...
ddd856529b
| Author | SHA1 | Date | |
|---|---|---|---|
| ddd856529b | |||
| 48638111ec | |||
| d255ecc503 | |||
| 00321b01c3 | |||
| 59904223b4 | |||
| b732e1be83 | |||
| fd86d6c221 | |||
| fbe8ac27bf | |||
| fb1f47c0c0 |
@@ -32,4 +32,7 @@ BACKUP_SCHEDULE=0 2 * * *
|
|||||||
BACKUP_RETENTION_DAYS=30
|
BACKUP_RETENTION_DAYS=30
|
||||||
|
|
||||||
# Download Configuration
|
# Download Configuration
|
||||||
DOWNLOAD_SECRET_KEY=your_download_secret_key_here
|
DOWNLOAD_SECRET_KEY=your_download_secret_key_here
|
||||||
|
|
||||||
|
# Access Key for Development API
|
||||||
|
DEV_ACCESS_KEY=your_dev_access_key_here
|
||||||
1
main.go
1
main.go
@@ -42,6 +42,7 @@ func main() {
|
|||||||
api.AddActivityRoutes(apiG)
|
api.AddActivityRoutes(apiG)
|
||||||
api.AddCollectionRoutes(apiG)
|
api.AddCollectionRoutes(apiG)
|
||||||
api.AddProxyRoutes(apiG)
|
api.AddProxyRoutes(apiG)
|
||||||
|
api.AddDevAPI(apiG)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Fatal(app.Listen(":3000"))
|
log.Fatal(app.Listen(":3000"))
|
||||||
|
|||||||
29
server/api/dev.go
Normal file
29
server/api/dev.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"nysoure/server/middleware"
|
||||||
|
|
||||||
|
"nysoure/server/search"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rebuildSearchIndex(c fiber.Ctx) error {
|
||||||
|
err := search.RebuildSearchIndex()
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Failed to rebuild search index: " + err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"message": "Search index rebuilt successfully",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddDevAPI(router fiber.Router) {
|
||||||
|
devGroup := router.Group("/dev")
|
||||||
|
devGroup.Use(middleware.DevMiddleware())
|
||||||
|
{
|
||||||
|
devGroup.Post("/rebuild_search_index", rebuildSearchIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -287,7 +287,11 @@ func handleGetCharactersFromVndb(c fiber.Ctx) error {
|
|||||||
if vnID == "" {
|
if vnID == "" {
|
||||||
return model.NewRequestError("VNDB ID is required")
|
return model.NewRequestError("VNDB ID is required")
|
||||||
}
|
}
|
||||||
characters, err := service.GetCharactersFromVndb(vnID)
|
uid, ok := c.Locals("uid").(uint)
|
||||||
|
if !ok {
|
||||||
|
return model.NewUnAuthorizedError("You must be logged in to get characters from VNDB")
|
||||||
|
}
|
||||||
|
characters, err := service.GetCharactersFromVndb(vnID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
22
server/middleware/dev_middleware.go
Normal file
22
server/middleware/dev_middleware.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"nysoure/server/model"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DevMiddleware() func(c fiber.Ctx) error {
|
||||||
|
AccessKey := os.Getenv("DEV_ACCESS_KEY")
|
||||||
|
return func(c fiber.Ctx) error {
|
||||||
|
if AccessKey == "" {
|
||||||
|
return model.NewUnAuthorizedError("Unauthorized")
|
||||||
|
}
|
||||||
|
providedKey := c.Get("X-DEV-ACCESS-KEY")
|
||||||
|
if providedKey != AccessKey {
|
||||||
|
return model.NewUnAuthorizedError("Unauthorized")
|
||||||
|
}
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,30 +3,54 @@ package search
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"nysoure/server/dao"
|
"nysoure/server/dao"
|
||||||
"nysoure/server/model"
|
"nysoure/server/model"
|
||||||
"nysoure/server/utils"
|
"nysoure/server/utils"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/blevesearch/bleve"
|
"github.com/blevesearch/bleve"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
index bleve.Index
|
||||||
|
mu = sync.RWMutex{}
|
||||||
|
)
|
||||||
|
|
||||||
type ResourceParams struct {
|
type ResourceParams struct {
|
||||||
Id uint
|
Id uint
|
||||||
Title string
|
Title string
|
||||||
Subtitles []string
|
Subtitles []string
|
||||||
Time time.Time
|
Time time.Time
|
||||||
|
Characters []ResourceCharacter
|
||||||
}
|
}
|
||||||
|
|
||||||
var index bleve.Index
|
type ResourceCharacter struct {
|
||||||
|
Name string
|
||||||
|
Alias []string
|
||||||
|
CV string
|
||||||
|
}
|
||||||
|
|
||||||
func AddResourceToIndex(r model.Resource) error {
|
func AddResourceToIndex(r model.Resource) error {
|
||||||
|
mu.RLock()
|
||||||
|
defer mu.RUnlock()
|
||||||
|
cs := make([]ResourceCharacter, 0, len(r.Characters))
|
||||||
|
for _, c := range r.Characters {
|
||||||
|
cs = append(cs, ResourceCharacter{
|
||||||
|
Name: c.Name,
|
||||||
|
Alias: c.Alias,
|
||||||
|
CV: c.CV,
|
||||||
|
})
|
||||||
|
}
|
||||||
return index.Index(fmt.Sprintf("%d", r.ID), ResourceParams{
|
return index.Index(fmt.Sprintf("%d", r.ID), ResourceParams{
|
||||||
Id: r.ID,
|
Id: r.ID,
|
||||||
Title: r.Title,
|
Title: r.Title,
|
||||||
Subtitles: r.AlternativeTitles,
|
Subtitles: r.AlternativeTitles,
|
||||||
Time: r.CreatedAt,
|
Time: r.CreatedAt,
|
||||||
|
Characters: cs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,16 +64,25 @@ func createIndex() error {
|
|||||||
}
|
}
|
||||||
page := 1
|
page := 1
|
||||||
total := 1
|
total := 1
|
||||||
|
current := 0
|
||||||
for page <= total {
|
for page <= total {
|
||||||
res, totalPages, err := dao.GetResourceList(page, 100, model.RSortTimeAsc)
|
res, totalPages, err := dao.GetResourceList(page, 100, model.RSortTimeAsc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, r := range res {
|
for _, r := range res {
|
||||||
err := AddResourceToIndex(r)
|
r, err := dao.GetResourceByID(r.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = AddResourceToIndex(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
current++
|
||||||
|
if current%20 == 0 {
|
||||||
|
slog.Info("Rebuilding search index", "current", current, "total", totalPages*100)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
page++
|
page++
|
||||||
total = totalPages
|
total = totalPages
|
||||||
@@ -80,6 +113,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SearchResource(keyword string) ([]uint, error) {
|
func SearchResource(keyword string) ([]uint, error) {
|
||||||
|
mu.RLock()
|
||||||
|
defer mu.RUnlock()
|
||||||
query := bleve.NewMatchQuery(keyword)
|
query := bleve.NewMatchQuery(keyword)
|
||||||
searchRequest := bleve.NewSearchRequest(query)
|
searchRequest := bleve.NewSearchRequest(query)
|
||||||
searchResults, err := index.Search(searchRequest)
|
searchResults, err := index.Search(searchRequest)
|
||||||
@@ -112,3 +147,24 @@ func IsStopWord(word string) bool {
|
|||||||
tokens := analyzer.Analyze([]byte(word))
|
tokens := analyzer.Analyze([]byte(word))
|
||||||
return len(tokens) == 0
|
return len(tokens) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RebuildSearchIndex() error {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
err := index.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to close search index: %w", err)
|
||||||
|
}
|
||||||
|
indexPath := utils.GetStoragePath() + "/resource_index.bleve"
|
||||||
|
err = os.RemoveAll(indexPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to remove search index: %w", err)
|
||||||
|
}
|
||||||
|
mapping := bleve.NewIndexMapping()
|
||||||
|
index, err = bleve.New(indexPath, mapping)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create search index: %w", err)
|
||||||
|
}
|
||||||
|
go createIndex()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -615,7 +615,15 @@ func GetPinnedResources() ([]model.ResourceView, error) {
|
|||||||
return views, nil
|
return views, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCharactersFromVndb(vnID string) ([]CharacterParams, error) {
|
func GetCharactersFromVndb(vnID string, uid uint) ([]CharacterParams, error) {
|
||||||
|
canUpload, err := checkUserCanUpload(uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !canUpload {
|
||||||
|
return nil, model.NewUnAuthorizedError("You have not permission to fetch characters from VNDB")
|
||||||
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
jsonStr := fmt.Sprintf(`
|
jsonStr := fmt.Sprintf(`
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user