Add play button to video thumbnails and implement video streaming endpoint
This commit is contained in:
parent
9100d11bbf
commit
e17b9f3ec4
@ -58,6 +58,25 @@
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.play-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 80px; /* Adjust size as needed */
|
||||||
|
height: 80px; /* Adjust size as needed */
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E");
|
||||||
|
background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent background */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: 50%; /* Adjust icon size within button */
|
||||||
|
border-radius: 50%; /* Circular button */
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 3; /* Ensure it's above the video thumbnails */
|
||||||
|
border: 2px solid white;
|
||||||
|
box-shadow: 0 0 15px rgba(0,0,0,0.7);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
function hideLoader() {
|
function hideLoader() {
|
||||||
@ -91,6 +110,7 @@
|
|||||||
<img id="prev-thumb" class="video-thumbnail side-video" alt="Previous Video">
|
<img id="prev-thumb" class="video-thumbnail side-video" alt="Previous Video">
|
||||||
<img id="current-thumb" class="video-thumbnail current-video" alt="Current Video">
|
<img id="current-thumb" class="video-thumbnail current-video" alt="Current Video">
|
||||||
<img id="next-thumb" class="video-thumbnail side-video" alt="Next Video">
|
<img id="next-thumb" class="video-thumbnail side-video" alt="Next Video">
|
||||||
|
<div class="play-button" id="play-button"></div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
105
webview.go
105
webview.go
@ -1,10 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"gitea.seeseepuff.be/seeseemelk/mysqlite"
|
"gitea.seeseepuff.be/seeseemelk/mysqlite"
|
||||||
"github.com/donseba/go-htmx"
|
"github.com/donseba/go-htmx"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
@ -23,6 +28,7 @@ func serveWebview(db *mysqlite.Db) {
|
|||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
router.StaticFile("/", "static/index.html")
|
router.StaticFile("/", "static/index.html")
|
||||||
|
router.GET("/stream/:id", app.serveStream)
|
||||||
|
|
||||||
api := router.Group("/api")
|
api := router.Group("/api")
|
||||||
api.GET("/homepage", app.homePage)
|
api.GET("/homepage", app.homePage)
|
||||||
@ -47,6 +53,7 @@ func serveWebview(db *mysqlite.Db) {
|
|||||||
type VideoModel struct {
|
type VideoModel struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Thumbnail string `json:"thumbnail"`
|
Thumbnail string `json:"thumbnail"`
|
||||||
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HomePageModel struct {
|
type HomePageModel struct {
|
||||||
@ -63,6 +70,7 @@ func (a *App) homePage(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
model.CurrentVideo.Thumbnail = "https://imgproxy.fourthwall.com/GHX1MSukwJHMQeiqcJLZL906v2--re7qQbQIlHgy5jY/rs:fill:607:342:0/q:90/sm:1/enc/NDJiMWM5YzU3ODJh/MzgzZXFIti10srar/EYcgeYXIe6MXrQge/VBPZVk3b6DCE53dq/VGponLkc45F9743G/4la9S4IjbcNxs4lF/WnLXCMzFhaSUaZnL/Og4de_FSYxQOtzCC/0pfkgH1g4FJfajde/KrZfes95EWXzg9sP/kvEwcqro2EM.webp"
|
model.CurrentVideo.Thumbnail = "https://imgproxy.fourthwall.com/GHX1MSukwJHMQeiqcJLZL906v2--re7qQbQIlHgy5jY/rs:fill:607:342:0/q:90/sm:1/enc/NDJiMWM5YzU3ODJh/MzgzZXFIti10srar/EYcgeYXIe6MXrQge/VBPZVk3b6DCE53dq/VGponLkc45F9743G/4la9S4IjbcNxs4lF/WnLXCMzFhaSUaZnL/Og4de_FSYxQOtzCC/0pfkgH1g4FJfajde/KrZfes95EWXzg9sP/kvEwcqro2EM.webp"
|
||||||
|
model.CurrentVideo.URL = fmt.Sprintf("/stream/%d", model.CurrentVideo.ID)
|
||||||
|
|
||||||
c.JSON(200, model)
|
c.JSON(200, model)
|
||||||
}
|
}
|
||||||
@ -178,52 +186,57 @@ func (a *App) homePage(c *gin.Context) {
|
|||||||
// }
|
// }
|
||||||
// a.renderTemplate(w, "video", vm)
|
// a.renderTemplate(w, "video", vm)
|
||||||
//}
|
//}
|
||||||
//
|
|
||||||
//func (a *App) serveStream(w http.ResponseWriter, r *http.Request) {
|
func (a *App) serveStream(c *gin.Context) {
|
||||||
// // Parse the video ID from the URL
|
// Parse the video ID from the URL
|
||||||
// pathParts := strings.Split(r.URL.Path, "/")
|
idStr := c.Param("id")
|
||||||
// if len(pathParts) < 3 {
|
videoID, err := strconv.Atoi(idStr)
|
||||||
// http.Error(w, "Invalid video ID", http.StatusBadRequest)
|
if err != nil {
|
||||||
// return
|
log.Printf("Failed to parse video ID: %v", err)
|
||||||
// }
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid video ID"})
|
||||||
//
|
return
|
||||||
// videoIDStr := pathParts[2]
|
}
|
||||||
// videoID, err := strconv.Atoi(videoIDStr)
|
|
||||||
// if err != nil {
|
// Get video metadata from database
|
||||||
// http.Error(w, "Invalid video ID", http.StatusBadRequest)
|
var year, episode int
|
||||||
// return
|
err = a.db.Query(`SELECT year, episode FROM videos WHERE id = ?`).Bind(videoID).ScanSingle(&year, &episode)
|
||||||
// }
|
if err != nil {
|
||||||
//
|
log.Printf("Failed to find video: %v", err)
|
||||||
// // Get video metadata from database
|
c.JSON(http.StatusNotFound, gin.H{"error": "Video not found"})
|
||||||
// var year, episode int
|
return
|
||||||
// err = a.db.Query(`SELECT year, episode FROM videos WHERE id = ?`).Bind(videoID).ScanSingle(&year, &episode)
|
}
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, "Video not found", http.StatusNotFound)
|
// Determine the video file path
|
||||||
// return
|
downloadDir := os.Getenv("VIVAPLUS_DESTINATION")
|
||||||
// }
|
if downloadDir == "" {
|
||||||
//
|
downloadDir = "./downloads"
|
||||||
// // Determine the video file path
|
}
|
||||||
// downloadDir := os.Getenv("VIVAPLUS_DESTINATION")
|
|
||||||
// if downloadDir == "" {
|
seasonDir := filepath.Join(downloadDir, fmt.Sprintf("Season %d", year))
|
||||||
// downloadDir = "./downloads"
|
videoFilename := fmt.Sprintf("S%dE%03d.mp4", year, episode)
|
||||||
// }
|
videoPath := filepath.Join(seasonDir, videoFilename)
|
||||||
//
|
|
||||||
// seasonDir := filepath.Join(downloadDir, fmt.Sprintf("Season %d", year))
|
// Check if the file exists
|
||||||
// videoFilename := fmt.Sprintf("S%dE%03d.mp4", year, episode)
|
log.Printf("Streaming video: %s", videoPath)
|
||||||
// videoPath := filepath.Join(seasonDir, videoFilename)
|
_, err = os.Stat(videoPath)
|
||||||
//
|
if os.IsNotExist(err) {
|
||||||
// // Check if the file exists
|
log.Printf("Video file not found: %s", videoPath)
|
||||||
// log.Printf("Streaming video: %s", videoPath)
|
c.JSON(http.StatusNotFound, gin.H{"error": "Video file not found"})
|
||||||
// _, err = os.Stat(videoPath)
|
return
|
||||||
// if os.IsNotExist(err) {
|
}
|
||||||
// http.Error(w, "Video file not found", http.StatusNotFound)
|
|
||||||
// return
|
// Serve the file
|
||||||
// }
|
w := c.Writer
|
||||||
//
|
r := c.Request
|
||||||
// // Serve the file
|
w.Header().Set("Content-Type", "video/mp4")
|
||||||
// http.ServeFile(w, r, videoPath)
|
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", videoFilename))
|
||||||
//}
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
//
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
w.Header().Set("Expires", "0")
|
||||||
|
log.Printf("Serving video file: %s", videoPath)
|
||||||
|
http.ServeFile(w, r, videoPath)
|
||||||
|
}
|
||||||
|
|
||||||
//func (a *App) handleMarkWatched(w http.ResponseWriter, r *http.Request) {
|
//func (a *App) handleMarkWatched(w http.ResponseWriter, r *http.Request) {
|
||||||
// // Only handle POST requests
|
// // Only handle POST requests
|
||||||
// if r.Method != http.MethodPost {
|
// if r.Method != http.MethodPost {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user