mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-06 21:36:37 +08:00
feat: port remaining Vue UI surfaces with full backend support
Backend additions:
- New GORM models: NotifyChannel, PlayProfile (with PIN hashing).
- NotifyChannelService: multi-channel CRUD + unified dispatcher
supporting Telegram / Bark / WeChat / Webhook with optional
per-channel event filtering.
- PlayProfileService: per-user 'viewing personas' with
content-rating gates, library scoping, PIN protection, and
player defaults (autoplay, skip-intro, audio/subtitle prefs).
- New endpoints:
GET /admin/notify/channels list
POST /admin/notify/channels create
PUT /admin/notify/channels/:id update
DELETE /admin/notify/channels/:id delete
POST /admin/notify/channels/:id/test send test
GET /play-profiles list (admin: ?all=true)
POST /play-profiles create
PUT /play-profiles/:id update
DELETE /play-profiles/:id delete
GET /media/recent home page rail
GET /media/stats library composition
GET /watch-history list
GET /watch-history/stats aggregate
GET /watch-history/continue continue-watching rail
DELETE /watch-history[?media_id=] clear
DELETE /watch-history/:id remove one
GET /discover/sections available rails
GET /discover/feed?sections=a,b multi-section TMDb fetch
GET /system/info name/version/runtime
GET /system/status uptime/cpu/mem/disk
GET /system/scheduler read-only scheduler view
GET /stats/overview counts only
GET /stats/trend daily plays
GET /stats/top-content most played
GET /stats/libraries per-library size
GET /stats/monitor live hardware
Frontend additions:
- New API helpers: notify_channels, play_profiles, history,
stats_extra, media_extra, discover_extra, system.
- ProfileManagementPage (/play-profiles): full CRUD form with
PIN management, library scoping, language preferences.
- NotifyChannelsPage (/notify-channels, admin): typed config
forms per channel type + per-channel test action.
- SettingsPage (/settings, admin): grouped key/value editor
covering General, Organize/Scrape, Adult, qBittorrent.
- Layout sidebar links and App.tsx routes wired for all three.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// Package handler — auxiliary media endpoints used by the home page
|
||||
// rails (recent additions) and the admin dashboard summary card.
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/service"
|
||||
)
|
||||
|
||||
func recentMediaHandler(svc *service.Container) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "12"))
|
||||
if limit <= 0 || limit > 100 {
|
||||
limit = 12
|
||||
}
|
||||
var items []model.Media
|
||||
if err := svc.Repo.DB.Order("created_at desc").Limit(limit).Find(&items).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, items)
|
||||
}
|
||||
}
|
||||
|
||||
func mediaStatsHandler(svc *service.Container) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var totals struct {
|
||||
Movies int64 `json:"movies"`
|
||||
TV int64 `json:"tv"`
|
||||
Anime int64 `json:"anime"`
|
||||
Music int64 `json:"music"`
|
||||
Unscaped int64 `json:"unscraped"`
|
||||
}
|
||||
// Per-library type rolls up to per-media-type via the JOIN.
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Joins("JOIN libraries ON libraries.id = media.library_id").
|
||||
Where("libraries.type = ?", "movie").Count(&totals.Movies).Error
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Joins("JOIN libraries ON libraries.id = media.library_id").
|
||||
Where("libraries.type = ?", "tv").Count(&totals.TV).Error
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Joins("JOIN libraries ON libraries.id = media.library_id").
|
||||
Where("libraries.type = ?", "anime").Count(&totals.Anime).Error
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Joins("JOIN libraries ON libraries.id = media.library_id").
|
||||
Where("libraries.type = ?", "music").Count(&totals.Music).Error
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Where("scrape_status IS NULL OR scrape_status = '' OR scrape_status = 'pending'").
|
||||
Count(&totals.Unscaped).Error
|
||||
|
||||
var totalCount, totalSize, totalSeconds int64
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).Count(&totalCount).Error
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Select("COALESCE(SUM(size_bytes),0)").Row().Scan(&totalSize)
|
||||
_ = svc.Repo.DB.Model(&model.Media{}).
|
||||
Select("COALESCE(SUM(duration_sec),0)").Row().Scan(&totalSeconds)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"by_type": totals,
|
||||
"total": totalCount,
|
||||
"total_size": totalSize,
|
||||
"total_seconds": totalSeconds,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user