This commit is contained in:
afkarxyz
2026-01-15 11:03:27 +07:00
parent d9cf5a5361
commit b160d3c790
34 changed files with 2368 additions and 1293 deletions
+43
View File
@@ -162,3 +162,46 @@ func GetFileSize(filepath string) (int64, error) {
}
return info.Size(), nil
}
func GetTrackMetadata(filepath string) (*AnalysisResult, error) {
if !fileExists(filepath) {
return nil, fmt.Errorf("file does not exist: %s", filepath)
}
fileInfo, err := os.Stat(filepath)
if err != nil {
return nil, fmt.Errorf("failed to get file info: %w", err)
}
f, err := flac.ParseFile(filepath)
if err != nil {
return nil, fmt.Errorf("failed to parse FLAC file: %w", err)
}
result := &AnalysisResult{
FilePath: filepath,
FileSize: fileInfo.Size(),
}
if len(f.Meta) > 0 {
streamInfo := f.Meta[0]
if streamInfo.Type == flac.StreamInfo {
data := streamInfo.Data
if len(data) >= 18 {
result.SampleRate = uint32(data[10])<<12 | uint32(data[11])<<4 | uint32(data[12])>>4
result.BitsPerSample = ((data[12]&0x01)<<4 | data[13]>>4) + 1
result.TotalSamples = uint64(data[13]&0x0F)<<32 |
uint64(data[14])<<24 |
uint64(data[15])<<16 |
uint64(data[16])<<8 |
uint64(data[17])
if result.SampleRate > 0 {
result.Duration = float64(result.TotalSamples) / float64(result.SampleRate)
}
}
}
}
result.BitDepth = fmt.Sprintf("%d-bit", result.BitsPerSample)
return result, nil
}
+149
View File
@@ -0,0 +1,149 @@
package backend
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
"time"
bolt "go.etcd.io/bbolt"
)
type HistoryItem struct {
ID string `json:"id"`
SpotifyID string `json:"spotify_id"`
Title string `json:"title"`
Artists string `json:"artists"`
Album string `json:"album"`
DurationStr string `json:"duration_str"`
CoverURL string `json:"cover_url"`
Quality string `json:"quality"`
Format string `json:"format"`
Path string `json:"path"`
Timestamp int64 `json:"timestamp"`
}
var historyDB *bolt.DB
const (
historyBucket = "DownloadHistory"
maxHistory = 10000
)
func InitHistoryDB(appName string) error {
appDir, err := GetFFmpegDir()
if err != nil {
return err
}
if _, err := os.Stat(appDir); os.IsNotExist(err) {
os.MkdirAll(appDir, 0755)
}
dbPath := filepath.Join(appDir, "history.db")
db, err := bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
return err
}
err = db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(historyBucket))
return err
})
if err != nil {
db.Close()
return err
}
historyDB = db
return nil
}
func CloseHistoryDB() {
if historyDB != nil {
historyDB.Close()
}
}
func AddHistoryItem(item HistoryItem, appName string) error {
if historyDB == nil {
if err := InitHistoryDB(appName); err != nil {
return err
}
}
return historyDB.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(historyBucket))
id, _ := b.NextSequence()
item.ID = fmt.Sprintf("%d-%d", time.Now().UnixNano(), id)
item.Timestamp = time.Now().Unix()
buf, err := json.Marshal(item)
if err != nil {
return err
}
if b.Stats().KeyN >= maxHistory {
c := b.Cursor()
toDelete := maxHistory / 20
if toDelete < 1 {
toDelete = 1
}
count := 0
for k, _ := c.First(); k != nil && count < toDelete; k, _ = c.Next() {
if err := b.Delete(k); err != nil {
return err
}
count++
}
}
return b.Put([]byte(item.ID), buf)
})
}
func GetHistoryItems(appName string) ([]HistoryItem, error) {
if historyDB == nil {
if err := InitHistoryDB(appName); err != nil {
return nil, err
}
}
var items []HistoryItem
err := historyDB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(historyBucket))
if b == nil {
return nil
}
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
var item HistoryItem
if err := json.Unmarshal(v, &item); err == nil {
items = append(items, item)
}
}
return nil
})
sort.Slice(items, func(i, j int) bool {
return items[i].Timestamp > items[j].Timestamp
})
return items, err
}
func ClearHistory(appName string) error {
if historyDB == nil {
if err := InitHistoryDB(appName); err != nil {
return err
}
}
return historyDB.Update(func(tx *bolt.Tx) error {
return tx.DeleteBucket([]byte(historyBucket))
})
}