implement full load of videos and startdata
modify api where necessary
This commit is contained in:
72
apiGo/api/Actors.go
Normal file
72
apiGo/api/Actors.go
Normal file
@ -0,0 +1,72 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
"openmediacenter/apiGo/database"
|
||||
)
|
||||
|
||||
func AddActorsHandlers() {
|
||||
saveActorsToDB()
|
||||
getActorsFromDB()
|
||||
}
|
||||
|
||||
func getActorsFromDB() {
|
||||
AddHandler("getAllActors", ActorNode, nil, func() []byte {
|
||||
query := "SELECT actor_id, name, thumbnail FROM actors"
|
||||
return jsonify(readActorsFromResultset(database.Query(query)))
|
||||
})
|
||||
|
||||
var gaov struct {
|
||||
MovieId int
|
||||
}
|
||||
AddHandler("getActorsOfVideo", ActorNode, &gaov, func() []byte {
|
||||
query := fmt.Sprintf(`SELECT a.actor_id, name, thumbnail FROM actors_videos
|
||||
JOIN actors a on actors_videos.actor_id = a.actor_id
|
||||
WHERE actors_videos.video_id=%d`, gaov.MovieId)
|
||||
|
||||
return jsonify(readActorsFromResultset(database.Query(query)))
|
||||
})
|
||||
|
||||
var gai struct {
|
||||
ActorId int
|
||||
}
|
||||
AddHandler("getActorInfo", ActorNode, &gai, func() []byte {
|
||||
query := fmt.Sprintf(`SELECT movie_id, movie_name FROM actors_videos
|
||||
JOIN videos v on v.movie_id = actors_videos.video_id
|
||||
WHERE actors_videos.actor_id=%d`, gai.ActorId)
|
||||
videos := readVideosFromResultset(database.Query(query))
|
||||
|
||||
query = fmt.Sprintf("SELECT actor_id, name, thumbnail FROM actors WHERE actor_id=%d", gai.ActorId)
|
||||
actor := readActorsFromResultset(database.Query(query))[0]
|
||||
|
||||
var result = struct {
|
||||
Videos []types.VideoUnloadedType
|
||||
Info types.Actor
|
||||
}{
|
||||
Videos: videos,
|
||||
Info: actor,
|
||||
}
|
||||
|
||||
return jsonify(result)
|
||||
})
|
||||
}
|
||||
|
||||
func saveActorsToDB() {
|
||||
var ca struct {
|
||||
ActorName string
|
||||
}
|
||||
AddHandler("createActor", ActorNode, &ca, func() []byte {
|
||||
query := "INSERT IGNORE INTO actors (name) VALUES (?)"
|
||||
return database.SuccessQuery(query, ca.ActorName)
|
||||
})
|
||||
|
||||
var aatv struct {
|
||||
ActorId int
|
||||
MovieId int
|
||||
}
|
||||
AddHandler("addActorToVideo", ActorNode, &aatv, func() []byte {
|
||||
query := fmt.Sprintf("INSERT IGNORE INTO actors_videos (actor_id, video_id) VALUES (%d,%d)", aatv.ActorId, aatv.MovieId)
|
||||
return database.SuccessQuery(query)
|
||||
})
|
||||
}
|
101
apiGo/api/ApiBase.go
Normal file
101
apiGo/api/ApiBase.go
Normal file
@ -0,0 +1,101 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const APIPREFIX = "/api"
|
||||
|
||||
const (
|
||||
VideoNode = iota
|
||||
TagNode = iota
|
||||
SettingsNode = iota
|
||||
ActorNode = iota
|
||||
)
|
||||
|
||||
type actionStruct struct {
|
||||
Action string
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
action string
|
||||
handler func() []byte
|
||||
arguments interface{}
|
||||
apiNode int
|
||||
}
|
||||
|
||||
var handlers []Handler
|
||||
|
||||
func AddHandler(action string, apiNode int, n interface{}, h func() []byte) {
|
||||
// append new handler to the handlers
|
||||
handlers = append(handlers, Handler{action, h, n, apiNode})
|
||||
}
|
||||
|
||||
func ServerInit(port uint16) {
|
||||
http.Handle(APIPREFIX+"/video", http.HandlerFunc(videoHandler))
|
||||
http.Handle(APIPREFIX+"/tags", http.HandlerFunc(tagHandler))
|
||||
http.Handle(APIPREFIX+"/settings", http.HandlerFunc(settingsHandler))
|
||||
http.Handle(APIPREFIX+"/actor", http.HandlerFunc(actorHandler))
|
||||
|
||||
fmt.Printf("OpenMediacenter server up and running on port %d\n", port)
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
||||
}
|
||||
|
||||
func handleAPICall(action string, requestBody string, apiNode int) []byte {
|
||||
for i := range handlers {
|
||||
if handlers[i].action == action && handlers[i].apiNode == apiNode {
|
||||
// call the handler and return
|
||||
|
||||
if handlers[i].arguments != nil {
|
||||
// decode the arguments to the corresponding arguments object
|
||||
err := json.Unmarshal([]byte(requestBody), &handlers[i].arguments)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to decode arguments of action %s :: %s\n", action, requestBody)
|
||||
}
|
||||
}
|
||||
|
||||
return handlers[i].handler()
|
||||
}
|
||||
}
|
||||
fmt.Printf("no handler found for Action: %d/%s\n", apiNode, action)
|
||||
return nil
|
||||
}
|
||||
|
||||
func actorHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
handlefunc(rw, req, ActorNode)
|
||||
}
|
||||
|
||||
func videoHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
handlefunc(rw, req, VideoNode)
|
||||
}
|
||||
|
||||
func tagHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
handlefunc(rw, req, TagNode)
|
||||
}
|
||||
|
||||
func settingsHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
handlefunc(rw, req, SettingsNode)
|
||||
}
|
||||
|
||||
func handlefunc(rw http.ResponseWriter, req *http.Request, node int) {
|
||||
// only allow post requests
|
||||
if req.Method != "POST" {
|
||||
return
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(req.Body)
|
||||
body := buf.String()
|
||||
|
||||
var t actionStruct
|
||||
err := json.Unmarshal([]byte(body), &t)
|
||||
if err != nil {
|
||||
fmt.Println("failed to read action from request! :: " + body)
|
||||
}
|
||||
|
||||
rw.Write(handleAPICall(t.Action, body, node))
|
||||
}
|
66
apiGo/api/ApiBase_test.go
Normal file
66
apiGo/api/ApiBase_test.go
Normal file
@ -0,0 +1,66 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func cleanUp() {
|
||||
handlers = nil
|
||||
}
|
||||
|
||||
func TestAddHandler(t *testing.T) {
|
||||
cleanUp()
|
||||
|
||||
AddHandler("test", ActorNode, nil, func() []byte {
|
||||
return nil
|
||||
})
|
||||
if len(handlers) != 1 {
|
||||
t.Errorf("Handler insertion failed, got: %d handlers, want: %d.", len(handlers), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallOfHandler(t *testing.T) {
|
||||
cleanUp()
|
||||
|
||||
i := 0
|
||||
AddHandler("test", ActorNode, nil, func() []byte {
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
|
||||
// simulate the call of the api
|
||||
handleAPICall("test", "", ActorNode)
|
||||
|
||||
if i != 1 {
|
||||
t.Errorf("Unexpected number of Lambda calls : %d/1", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodingOfArguments(t *testing.T) {
|
||||
cleanUp()
|
||||
|
||||
var myvar struct {
|
||||
Test string
|
||||
TestInt int
|
||||
}
|
||||
AddHandler("test", ActorNode, &myvar, func() []byte {
|
||||
return nil
|
||||
})
|
||||
|
||||
// simulate the call of the api
|
||||
handleAPICall("test", `{"Test":"myString","TestInt":42}`, ActorNode)
|
||||
|
||||
if myvar.TestInt != 42 || myvar.Test != "myString" {
|
||||
t.Errorf("Wrong parsing of argument parameters : %d/42 - %s/myString", myvar.TestInt, myvar.Test)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoHandlerCovers(t *testing.T) {
|
||||
cleanUp()
|
||||
|
||||
ret := handleAPICall("test", "", ActorNode)
|
||||
|
||||
if ret != nil {
|
||||
t.Error("Expect nil return within unhandled api action")
|
||||
}
|
||||
}
|
71
apiGo/api/Helpers.go
Normal file
71
apiGo/api/Helpers.go
Normal file
@ -0,0 +1,71 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
)
|
||||
|
||||
// MovieId - MovieName : pay attention to the order!
|
||||
func readVideosFromResultset(rows *sql.Rows) []types.VideoUnloadedType {
|
||||
result := []types.VideoUnloadedType{}
|
||||
for rows.Next() {
|
||||
var vid types.VideoUnloadedType
|
||||
err := rows.Scan(&vid.MovieId, &vid.MovieName)
|
||||
if err != nil {
|
||||
panic(err.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
result = append(result, vid)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// TagID - TagName : pay attention to the order!
|
||||
func readTagsFromResultset(rows *sql.Rows) []types.Tag {
|
||||
// initialize with empty array!
|
||||
result := []types.Tag{}
|
||||
for rows.Next() {
|
||||
var tag types.Tag
|
||||
err := rows.Scan(&tag.TagId, &tag.TagName)
|
||||
if err != nil {
|
||||
panic(err.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
result = append(result, tag)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ActorId - ActorName - Thumbnail : pay attention to the order!
|
||||
func readActorsFromResultset(rows *sql.Rows) []types.Actor {
|
||||
var result []types.Actor
|
||||
for rows.Next() {
|
||||
var actor types.Actor
|
||||
var thumbnail []byte
|
||||
|
||||
err := rows.Scan(&actor.ActorId, &actor.Name, &thumbnail)
|
||||
if len(thumbnail) != 0 {
|
||||
actor.Thumbnail = string(thumbnail)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
result = append(result, actor)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func jsonify(v interface{}) []byte {
|
||||
// jsonify results
|
||||
str, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
fmt.Println("Error while Jsonifying return object: " + err.Error())
|
||||
}
|
||||
return str
|
||||
}
|
94
apiGo/api/Settings.go
Normal file
94
apiGo/api/Settings.go
Normal file
@ -0,0 +1,94 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
"openmediacenter/apiGo/database"
|
||||
"openmediacenter/apiGo/videoparser"
|
||||
)
|
||||
|
||||
func AddSettingsHandlers() {
|
||||
saveSettingsToDB()
|
||||
getSettingsFromDB()
|
||||
reIndexHandling()
|
||||
}
|
||||
|
||||
func getSettingsFromDB() {
|
||||
AddHandler("loadInitialData", SettingsNode, nil, func() []byte {
|
||||
query := "SELECT DarkMode, password, mediacenter_name, video_path from settings"
|
||||
|
||||
type InitialDataType struct {
|
||||
DarkMode int
|
||||
Pasword int
|
||||
Mediacenter_name string
|
||||
VideoPath string
|
||||
}
|
||||
|
||||
result := InitialDataType{}
|
||||
|
||||
err := database.QueryRow(query).Scan(&result.DarkMode, &result.Pasword, &result.Mediacenter_name, &result.VideoPath)
|
||||
if err != nil {
|
||||
fmt.Println("error while parsing db data: " + err.Error())
|
||||
}
|
||||
|
||||
type InitialDataTypeResponse struct {
|
||||
DarkMode bool
|
||||
Pasword bool
|
||||
Mediacenter_name string
|
||||
VideoPath string
|
||||
}
|
||||
|
||||
res := InitialDataTypeResponse{
|
||||
DarkMode: result.DarkMode != 0,
|
||||
Pasword: result.Pasword != -1,
|
||||
Mediacenter_name: result.Mediacenter_name,
|
||||
VideoPath: result.VideoPath,
|
||||
}
|
||||
|
||||
str, _ := json.Marshal(res)
|
||||
return str
|
||||
})
|
||||
|
||||
AddHandler("loadGeneralSettings", SettingsNode, nil, func() []byte {
|
||||
result := database.GetSettings()
|
||||
return jsonify(result)
|
||||
})
|
||||
}
|
||||
|
||||
func saveSettingsToDB() {
|
||||
var sgs struct {
|
||||
Settings types.SettingsType
|
||||
}
|
||||
AddHandler("saveGeneralSettings", SettingsNode, &sgs, func() []byte {
|
||||
query := `
|
||||
UPDATE settings SET
|
||||
video_path=?,
|
||||
episode_path=?,
|
||||
password=?,
|
||||
mediacenter_name=?,
|
||||
TMDB_grabbing=?,
|
||||
DarkMode=?
|
||||
WHERE 1`
|
||||
return database.SuccessQuery(query,
|
||||
sgs.Settings.VideoPath, sgs.Settings.EpisodePath, sgs.Settings.Password,
|
||||
sgs.Settings.MediacenterName, sgs.Settings.TMDBGrabbing, sgs.Settings.DarkMode)
|
||||
})
|
||||
}
|
||||
|
||||
// methods for handling reindexing and cleanup of db gravity
|
||||
func reIndexHandling() {
|
||||
AddHandler("startReindex", SettingsNode, nil, func() []byte {
|
||||
videoparser.StartReindex()
|
||||
return database.ManualSuccessResponse(nil)
|
||||
})
|
||||
|
||||
AddHandler("cleanupGravity", SettingsNode, nil, func() []byte {
|
||||
videoparser.StartCleanup()
|
||||
return nil
|
||||
})
|
||||
|
||||
AddHandler("getStatusMessage", SettingsNode, nil, func() []byte {
|
||||
return jsonify(videoparser.GetStatusMessage())
|
||||
})
|
||||
}
|
74
apiGo/api/Tags.go
Normal file
74
apiGo/api/Tags.go
Normal file
@ -0,0 +1,74 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/database"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func AddTagHandlers() {
|
||||
getFromDB()
|
||||
addToDB()
|
||||
deleteFromDB()
|
||||
}
|
||||
|
||||
func deleteFromDB() {
|
||||
var dT struct {
|
||||
TagId int
|
||||
Force bool
|
||||
}
|
||||
AddHandler("deleteTag", TagNode, &dT, func() []byte {
|
||||
// delete key constraints first
|
||||
if dT.Force {
|
||||
query := fmt.Sprintf("DELETE FROM video_tags WHERE tag_id=%d", dT.TagId)
|
||||
err := database.Edit(query)
|
||||
|
||||
// respond only if result not successful
|
||||
if err != nil {
|
||||
return database.ManualSuccessResponse(err)
|
||||
}
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("DELETE FROM tags WHERE tag_id=%d", dT.TagId)
|
||||
err := database.Edit(query)
|
||||
|
||||
if err == nil {
|
||||
// return if successful
|
||||
return database.ManualSuccessResponse(err)
|
||||
} else {
|
||||
// check with regex if its the key constraint error
|
||||
r, _ := regexp.Compile("^.*a foreign key constraint fails.*$")
|
||||
if r.MatchString(err.Error()) {
|
||||
return []byte(`{"result":"not empty tag"}`)
|
||||
} else {
|
||||
return database.ManualSuccessResponse(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getFromDB() {
|
||||
AddHandler("getAllTags", TagNode, nil, func() []byte {
|
||||
query := "SELECT tag_id,tag_name from tags"
|
||||
return jsonify(readTagsFromResultset(database.Query(query)))
|
||||
})
|
||||
}
|
||||
|
||||
func addToDB() {
|
||||
var ct struct {
|
||||
TagName string
|
||||
}
|
||||
AddHandler("createTag", TagNode, &ct, func() []byte {
|
||||
query := "INSERT IGNORE INTO tags (tag_name) VALUES (?)"
|
||||
return database.SuccessQuery(query, ct.TagName)
|
||||
})
|
||||
|
||||
var at struct {
|
||||
MovieId int
|
||||
TagId int
|
||||
}
|
||||
AddHandler("addTag", TagNode, &at, func() []byte {
|
||||
query := "INSERT IGNORE INTO video_tags(tag_id, video_id) VALUES (?,?)"
|
||||
return database.SuccessQuery(query, at.TagId, at.MovieId)
|
||||
})
|
||||
}
|
233
apiGo/api/Video.go
Normal file
233
apiGo/api/Video.go
Normal file
@ -0,0 +1,233 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
"openmediacenter/apiGo/database"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func AddVideoHandlers() {
|
||||
getVideoHandlers()
|
||||
loadVideosHandlers()
|
||||
addToVideoHandlers()
|
||||
}
|
||||
|
||||
func getVideoHandlers() {
|
||||
var mrq struct {
|
||||
Tag int
|
||||
}
|
||||
AddHandler("getMovies", VideoNode, &mrq, func() []byte {
|
||||
var query string
|
||||
// 1 is the id of the ALL tag
|
||||
if mrq.Tag != 1 {
|
||||
query = fmt.Sprintf(`SELECT movie_id,movie_name FROM videos
|
||||
INNER JOIN video_tags vt on videos.movie_id = vt.video_id
|
||||
INNER JOIN tags t on vt.tag_id = t.tag_id
|
||||
WHERE t.tag_id = '%d'
|
||||
ORDER BY likes DESC, create_date, movie_name`, mrq.Tag)
|
||||
} else {
|
||||
query = "SELECT movie_id,movie_name FROM videos ORDER BY create_date DESC, movie_name"
|
||||
}
|
||||
|
||||
result := readVideosFromResultset(database.Query(query))
|
||||
// jsonify results
|
||||
str, _ := json.Marshal(result)
|
||||
return str
|
||||
})
|
||||
|
||||
var rtn struct {
|
||||
Movieid int
|
||||
}
|
||||
AddHandler("readThumbnail", VideoNode, &rtn, func() []byte {
|
||||
var pic []byte
|
||||
|
||||
query := fmt.Sprintf("SELECT thumbnail FROM videos WHERE movie_id='%d'", rtn.Movieid)
|
||||
|
||||
err := database.QueryRow(query).Scan(&pic)
|
||||
if err != nil {
|
||||
fmt.Printf("the thumbnail of movie id %d couldn't be found", rtn.Movieid)
|
||||
return nil
|
||||
}
|
||||
|
||||
return pic
|
||||
})
|
||||
|
||||
var grm struct {
|
||||
Number int
|
||||
}
|
||||
AddHandler("getRandomMovies", VideoNode, &grm, func() []byte {
|
||||
var result struct {
|
||||
Tags []types.Tag
|
||||
Videos []types.VideoUnloadedType
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("SELECT movie_id,movie_name FROM videos ORDER BY RAND() LIMIT %d", grm.Number)
|
||||
result.Videos = readVideosFromResultset(database.Query(query))
|
||||
|
||||
var ids string
|
||||
for i := range result.Videos {
|
||||
ids += "video_tags.video_id=" + strconv.Itoa(result.Videos[i].MovieId)
|
||||
|
||||
if i < len(result.Videos)-1 {
|
||||
ids += " OR "
|
||||
}
|
||||
}
|
||||
|
||||
// add the corresponding tags
|
||||
query = fmt.Sprintf(`SELECT t.tag_name,t.tag_id FROM video_tags
|
||||
INNER JOIN tags t on video_tags.tag_id = t.tag_id
|
||||
WHERE %s
|
||||
GROUP BY t.tag_id`, ids)
|
||||
|
||||
rows := database.Query(query)
|
||||
|
||||
for rows.Next() {
|
||||
var tag types.Tag
|
||||
err := rows.Scan(&tag.TagName, &tag.TagId)
|
||||
if err != nil {
|
||||
panic(err.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
// append to final array
|
||||
result.Tags = append(result.Tags, tag)
|
||||
}
|
||||
|
||||
// jsonify results
|
||||
str, _ := json.Marshal(result)
|
||||
return str
|
||||
})
|
||||
|
||||
var gsk struct {
|
||||
KeyWord string
|
||||
}
|
||||
AddHandler("getSearchKeyWord", VideoNode, &gsk, func() []byte {
|
||||
query := fmt.Sprintf(`SELECT movie_id,movie_name FROM videos
|
||||
WHERE movie_name LIKE '%%%s%%'
|
||||
ORDER BY likes DESC, create_date DESC, movie_name`, gsk.KeyWord)
|
||||
|
||||
result := readVideosFromResultset(database.Query(query))
|
||||
// jsonify results
|
||||
str, _ := json.Marshal(result)
|
||||
return str
|
||||
})
|
||||
}
|
||||
|
||||
// function to handle stuff for loading specific videos and startdata
|
||||
func loadVideosHandlers() {
|
||||
var lv struct {
|
||||
MovieId int
|
||||
}
|
||||
AddHandler("loadVideo", VideoNode, &lv, func() []byte {
|
||||
query := fmt.Sprintf(`SELECT movie_name,movie_url,movie_id,thumbnail,poster,likes,quality,length
|
||||
FROM videos WHERE movie_id=%d`, lv.MovieId)
|
||||
|
||||
var res types.FullVideoType
|
||||
var poster []byte
|
||||
var thumbnail []byte
|
||||
|
||||
err := database.QueryRow(query).Scan(&res.MovieName, &res.MovieUrl, &res.MovieId, &thumbnail, &poster, &res.Likes, &res.Quality, &res.Length)
|
||||
if err != nil {
|
||||
fmt.Printf("error getting full data list of videoid - %d", lv.MovieId)
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
// we ned to urlencode the movieurl
|
||||
res.MovieUrl = url.PathEscape(res.MovieUrl)
|
||||
|
||||
// we need to stringify the pic byte array
|
||||
res.Poster = string(poster)
|
||||
|
||||
// if poster in db is empty we use the thumbnail
|
||||
if res.Poster == "" {
|
||||
res.Poster = string(thumbnail)
|
||||
}
|
||||
|
||||
// now add the tags of this video
|
||||
query = fmt.Sprintf(`SELECT t.tag_id, t.tag_name FROM video_tags
|
||||
INNER JOIN tags t on video_tags.tag_id = t.tag_id
|
||||
WHERE video_tags.video_id=%d
|
||||
GROUP BY t.tag_id`, lv.MovieId)
|
||||
|
||||
res.Tags = readTagsFromResultset(database.Query(query))
|
||||
|
||||
query = fmt.Sprintf(`SELECT * FROM tags
|
||||
WHERE tag_id NOT IN (
|
||||
SELECT video_tags.tag_id FROM video_tags
|
||||
WHERE video_id=%d)
|
||||
ORDER BY rand()
|
||||
LIMIT 5`, lv.MovieId)
|
||||
|
||||
res.SuggestedTag = readTagsFromResultset(database.Query(query))
|
||||
|
||||
// query the actors corresponding to video
|
||||
query = fmt.Sprintf(`SELECT a.actor_id, name, thumbnail FROM actors_videos
|
||||
JOIN actors a on actors_videos.actor_id = a.actor_id
|
||||
WHERE actors_videos.video_id=%d`, lv.MovieId)
|
||||
|
||||
res.Actors = readActorsFromResultset(database.Query(query))
|
||||
|
||||
// jsonify results
|
||||
str, _ := json.Marshal(res)
|
||||
return str
|
||||
})
|
||||
|
||||
AddHandler("getStartData", VideoNode, nil, func() []byte {
|
||||
var result types.StartData
|
||||
// query settings and infotile values
|
||||
query := `
|
||||
SELECT (
|
||||
SELECT COUNT(*) FROM videos
|
||||
) AS videonr,
|
||||
(
|
||||
SELECT COUNT(*) FROM videos
|
||||
INNER JOIN video_tags vt on videos.movie_id = vt.video_id
|
||||
INNER JOIN tags t on vt.tag_id = t.tag_id
|
||||
) AS tagged,
|
||||
(
|
||||
SELECT COUNT(*) FROM video_tags as vt
|
||||
INNER JOIN tags t on vt.tag_id = t.tag_id
|
||||
WHERE t.tag_name='hd'
|
||||
) AS hd,
|
||||
(
|
||||
SELECT COUNT(*) FROM video_tags as vt
|
||||
INNER JOIN tags t on vt.tag_id = t.tag_id
|
||||
WHERE t.tag_name='fullhd'
|
||||
) AS fullhd,
|
||||
(
|
||||
SELECT COUNT(*) FROM video_tags as vt
|
||||
INNER JOIN tags t on vt.tag_id = t.tag_id
|
||||
WHERE t.tag_name='lowquality'
|
||||
) AS lq,
|
||||
(
|
||||
SELECT COUNT(*) as nr FROM tags
|
||||
) as tags
|
||||
LIMIT 1`
|
||||
|
||||
_ = database.QueryRow(query).Scan(&result.VideoNr, &result.Tagged, &result.HDNr, &result.FullHdNr, &result.SDNr, &result.DifferentTags)
|
||||
|
||||
// jsonify results
|
||||
str, _ := json.Marshal(result)
|
||||
return str
|
||||
})
|
||||
}
|
||||
|
||||
func addToVideoHandlers() {
|
||||
var al struct {
|
||||
MovieId int
|
||||
}
|
||||
AddHandler("addLike", VideoNode, &al, func() []byte {
|
||||
query := fmt.Sprintf("update videos set likes = likes + 1 where movie_id = %d", al.MovieId)
|
||||
return database.SuccessQuery(query)
|
||||
})
|
||||
|
||||
var dv struct {
|
||||
MovieId int
|
||||
}
|
||||
AddHandler("deleteVideo", VideoNode, &dv, func() []byte {
|
||||
query := fmt.Sprintf("DELETE FROM videos WHERE movie_id=%d", dv.MovieId)
|
||||
return database.SuccessQuery(query)
|
||||
})
|
||||
}
|
56
apiGo/api/types/Types.go
Normal file
56
apiGo/api/types/Types.go
Normal file
@ -0,0 +1,56 @@
|
||||
package types
|
||||
|
||||
type VideoUnloadedType struct {
|
||||
MovieId int
|
||||
MovieName string
|
||||
}
|
||||
|
||||
type FullVideoType struct {
|
||||
MovieName string
|
||||
MovieId int
|
||||
MovieUrl string
|
||||
Poster string
|
||||
Likes int
|
||||
Quality int
|
||||
Length int
|
||||
Tags []Tag
|
||||
SuggestedTag []Tag
|
||||
Actors []Actor
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
TagName string
|
||||
TagId int
|
||||
}
|
||||
|
||||
type Actor struct {
|
||||
ActorId int
|
||||
Name string
|
||||
Thumbnail string
|
||||
}
|
||||
|
||||
type StartData struct {
|
||||
VideoNr int
|
||||
FullHdNr int
|
||||
HDNr int
|
||||
SDNr int
|
||||
DifferentTags int
|
||||
Tagged int
|
||||
}
|
||||
|
||||
type SettingsType struct {
|
||||
VideoPath string
|
||||
EpisodePath string
|
||||
MediacenterName string
|
||||
Password string
|
||||
PasswordEnabled bool
|
||||
TMDBGrabbing bool
|
||||
DarkMode bool
|
||||
|
||||
VideoNr int
|
||||
DBSize float32
|
||||
DifferentTags int
|
||||
TagsAdded int
|
||||
|
||||
PathPrefix string
|
||||
}
|
136
apiGo/database/Database.go
Normal file
136
apiGo/database/Database.go
Normal file
@ -0,0 +1,136 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
)
|
||||
|
||||
var db *sql.DB
|
||||
var DBName string
|
||||
|
||||
// store the command line parameter for Videoprefix
|
||||
var SettingsVideoPrefix = ""
|
||||
|
||||
type DatabaseConfig struct {
|
||||
DBHost string
|
||||
DBPort int
|
||||
DBUser string
|
||||
DBPassword string
|
||||
DBName string
|
||||
}
|
||||
|
||||
func InitDB(dbconf *DatabaseConfig) {
|
||||
DBName = dbconf.DBName
|
||||
|
||||
// Open up our database connection.
|
||||
var err error
|
||||
db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", dbconf.DBUser, dbconf.DBPassword, dbconf.DBHost, dbconf.DBPort, dbconf.DBName))
|
||||
|
||||
// if there is an error opening the connection, handle it
|
||||
if err != nil {
|
||||
fmt.Printf("Error while connecting to database! - %s\n", err.Error())
|
||||
}
|
||||
|
||||
if db != nil {
|
||||
ping := db.Ping()
|
||||
if ping != nil {
|
||||
fmt.Printf("Error while connecting to database! - %s\n", ping.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Query(query string, args ...interface{}) *sql.Rows {
|
||||
// perform a db.Query insert
|
||||
res, err := db.Query(query, args...)
|
||||
|
||||
// if there is an error inserting, handle it
|
||||
if err != nil {
|
||||
fmt.Printf("Error while requesting data! - %s\n", err.Error())
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func QueryRow(SQL string, args ...interface{}) *sql.Row {
|
||||
return db.QueryRow(SQL, args...)
|
||||
}
|
||||
|
||||
// edit something in the DB and give only an error response
|
||||
func Edit(query string, args ...interface{}) error {
|
||||
_, err := db.Exec(query, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// insert/edit a query and return last insert id
|
||||
func Insert(query string, args ...interface{}) (error, int64) {
|
||||
resp, err := db.Exec(query, args...)
|
||||
var id int64 = 0
|
||||
if err == nil {
|
||||
id, err = resp.LastInsertId()
|
||||
}
|
||||
|
||||
return err, id
|
||||
}
|
||||
|
||||
func SuccessQuery(query string, args ...interface{}) []byte {
|
||||
return ManualSuccessResponse(Edit(query, args...))
|
||||
}
|
||||
|
||||
func ManualSuccessResponse(err error) []byte {
|
||||
if err == nil {
|
||||
return []byte(`{"result":"success"}`)
|
||||
} else {
|
||||
return []byte(fmt.Sprintf(`{"result":"%s"}`, err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func Close() {
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func GetSettings() types.SettingsType {
|
||||
var result types.SettingsType
|
||||
|
||||
// query settings and infotile values
|
||||
query := fmt.Sprintf(`
|
||||
SELECT (
|
||||
SELECT COUNT(*)
|
||||
FROM videos
|
||||
) AS videonr,
|
||||
(
|
||||
SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS Size
|
||||
FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = '%s'
|
||||
GROUP BY table_schema
|
||||
) AS dbsize,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM tags
|
||||
) AS difftagnr,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM video_tags
|
||||
) AS tagsadded,
|
||||
video_path, episode_path, password, mediacenter_name, TMDB_grabbing, DarkMode
|
||||
FROM settings
|
||||
LIMIT 1`, DBName)
|
||||
|
||||
var DarkMode int
|
||||
var TMDBGrabbing int
|
||||
|
||||
err := QueryRow(query).Scan(&result.VideoNr, &result.DBSize, &result.DifferentTags, &result.TagsAdded,
|
||||
&result.VideoPath, &result.EpisodePath, &result.Password, &result.MediacenterName, &TMDBGrabbing, &DarkMode)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
result.TMDBGrabbing = TMDBGrabbing != 0
|
||||
result.PasswordEnabled = result.Password != "-1"
|
||||
result.DarkMode = DarkMode != 0
|
||||
result.PathPrefix = SettingsVideoPrefix
|
||||
|
||||
return result
|
||||
}
|
5
apiGo/go.mod
Normal file
5
apiGo/go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module openmediacenter/apiGo
|
||||
|
||||
go 1.16
|
||||
|
||||
require github.com/go-sql-driver/mysql v1.5.0
|
2
apiGo/go.sum
Normal file
2
apiGo/go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
53
apiGo/main.go
Normal file
53
apiGo/main.go
Normal file
@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/api"
|
||||
"openmediacenter/apiGo/database"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("init OpenMediaCenter server")
|
||||
|
||||
db, verbose, pathPrefix := handleCommandLineArguments()
|
||||
// todo some verbosity logger or sth
|
||||
|
||||
fmt.Printf("Use verbose output: %t\n", verbose)
|
||||
fmt.Printf("Videopath prefix: %s\n", *pathPrefix)
|
||||
|
||||
// set pathprefix in database settings object
|
||||
database.SettingsVideoPrefix = *pathPrefix
|
||||
|
||||
database.InitDB(db)
|
||||
defer database.Close()
|
||||
|
||||
api.AddVideoHandlers()
|
||||
api.AddSettingsHandlers()
|
||||
api.AddTagHandlers()
|
||||
api.AddActorsHandlers()
|
||||
|
||||
api.ServerInit(8081)
|
||||
}
|
||||
|
||||
func handleCommandLineArguments() (*database.DatabaseConfig, bool, *string) {
|
||||
dbhostPtr := flag.String("DBHost", "127.0.0.1", "database host name")
|
||||
dbPortPtr := flag.Int("DBPort", 3306, "database port")
|
||||
dbUserPtr := flag.String("DBUser", "mediacenteruser", "database username")
|
||||
dbPassPtr := flag.String("DBPassword", "mediapassword", "database username")
|
||||
dbNamePtr := flag.String("DBName", "mediacenter", "database name")
|
||||
|
||||
verbosePtr := flag.Bool("v", true, "Verbose log output")
|
||||
|
||||
pathPrefix := flag.String("ReindexPrefix", "/var/www/openmediacenter", "Prefix path for videos to reindex")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
return &database.DatabaseConfig{
|
||||
DBHost: *dbhostPtr,
|
||||
DBPort: *dbPortPtr,
|
||||
DBUser: *dbUserPtr,
|
||||
DBPassword: *dbPassPtr,
|
||||
DBName: *dbNamePtr,
|
||||
}, *verbosePtr, pathPrefix
|
||||
}
|
1
apiGo/videoparser/CleanUp.go
Normal file
1
apiGo/videoparser/CleanUp.go
Normal file
@ -0,0 +1 @@
|
||||
package videoparser
|
294
apiGo/videoparser/ReIndex.go
Normal file
294
apiGo/videoparser/ReIndex.go
Normal file
@ -0,0 +1,294 @@
|
||||
package videoparser
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
"openmediacenter/apiGo/database"
|
||||
"openmediacenter/apiGo/videoparser/tmdb"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var mSettings types.SettingsType
|
||||
var mExtDepsAvailable *ExtDependencySupport
|
||||
|
||||
// default Tag ids
|
||||
const (
|
||||
FullHd = 2
|
||||
Hd = 4
|
||||
LowQuality = 3
|
||||
)
|
||||
|
||||
type ExtDependencySupport struct {
|
||||
FFMpeg bool
|
||||
MediaInfo bool
|
||||
}
|
||||
|
||||
type VideoAttributes struct {
|
||||
Duration float32
|
||||
FileSize uint
|
||||
Width uint
|
||||
}
|
||||
|
||||
func ReIndexVideos(path []string, sett types.SettingsType) {
|
||||
mSettings = sett
|
||||
// check if the extern dependencies are available
|
||||
mExtDepsAvailable = checkExtDependencySupport()
|
||||
fmt.Printf("FFMPEG support: %t\n", mExtDepsAvailable.FFMpeg)
|
||||
fmt.Printf("MediaInfo support: %t\n", mExtDepsAvailable.MediaInfo)
|
||||
|
||||
for _, s := range path {
|
||||
processVideo(s)
|
||||
}
|
||||
|
||||
AppendMessageBuffer("reindex finished successfully!")
|
||||
|
||||
contentAvailable = false
|
||||
fmt.Println("Reindexing finished!")
|
||||
}
|
||||
|
||||
func processVideo(fileNameOrig string) {
|
||||
fmt.Printf("Processing %s video-", fileNameOrig)
|
||||
|
||||
// match the file extension
|
||||
r, _ := regexp.Compile(`\.[a-zA-Z0-9]+$`)
|
||||
fileName := r.ReplaceAllString(fileNameOrig, "")
|
||||
|
||||
year, fileName := matchYear(fileName)
|
||||
|
||||
// now we should look if this video already exists in db
|
||||
query := "SELECT * FROM videos WHERE movie_name = ?"
|
||||
err := database.QueryRow(query, fileName).Scan()
|
||||
if err == sql.ErrNoRows {
|
||||
fmt.Printf("The Video %s does't exist! Adding it to database.\n", fileName)
|
||||
|
||||
addVideo(fileName, fileNameOrig, year)
|
||||
} else {
|
||||
fmt.Println(" :existing!")
|
||||
}
|
||||
}
|
||||
|
||||
// add a video to the database
|
||||
func addVideo(videoName string, fileName string, year int) {
|
||||
var ppic *string
|
||||
var poster *string
|
||||
var tmdbData *tmdb.VideoTMDB
|
||||
var err error
|
||||
|
||||
// initialize defaults
|
||||
vidAtr := &VideoAttributes{
|
||||
Duration: 0,
|
||||
FileSize: 0,
|
||||
Width: 0,
|
||||
}
|
||||
|
||||
if mExtDepsAvailable.FFMpeg {
|
||||
ppic, err = parseFFmpegPic(fileName)
|
||||
if err != nil {
|
||||
fmt.Printf("FFmpeg error occured: %s\n", err.Error())
|
||||
} else {
|
||||
fmt.Println("successfully extracted thumbnail!!")
|
||||
}
|
||||
}
|
||||
|
||||
if mExtDepsAvailable.MediaInfo {
|
||||
atr := getVideoAttributes(fileName)
|
||||
if atr != nil {
|
||||
vidAtr = atr
|
||||
}
|
||||
}
|
||||
|
||||
// if TMDB grabbing is enabled serach in api for video...
|
||||
if mSettings.TMDBGrabbing {
|
||||
tmdbData = tmdb.SearchVideo(videoName, year)
|
||||
if tmdbData != nil {
|
||||
// reassign parsed pic as poster
|
||||
poster = ppic
|
||||
// and tmdb pic as thumbnail
|
||||
ppic = &tmdbData.Thumbnail
|
||||
}
|
||||
}
|
||||
|
||||
query := `INSERT INTO videos(movie_name,movie_url,poster,thumbnail,quality,length) VALUES (?,?,?,?,?,?)`
|
||||
err, insertId := database.Insert(query, videoName, fileName, poster, ppic, vidAtr.Width, vidAtr.Duration)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to insert video into db: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// add default tags
|
||||
if vidAtr.Width != 0 {
|
||||
insertSizeTag(vidAtr.Width, uint(insertId))
|
||||
}
|
||||
|
||||
// add tmdb tags
|
||||
if mSettings.TMDBGrabbing && tmdbData != nil {
|
||||
insertTMDBTags(tmdbData.GenreIds, insertId)
|
||||
}
|
||||
|
||||
AppendMessageBuffer(fmt.Sprintf("%s - added!", videoName))
|
||||
}
|
||||
|
||||
func matchYear(fileName string) (int, string) {
|
||||
r, _ := regexp.Compile(`\([0-9]{4}?\)`)
|
||||
years := r.FindAllString(fileName, -1)
|
||||
if len(years) == 0 {
|
||||
return -1, fileName
|
||||
}
|
||||
|
||||
year, err := strconv.Atoi(years[len(years)-1])
|
||||
|
||||
if err != nil {
|
||||
return -1, fileName
|
||||
}
|
||||
|
||||
// cut out year from filename
|
||||
return year, r.ReplaceAllString(fileName, "")
|
||||
}
|
||||
|
||||
// parse the thumbail picture from video file
|
||||
func parseFFmpegPic(fileName string) (*string, error) {
|
||||
app := "ffmpeg"
|
||||
|
||||
cmd := exec.Command(app,
|
||||
"-hide_banner",
|
||||
"-loglevel", "panic",
|
||||
"-ss", "00:04:00",
|
||||
"-i", mSettings.VideoPath+fileName,
|
||||
"-vframes", "1",
|
||||
"-q:v", "2",
|
||||
"-f", "singlejpeg",
|
||||
"pipe:1")
|
||||
|
||||
stdout, err := cmd.Output()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
fmt.Println(string(err.(*exec.ExitError).Stderr))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backpic64 := "data:image/jpeg;base64," + base64.StdEncoding.EncodeToString(stdout)
|
||||
|
||||
return &backpic64, nil
|
||||
}
|
||||
|
||||
func getVideoAttributes(fileName string) *VideoAttributes {
|
||||
app := "mediainfo"
|
||||
|
||||
arg0 := mSettings.VideoPath + fileName
|
||||
arg1 := "--Output=JSON"
|
||||
|
||||
cmd := exec.Command(app, arg1, "-f", arg0)
|
||||
stdout, err := cmd.Output()
|
||||
|
||||
var t struct {
|
||||
Media struct {
|
||||
Track []struct {
|
||||
Duration string
|
||||
FileSize string
|
||||
Width string
|
||||
}
|
||||
}
|
||||
}
|
||||
err = json.Unmarshal(stdout, &t)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
duration, err := strconv.ParseFloat(t.Media.Track[0].Duration, 32)
|
||||
filesize, err := strconv.Atoi(t.Media.Track[0].FileSize)
|
||||
width, err := strconv.Atoi(t.Media.Track[1].Width)
|
||||
|
||||
ret := VideoAttributes{
|
||||
Duration: float32(duration),
|
||||
FileSize: uint(filesize),
|
||||
Width: uint(width),
|
||||
}
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
func AppendMessageBuffer(message string) {
|
||||
messageBuffer = append(messageBuffer, message)
|
||||
}
|
||||
|
||||
// ext dependency support check
|
||||
func checkExtDependencySupport() *ExtDependencySupport {
|
||||
var extDepsAvailable ExtDependencySupport
|
||||
|
||||
extDepsAvailable.FFMpeg = commandExists("ffmpeg")
|
||||
extDepsAvailable.MediaInfo = commandExists("mediainfo")
|
||||
|
||||
return &extDepsAvailable
|
||||
}
|
||||
|
||||
// check if a specific system command is available
|
||||
func commandExists(cmd string) bool {
|
||||
_, err := exec.LookPath(cmd)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// insert the default size tags to corresponding video
|
||||
func insertSizeTag(width uint, videoId uint) {
|
||||
var tagType uint
|
||||
|
||||
if width >= 1080 {
|
||||
tagType = FullHd
|
||||
} else if width >= 720 {
|
||||
tagType = Hd
|
||||
} else {
|
||||
tagType = LowQuality
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("INSERT INTO video_tags(video_id,tag_id) VALUES (%d,%d)", videoId, tagType)
|
||||
err := database.Edit(query)
|
||||
if err != nil {
|
||||
fmt.Printf("Eror occured while adding default Tag: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// insert id array of tmdb geners to database
|
||||
func insertTMDBTags(ids []int, videoId int64) {
|
||||
genres := tmdb.GetGenres()
|
||||
|
||||
for _, id := range ids {
|
||||
var idGenre *tmdb.TMDBGenre
|
||||
for _, genre := range *genres {
|
||||
if genre.Id == id {
|
||||
idGenre = &genre
|
||||
break
|
||||
}
|
||||
}
|
||||
// skip tag if name couldn't be found
|
||||
if idGenre == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// now we check if the tag we want to add already exists
|
||||
tagId := createTagToDB(idGenre.Name)
|
||||
|
||||
// now we add the tag
|
||||
query := fmt.Sprintf("INSERT INTO video_tags(video_id,tag_id) VALUES (%d,%d)", videoId, tagId)
|
||||
_ = database.Edit(query)
|
||||
}
|
||||
}
|
||||
|
||||
// returns id of tag or creates it if not existing
|
||||
func createTagToDB(tagName string) int64 {
|
||||
query := fmt.Sprintf("SELECT tag_id FROM tags WHERE tag_name = %s", tagName)
|
||||
var id int64
|
||||
err := database.QueryRow(query).Scan(&id)
|
||||
if err == sql.ErrNoRows {
|
||||
// tag doesn't exist -- add it
|
||||
query = fmt.Sprintf("INSERT INTO tags (tag_name) VALUES (%s)", tagName)
|
||||
err, id = database.Insert(query)
|
||||
}
|
||||
return id
|
||||
}
|
70
apiGo/videoparser/VideoParser.go
Normal file
70
apiGo/videoparser/VideoParser.go
Normal file
@ -0,0 +1,70 @@
|
||||
package videoparser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"openmediacenter/apiGo/database"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var messageBuffer []string
|
||||
var contentAvailable = false
|
||||
|
||||
type StatusMessage struct {
|
||||
Messages []string
|
||||
ContentAvailable bool
|
||||
}
|
||||
|
||||
func StartReindex() bool {
|
||||
messageBuffer = []string{}
|
||||
contentAvailable = true
|
||||
|
||||
fmt.Println("starting reindex..")
|
||||
|
||||
mSettings := database.GetSettings()
|
||||
// add the path prefix to videopath
|
||||
mSettings.VideoPath = mSettings.PathPrefix + mSettings.VideoPath
|
||||
|
||||
// check if path even exists
|
||||
if _, err := os.Stat(mSettings.VideoPath); os.IsNotExist(err) {
|
||||
fmt.Println("Reindex path doesn't exist!")
|
||||
return false
|
||||
}
|
||||
|
||||
var files []string
|
||||
err := filepath.Walk(mSettings.VideoPath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() && strings.HasSuffix(info.Name(), ".mp4") {
|
||||
files = append(files, info.Name())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
// start reindex process
|
||||
AppendMessageBuffer("Starting Reindexing!")
|
||||
go ReIndexVideos(files, mSettings)
|
||||
return true
|
||||
}
|
||||
|
||||
func GetStatusMessage() *StatusMessage {
|
||||
msg := StatusMessage{
|
||||
Messages: messageBuffer,
|
||||
ContentAvailable: contentAvailable,
|
||||
}
|
||||
|
||||
messageBuffer = []string{}
|
||||
|
||||
return &msg
|
||||
}
|
||||
|
||||
func StartCleanup() {
|
||||
// todo start cleanup
|
||||
}
|
144
apiGo/videoparser/tmdb/TMDBApi.go
Normal file
144
apiGo/videoparser/tmdb/TMDBApi.go
Normal file
@ -0,0 +1,144 @@
|
||||
package tmdb
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const apiKey = "9fd90530b11447f5646f8e6fb4733fb4"
|
||||
const baseUrl = "https://api.themoviedb.org/3/"
|
||||
const pictureBase = "https://image.tmdb.org/t/p/w500"
|
||||
|
||||
type VideoTMDB struct {
|
||||
Thumbnail string
|
||||
Overview string
|
||||
Title string
|
||||
GenreIds []int
|
||||
}
|
||||
|
||||
type tmdbVidResult struct {
|
||||
Poster_path string
|
||||
Adult bool
|
||||
Overview string
|
||||
Release_date string
|
||||
Genre_ids []int
|
||||
Id int
|
||||
Original_title string
|
||||
Original_language string
|
||||
Title string
|
||||
Backdrop_path string
|
||||
Popularity int
|
||||
Vote_count int
|
||||
Video bool
|
||||
Vote_average int
|
||||
}
|
||||
|
||||
type TMDBGenre struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
|
||||
func SearchVideo(MovieName string, year int) *VideoTMDB {
|
||||
url := fmt.Sprintf("%ssearch/movie?api_key=%s&query=%s", baseUrl, apiKey, MovieName)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
var t struct {
|
||||
Results []tmdbVidResult
|
||||
}
|
||||
err = json.Unmarshal(body, &t)
|
||||
|
||||
fmt.Println(len(t.Results))
|
||||
|
||||
var tmdbVid tmdbVidResult
|
||||
if year != -1 {
|
||||
for _, result := range t.Results {
|
||||
r, _ := regexp.Compile(fmt.Sprintf(`^%d-[0-9]{2}?-[0-9]{2}?$`, year))
|
||||
if r.MatchString(result.Release_date) {
|
||||
tmdbVid = result
|
||||
// continue parsing
|
||||
goto cont
|
||||
}
|
||||
}
|
||||
// if there is no match use first one
|
||||
tmdbVid = t.Results[0]
|
||||
} else {
|
||||
tmdbVid = t.Results[0]
|
||||
}
|
||||
|
||||
// continue label
|
||||
cont:
|
||||
|
||||
thumbnail := fetchPoster(tmdbVid)
|
||||
|
||||
result := VideoTMDB{
|
||||
Thumbnail: *thumbnail,
|
||||
Overview: tmdbVid.Overview,
|
||||
Title: tmdbVid.Title,
|
||||
GenreIds: tmdbVid.Genre_ids,
|
||||
}
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func fetchPoster(vid tmdbVidResult) *string {
|
||||
url := fmt.Sprintf("%s%s", pictureBase, vid.Poster_path)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
backpic64 := "data:image/jpeg;base64," + base64.StdEncoding.EncodeToString(body)
|
||||
return &backpic64
|
||||
}
|
||||
|
||||
var tmdbGenres *[]TMDBGenre
|
||||
|
||||
func fetchGenres() *[]TMDBGenre {
|
||||
url := fmt.Sprintf("%sgenre/movie/list?api_key=%s", baseUrl, apiKey)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
var t []TMDBGenre
|
||||
err = json.Unmarshal(body, &t)
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
func GetGenres() *[]TMDBGenre {
|
||||
// if generes are nil fetch them once
|
||||
if tmdbGenres == nil {
|
||||
tmdbGenres = fetchGenres()
|
||||
}
|
||||
return tmdbGenres
|
||||
}
|
Reference in New Issue
Block a user