Merge branch 'APIDoc_handling_mechanics' into 'master'
Api mechanics See merge request lukas/openmediacenter!46
This commit is contained in:
		| @@ -12,32 +12,83 @@ func AddActorsHandlers() { | ||||
| } | ||||
|  | ||||
| func getActorsFromDB() { | ||||
| 	AddHandler("getAllActors", ActorNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/actor [getAllActors] | ||||
| 	 * @apiDescription Get all available Actors | ||||
| 	 * @apiName getAllActors | ||||
| 	 * @apiGroup Actor | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} . Array of Actors available | ||||
| 	 * @apiSuccess {uint32} .ActorId Actor Id | ||||
| 	 * @apiSuccess {string} .Name Actor Name | ||||
| 	 * @apiSuccess {string} .Thumbnail Portrait Thumbnail | ||||
| 	 */ | ||||
| 	AddHandler("getAllActors", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		query := "SELECT actor_id, name, thumbnail FROM actors" | ||||
| 		return jsonify(readActorsFromResultset(database.Query(query))) | ||||
| 	}) | ||||
|  | ||||
| 	var gaov struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/actor [getActorsOfVideo] | ||||
| 	 * @apiDescription Get all actors playing in one video | ||||
| 	 * @apiName getActorsOfVideo | ||||
| 	 * @apiGroup Actor | ||||
| 	 * | ||||
| 	 * @apiParam {int} MovieId ID of video | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} . Array of Actors available | ||||
| 	 * @apiSuccess {uint32} .ActorId Actor Id | ||||
| 	 * @apiSuccess {string} .Name Actor Name | ||||
| 	 * @apiSuccess {string} .Thumbnail Portrait Thumbnail | ||||
| 	 */ | ||||
| 	AddHandler("getActorsOfVideo", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			MovieId int | ||||
| 		} | ||||
| 	AddHandler("getActorsOfVideo", ActorNode, &gaov, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 									WHERE actors_videos.video_id=%d`, args.MovieId) | ||||
|  | ||||
| 		return jsonify(readActorsFromResultset(database.Query(query))) | ||||
| 	}) | ||||
|  | ||||
| 	var gai struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/actor [getActorInfo] | ||||
| 	 * @apiDescription Get all infos for an actor | ||||
| 	 * @apiName getActorInfo | ||||
| 	 * @apiGroup Actor | ||||
| 	 * | ||||
| 	 * @apiParam {int} ActorId ID of Actor | ||||
| 	 * | ||||
| 	 * @apiSuccess {VideoUnloadedType[]} Videos Array of Videos this actor plays in | ||||
| 	 * @apiSuccess {uint32} Videos.MovieId Video Id | ||||
| 	 * @apiSuccess {string} Videos.MovieName Video Name | ||||
| 	 * | ||||
| 	 * @apiSuccess {Info} Info Infos about the actor | ||||
| 	 * @apiSuccess {uint32} Info.ActorId Actor Id | ||||
| 	 * @apiSuccess {string} Info.Name Actor Name | ||||
| 	 * @apiSuccess {string} Info.Thumbnail Actor Thumbnail | ||||
| 	 */ | ||||
| 	AddHandler("getActorInfo", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			ActorId int | ||||
| 		} | ||||
| 	AddHandler("getActorInfo", ActorNode, &gai, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 										WHERE actors_videos.actor_id=%d`, args.ActorId) | ||||
| 		videos := readVideosFromResultset(database.Query(query)) | ||||
|  | ||||
| 		query = fmt.Sprintf("SELECT actor_id, name, thumbnail FROM actors WHERE actor_id=%d", gai.ActorId) | ||||
| 		query = fmt.Sprintf("SELECT actor_id, name, thumbnail FROM actors WHERE actor_id=%d", args.ActorId) | ||||
| 		actor := readActorsFromResultset(database.Query(query))[0] | ||||
|  | ||||
| 		var result = struct { | ||||
| @@ -53,20 +104,51 @@ func getActorsFromDB() { | ||||
| } | ||||
|  | ||||
| func saveActorsToDB() { | ||||
| 	var ca struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [createActor] | ||||
| 	 * @apiDescription Create a new Actor | ||||
| 	 * @apiName createActor | ||||
| 	 * @apiGroup Actor | ||||
| 	 * | ||||
| 	 * @apiParam {string} ActorName Name of new Actor | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("createActor", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			ActorName string | ||||
| 		} | ||||
| 	AddHandler("createActor", ActorNode, &ca, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := "INSERT IGNORE INTO actors (name) VALUES (?)" | ||||
| 		return database.SuccessQuery(query, ca.ActorName) | ||||
| 		return database.SuccessQuery(query, args.ActorName) | ||||
| 	}) | ||||
|  | ||||
| 	var aatv struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [addActorToVideo] | ||||
| 	 * @apiDescription Add Actor to Video | ||||
| 	 * @apiName addActorToVideo | ||||
| 	 * @apiGroup Actor | ||||
| 	 * | ||||
| 	 * @apiParam {int} ActorId Id of Actor | ||||
| 	 * @apiParam {int} MovieId Id of Movie to add to | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("addActorToVideo", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		var args 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) | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := fmt.Sprintf("INSERT IGNORE INTO actors_videos (actor_id, video_id) VALUES (%d,%d)", args.ActorId, args.MovieId) | ||||
| 		return database.SuccessQuery(query) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"gopkg.in/oauth2.v3" | ||||
| 	"net/http" | ||||
| 	"openmediacenter/apiGo/api/oauth" | ||||
| ) | ||||
| @@ -18,22 +19,27 @@ const ( | ||||
| 	TVShowNode   = iota | ||||
| ) | ||||
|  | ||||
| type HandlerInfo struct { | ||||
| 	ID    string | ||||
| 	Token string | ||||
| 	Data  map[string]interface{} | ||||
| } | ||||
|  | ||||
| type actionStruct struct { | ||||
| 	Action string | ||||
| } | ||||
|  | ||||
| type Handler struct { | ||||
| 	action  string | ||||
| 	handler   func() []byte | ||||
| 	arguments interface{} | ||||
| 	handler func(info *HandlerInfo) []byte | ||||
| 	apiNode int | ||||
| } | ||||
|  | ||||
| var handlers []Handler | ||||
| var handlers = make(map[string]Handler) | ||||
|  | ||||
| func AddHandler(action string, apiNode int, n interface{}, h func() []byte) { | ||||
| func AddHandler(action string, apiNode int, h func(info *HandlerInfo) []byte) { | ||||
| 	// append new handler to the handlers | ||||
| 	handlers = append(handlers, Handler{action, h, n, apiNode}) | ||||
| 	handlers[fmt.Sprintf("%s/%d", action, apiNode)] = Handler{action, h, apiNode} | ||||
| } | ||||
|  | ||||
| func ServerInit() { | ||||
| @@ -47,27 +53,39 @@ func ServerInit() { | ||||
| 	oauth.InitOAuth() | ||||
| } | ||||
|  | ||||
| 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() | ||||
| 		} | ||||
| 	} | ||||
| func handleAPICall(action string, requestBody string, apiNode int, info *HandlerInfo) []byte { | ||||
| 	handler, ok := handlers[fmt.Sprintf("%s/%d", action, apiNode)] | ||||
| 	if !ok { | ||||
| 		// handler doesn't exist! | ||||
| 		fmt.Printf("no handler found for Action: %d/%s\n", apiNode, action) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| func handlefunc(rw http.ResponseWriter, req *http.Request, node int) { | ||||
| 	// check if info even exists | ||||
| 	if info == nil { | ||||
| 		info = &HandlerInfo{} | ||||
| 	} | ||||
|  | ||||
| 	// parse the arguments | ||||
| 	var args map[string]interface{} | ||||
| 	err := json.Unmarshal([]byte(requestBody), &args) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("failed to decode arguments of action %s :: %s\n", action, requestBody) | ||||
| 	} else { | ||||
| 		// check if map has an action | ||||
| 		if _, ok := args["action"]; ok { | ||||
| 			delete(args, "action") | ||||
| 		} | ||||
|  | ||||
| 		info.Data = args | ||||
| 	} | ||||
|  | ||||
| 	// call the handler | ||||
| 	return handler.handler(info) | ||||
| } | ||||
|  | ||||
| func handlefunc(rw http.ResponseWriter, req *http.Request, node int, tokenInfo *oauth2.TokenInfo) { | ||||
| 	// only allow post requests | ||||
| 	if req.Method != "POST" { | ||||
| 		return | ||||
| @@ -83,5 +101,13 @@ func handlefunc(rw http.ResponseWriter, req *http.Request, node int) { | ||||
| 		fmt.Println("failed to read action from request! :: " + body) | ||||
| 	} | ||||
|  | ||||
| 	rw.Write(handleAPICall(t.Action, body, node)) | ||||
| 	// load userid from received token object | ||||
| 	id := (*tokenInfo).GetClientID() | ||||
|  | ||||
| 	userinfo := &HandlerInfo{ | ||||
| 		ID:    id, | ||||
| 		Token: (*tokenInfo).GetCode(), | ||||
| 	} | ||||
|  | ||||
| 	rw.Write(handleAPICall(t.Action, body, node, userinfo)) | ||||
| } | ||||
|   | ||||
| @@ -5,13 +5,13 @@ import ( | ||||
| ) | ||||
|  | ||||
| func cleanUp() { | ||||
| 	handlers = nil | ||||
| 	handlers = make(map[string]Handler) | ||||
| } | ||||
|  | ||||
| func TestAddHandler(t *testing.T) { | ||||
| 	cleanUp() | ||||
|  | ||||
| 	AddHandler("test", ActorNode, nil, func() []byte { | ||||
| 	AddHandler("test", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		return nil | ||||
| 	}) | ||||
| 	if len(handlers) != 1 { | ||||
| @@ -23,13 +23,13 @@ func TestCallOfHandler(t *testing.T) { | ||||
| 	cleanUp() | ||||
|  | ||||
| 	i := 0 | ||||
| 	AddHandler("test", ActorNode, nil, func() []byte { | ||||
| 	AddHandler("test", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		i++ | ||||
| 		return nil | ||||
| 	}) | ||||
|  | ||||
| 	// simulate the call of the api | ||||
| 	handleAPICall("test", "", ActorNode) | ||||
| 	handleAPICall("test", "", ActorNode, nil) | ||||
|  | ||||
| 	if i != 1 { | ||||
| 		t.Errorf("Unexpected number of Lambda calls : %d/1", i) | ||||
| @@ -39,26 +39,32 @@ func TestCallOfHandler(t *testing.T) { | ||||
| func TestDecodingOfArguments(t *testing.T) { | ||||
| 	cleanUp() | ||||
|  | ||||
| 	var myvar struct { | ||||
| 	AddHandler("test", ActorNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			Test    string | ||||
| 			TestInt int | ||||
| 		} | ||||
| 	AddHandler("test", ActorNode, &myvar, func() []byte { | ||||
| 		err := FillStruct(&args, info.Data) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("Error parsing args: %s", err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		if args.TestInt != 42 || args.Test != "myString" { | ||||
| 			t.Errorf("Wrong parsing of argument parameters : %d/42 - %s/myString", args.TestInt, args.Test) | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 	} | ||||
| 	handleAPICall("test", `{"Test":"myString","TestInt":42}`, ActorNode, nil) | ||||
| } | ||||
|  | ||||
| func TestNoHandlerCovers(t *testing.T) { | ||||
| 	cleanUp() | ||||
|  | ||||
| 	ret := handleAPICall("test", "", ActorNode) | ||||
| 	ret := handleAPICall("test", "", ActorNode, nil) | ||||
|  | ||||
| 	if ret != nil { | ||||
| 		t.Error("Expect nil return within unhandled api action") | ||||
|   | ||||
| @@ -3,8 +3,10 @@ package api | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"openmediacenter/apiGo/api/types" | ||||
| 	"reflect" | ||||
| ) | ||||
|  | ||||
| // MovieId - MovieName : pay attention to the order! | ||||
| @@ -85,3 +87,45 @@ func jsonify(v interface{}) []byte { | ||||
| 	} | ||||
| 	return str | ||||
| } | ||||
|  | ||||
| // setField set a specific field of an object with an object provided | ||||
| func setField(obj interface{}, name string, value interface{}) error { | ||||
| 	structValue := reflect.ValueOf(obj).Elem() | ||||
| 	structFieldValue := structValue.FieldByName(name) | ||||
|  | ||||
| 	if !structFieldValue.IsValid() { | ||||
| 		return fmt.Errorf("no such field: %s in obj", name) | ||||
| 	} | ||||
|  | ||||
| 	if !structFieldValue.CanSet() { | ||||
| 		return fmt.Errorf("cannot set %s field value", name) | ||||
| 	} | ||||
|  | ||||
| 	structFieldType := structFieldValue.Type() | ||||
| 	val := reflect.ValueOf(value) | ||||
|  | ||||
| 	if structFieldType != val.Type() { | ||||
| 		if val.Type().ConvertibleTo(structFieldType) { | ||||
| 			// if type is convertible - convert and set | ||||
| 			structFieldValue.Set(val.Convert(structFieldType)) | ||||
| 		} else { | ||||
| 			return errors.New("provided value type didn't match obj field type and isn't convertible") | ||||
| 		} | ||||
| 	} else { | ||||
| 		// set value if type is the same | ||||
| 		structFieldValue.Set(val) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // FillStruct fill a custom struct with objects of a map | ||||
| func FillStruct(i interface{}, m map[string]interface{}) error { | ||||
| 	for k, v := range m { | ||||
| 		err := setField(i, k, v) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package api | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"openmediacenter/apiGo/api/types" | ||||
| 	"openmediacenter/apiGo/database" | ||||
| 	"openmediacenter/apiGo/database/settings" | ||||
| @@ -17,11 +18,43 @@ func AddSettingsHandlers() { | ||||
| } | ||||
|  | ||||
| func getSettingsFromDB() { | ||||
| 	AddHandler("loadGeneralSettings", SettingsNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/settings [loadGeneralSettings] | ||||
| 	 * @apiDescription Get the settings object | ||||
| 	 * @apiName loadGeneralSettings | ||||
| 	 * @apiGroup Settings | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object} Settings Settings object | ||||
| 	 * @apiSuccess {string} Settings.VideoPath webserver path to the videos | ||||
| 	 * @apiSuccess {string} Settings.EpisodePath webserver path to the tvshows | ||||
| 	 * @apiSuccess {string} Settings.MediacenterName overall name of the mediacenter | ||||
| 	 * @apiSuccess {string} Settings.Password new server password (-1 if no password set) | ||||
| 	 * @apiSuccess {bool} Settings.TMDBGrabbing TMDB grabbing support to grab tag info and thumbnails | ||||
| 	 * @apiSuccess {bool} Settings.DarkMode Darkmode enabled? | ||||
| 	 * @apiSuccess {uint32} Settings.VideoNr total number of videos | ||||
| 	 * @apiSuccess {float32} Settings.DBSize total size of database | ||||
| 	 * @apiSuccess {uint32} Settings.DifferentTags number of different tags available | ||||
| 	 * @apiSuccess {uint32} Settings.TagsAdded number of different tags added to videos | ||||
| 	 * @apiSuccess {string} Settings.PathPrefix | ||||
| 	 */ | ||||
| 	AddHandler("loadGeneralSettings", SettingsNode, func(info *HandlerInfo) []byte { | ||||
| 		result := database.GetSettings() | ||||
| 		return jsonify(result) | ||||
| 	}) | ||||
| 	AddHandler("loadInitialData", SettingsNode, nil, func() []byte { | ||||
|  | ||||
| 	/** | ||||
| 	 * @api {post} /api/settings [loadInitialData] | ||||
| 	 * @apiDescription load startdata to display on homepage | ||||
| 	 * @apiName loadInitialData | ||||
| 	 * @apiGroup Settings | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} VideoPath webserver path to the videos | ||||
| 	 * @apiSuccess {string} EpisodePath webserver path to the tvshows | ||||
| 	 * @apiSuccess {string} MediacenterName overall name of the mediacenter | ||||
| 	 * @apiSuccess {string} Pasword new server password (-1 if no password set) | ||||
| 	 * @apiSuccess {bool} DarkMode Darkmode enabled? | ||||
| 	 */ | ||||
| 	AddHandler("loadInitialData", SettingsNode, func(info *HandlerInfo) []byte { | ||||
| 		sett := settings.LoadSettings() | ||||
|  | ||||
| 		type InitialDataTypeResponse struct { | ||||
| @@ -52,10 +85,32 @@ func getSettingsFromDB() { | ||||
| } | ||||
|  | ||||
| func saveSettingsToDB() { | ||||
| 	var sgs struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/settings [saveGeneralSettings] | ||||
| 	 * @apiDescription Save the global settings provided | ||||
| 	 * @apiName saveGeneralSettings | ||||
| 	 * @apiGroup Settings | ||||
| 	 * | ||||
| 	 * @apiParam {Object} Settings Settings object | ||||
| 	 * @apiParam {string} Settings.VideoPath webserver path to the videos | ||||
| 	 * @apiParam {string} Settings.EpisodePath webserver path to the tvshows | ||||
| 	 * @apiParam {string} Settings.MediacenterName overall name of the mediacenter | ||||
| 	 * @apiParam {string} Settings.Password new server password (-1 if no password set) | ||||
| 	 * @apiParam {bool} Settings.TMDBGrabbing TMDB grabbing support to grab tag info and thumbnails | ||||
| 	 * @apiParam {bool} Settings.DarkMode Darkmode enabled? | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("saveGeneralSettings", SettingsNode, func(info *HandlerInfo) []byte { | ||||
| 		// todo correct type here! | ||||
| 		var args struct { | ||||
| 			Settings types.SettingsType | ||||
| 		} | ||||
| 	AddHandler("saveGeneralSettings", SettingsNode, &sgs, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := ` | ||||
| 					UPDATE settings SET  | ||||
|                         video_path=?, | ||||
| @@ -66,24 +121,46 @@ func saveSettingsToDB() { | ||||
|                         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) | ||||
| 			args.Settings.VideoPath, args.Settings.EpisodePath, args.Settings.Password, | ||||
| 			args.Settings.MediacenterName, args.Settings.TMDBGrabbing, args.Settings.DarkMode) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // methods for handling reindexing and cleanup of db gravity | ||||
| func reIndexHandling() { | ||||
| 	AddHandler("startReindex", SettingsNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/settings [startReindex] | ||||
| 	 * @apiDescription Start Database video reindex Job | ||||
| 	 * @apiName startReindex | ||||
| 	 * @apiGroup Settings | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("startReindex", SettingsNode, func(info *HandlerInfo) []byte { | ||||
| 		videoparser.StartReindex() | ||||
| 		return database.ManualSuccessResponse(nil) | ||||
| 	}) | ||||
|  | ||||
| 	AddHandler("startTVShowReindex", SettingsNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/settings [startTVShowReindex] | ||||
| 	 * @apiDescription Start Database TVShow reindex job | ||||
| 	 * @apiName startTVShowReindex | ||||
| 	 * @apiGroup Settings | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("startTVShowReindex", SettingsNode, func(info *HandlerInfo) []byte { | ||||
| 		videoparser.StartTVShowReindex() | ||||
| 		return database.ManualSuccessResponse(nil) | ||||
| 	}) | ||||
|  | ||||
| 	AddHandler("cleanupGravity", SettingsNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/settings [cleanupGravity] | ||||
| 	 * @apiDescription Start Database cleanup job | ||||
| 	 * @apiName cleanupGravity | ||||
| 	 * @apiGroup Settings | ||||
| 	 */ | ||||
| 	AddHandler("cleanupGravity", SettingsNode, func(info *HandlerInfo) []byte { | ||||
| 		videoparser.StartCleanup() | ||||
| 		return nil | ||||
| 	}) | ||||
|   | ||||
| @@ -6,17 +6,46 @@ import ( | ||||
| ) | ||||
|  | ||||
| func AddTvshowHandlers() { | ||||
| 	AddHandler("getTVShows", TVShowNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tvshow [getTVShows] | ||||
| 	 * @apiDescription get all available tv shows | ||||
| 	 * @apiName getTVShows | ||||
| 	 * @apiGroup TVshow | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} . | ||||
| 	 * @apiSuccess {uint32} .Id tvshow id | ||||
| 	 * @apiSuccess {string} .Name tvshow name | ||||
| 	 */ | ||||
| 	AddHandler("getTVShows", TVShowNode, func(info *HandlerInfo) []byte { | ||||
| 		query := "SELECT id, name FROM tvshow" | ||||
| 		rows := database.Query(query) | ||||
| 		return jsonify(readTVshowsFromResultset(rows)) | ||||
| 	}) | ||||
|  | ||||
| 	var ge struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tvshow [getEpisodes] | ||||
| 	 * @apiDescription get all Episodes of a TVShow | ||||
| 	 * @apiName getEpisodes | ||||
| 	 * @apiGroup TVshow | ||||
| 	 * | ||||
| 	 * @apiParam {uint32} ShowID id of tvshow to get episodes from | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} . | ||||
| 	 * @apiSuccess {uint32} .ID episode id | ||||
| 	 * @apiSuccess {string} .Name episode name | ||||
| 	 * @apiSuccess {uint8} .Season Season number | ||||
| 	 * @apiSuccess {uint8} .Episode Episode number | ||||
| 	 */ | ||||
| 	AddHandler("getEpisodes", TVShowNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			ShowID uint32 | ||||
| 		} | ||||
| 	AddHandler("getEpisodes", TVShowNode, &ge, func() []byte { | ||||
| 		query := fmt.Sprintf("SELECT id, name, season, episode FROM tvshow_episodes WHERE tvshow_id=%d", ge.ShowID) | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := fmt.Sprintf("SELECT id, name, season, episode FROM tvshow_episodes WHERE tvshow_id=%d", args.ShowID) | ||||
| 		rows := database.Query(query) | ||||
|  | ||||
| 		type Episode struct { | ||||
| @@ -41,15 +70,34 @@ func AddTvshowHandlers() { | ||||
| 		return jsonify(episodes) | ||||
| 	}) | ||||
|  | ||||
| 	var le struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tvshow [loadEpisode] | ||||
| 	 * @apiDescription load all info of episode | ||||
| 	 * @apiName loadEpisode | ||||
| 	 * @apiGroup TVshow | ||||
| 	 * | ||||
| 	 * @apiParam {uint32} ID id of episode | ||||
| 	 * | ||||
| 	 * @apiSuccess {uint32} TVShowID episode id | ||||
| 	 * @apiSuccess {string} Name episode name | ||||
| 	 * @apiSuccess {uint8} Season Season number | ||||
| 	 * @apiSuccess {uint8} Episode Episode number | ||||
| 	 * @apiSuccess {string} Path webserver path of video file | ||||
| 	 */ | ||||
| 	AddHandler("loadEpisode", TVShowNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			ID uint32 | ||||
| 		} | ||||
| 	AddHandler("loadEpisode", TVShowNode, &le, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := fmt.Sprintf(` | ||||
| SELECT tvshow_episodes.name, season, tvshow_id, episode, filename, t.foldername | ||||
| FROM tvshow_episodes  | ||||
| JOIN tvshow t on t.id = tvshow_episodes.tvshow_id | ||||
| WHERE tvshow_episodes.id=%d`, le.ID) | ||||
| WHERE tvshow_episodes.id=%d`, args.ID) | ||||
| 		row := database.QueryRow(query) | ||||
|  | ||||
| 		var ret struct { | ||||
| @@ -73,17 +121,32 @@ WHERE tvshow_episodes.id=%d`, le.ID) | ||||
| 		return jsonify(ret) | ||||
| 	}) | ||||
|  | ||||
| 	var rtn struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tvshow [readThumbnail] | ||||
| 	 * @apiDescription Load Thubnail of specific episode | ||||
| 	 * @apiName readThumbnail | ||||
| 	 * @apiGroup TVshow | ||||
| 	 * | ||||
| 	 * @apiParam {int} Id id of episode to load thumbnail | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} . Base64 encoded Thubnail | ||||
| 	 */ | ||||
| 	AddHandler("readThumbnail", TVShowNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			Id int | ||||
| 		} | ||||
| 	AddHandler("readThumbnail", TVShowNode, &rtn, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		var pic []byte | ||||
|  | ||||
| 		query := fmt.Sprintf("SELECT thumbnail FROM tvshow WHERE id=%d", rtn.Id) | ||||
| 		query := fmt.Sprintf("SELECT thumbnail FROM tvshow WHERE id=%d", args.Id) | ||||
|  | ||||
| 		err := database.QueryRow(query).Scan(&pic) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("the thumbnail of movie id %d couldn't be found", rtn.Id) | ||||
| 			fmt.Printf("the thumbnail of movie id %d couldn't be found", args.Id) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -13,14 +13,30 @@ func AddTagHandlers() { | ||||
| } | ||||
|  | ||||
| func deleteFromDB() { | ||||
| 	var dT struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tags [deleteTag] | ||||
| 	 * @apiDescription Start Database video reindex Job | ||||
| 	 * @apiName deleteTag | ||||
| 	 * @apiGroup Tags | ||||
| 	 * | ||||
| 	 * @apiParam {bool} [Force] force delete tag with its constraints | ||||
| 	 * @apiParam {int} TagId id of tag to delete | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("deleteTag", TagNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			TagId int | ||||
| 			Force bool | ||||
| 		} | ||||
| 	AddHandler("deleteTag", TagNode, &dT, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		// delete key constraints first | ||||
| 		if dT.Force { | ||||
| 			query := fmt.Sprintf("DELETE FROM video_tags WHERE tag_id=%d", dT.TagId) | ||||
| 		if args.Force { | ||||
| 			query := fmt.Sprintf("DELETE FROM video_tags WHERE tag_id=%d", args.TagId) | ||||
| 			err := database.Edit(query) | ||||
|  | ||||
| 			// respond only if result not successful | ||||
| @@ -29,7 +45,7 @@ func deleteFromDB() { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		query := fmt.Sprintf("DELETE FROM tags WHERE tag_id=%d", dT.TagId) | ||||
| 		query := fmt.Sprintf("DELETE FROM tags WHERE tag_id=%d", args.TagId) | ||||
| 		err := database.Edit(query) | ||||
|  | ||||
| 		if err == nil { | ||||
| @@ -39,7 +55,7 @@ func deleteFromDB() { | ||||
| 			// check with regex if its the key constraint error | ||||
| 			r := regexp.MustCompile("^.*a foreign key constraint fails.*$") | ||||
| 			if r.MatchString(err.Error()) { | ||||
| 				return []byte(`{"result":"not empty tag"}`) | ||||
| 				return database.ManualSuccessResponse(fmt.Errorf("not empty tag")) | ||||
| 			} else { | ||||
| 				return database.ManualSuccessResponse(err) | ||||
| 			} | ||||
| @@ -48,27 +64,68 @@ func deleteFromDB() { | ||||
| } | ||||
|  | ||||
| func getFromDB() { | ||||
| 	AddHandler("getAllTags", TagNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tags [getAllTags] | ||||
| 	 * @apiDescription get all available Tags | ||||
| 	 * @apiName getAllTags | ||||
| 	 * @apiGroup Tags | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} array of tag objects | ||||
| 	 * @apiSuccess {uint32} TagId | ||||
| 	 * @apiSuccess {string} TagName name of the Tag | ||||
| 	 */ | ||||
| 	AddHandler("getAllTags", TagNode, func(info *HandlerInfo) []byte { | ||||
| 		query := "SELECT tag_id,tag_name from tags" | ||||
| 		return jsonify(readTagsFromResultset(database.Query(query))) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func addToDB() { | ||||
| 	var ct struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tags [createTag] | ||||
| 	 * @apiDescription create a new tag | ||||
| 	 * @apiName createTag | ||||
| 	 * @apiGroup Tags | ||||
| 	 * | ||||
| 	 * @apiParam {string} TagName name of the tag | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("createTag", TagNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			TagName string | ||||
| 		} | ||||
| 	AddHandler("createTag", TagNode, &ct, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := "INSERT IGNORE INTO tags (tag_name) VALUES (?)" | ||||
| 		return database.SuccessQuery(query, ct.TagName) | ||||
| 		return database.SuccessQuery(query, args.TagName) | ||||
| 	}) | ||||
|  | ||||
| 	var at struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/tags [addTag] | ||||
| 	 * @apiDescription Add new tag to video | ||||
| 	 * @apiName addTag | ||||
| 	 * @apiGroup Tags | ||||
| 	 * | ||||
| 	 * @apiParam {int} TagId Tag id to add to video | ||||
| 	 * @apiParam {int} MovieId Video Id of video to add tag to | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("addTag", TagNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			MovieId int | ||||
| 			TagId   int | ||||
| 		} | ||||
| 	AddHandler("addTag", TagNode, &at, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := "INSERT IGNORE INTO video_tags(tag_id, video_id) VALUES (?,?)" | ||||
| 		return database.SuccessQuery(query, at.TagId, at.MovieId) | ||||
| 		return database.SuccessQuery(query, args.TagId, args.MovieId) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -16,18 +16,35 @@ func AddVideoHandlers() { | ||||
| } | ||||
|  | ||||
| func getVideoHandlers() { | ||||
| 	var mrq struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [getMovies] | ||||
| 	 * @apiDescription Request available Videos | ||||
| 	 * @apiName GetMovies | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {int} [Tag=all] id of VideoTag to get videos | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} . List of Videos | ||||
| 	 * @apiSuccess {number} .MovieId Id of Video | ||||
| 	 * @apiSuccess {String} .MovieName  Name of video | ||||
| 	 */ | ||||
| 	AddHandler("getMovies", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			Tag int | ||||
| 		} | ||||
| 	AddHandler("getMovies", VideoNode, &mrq, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		var query string | ||||
| 		// 1 is the id of the ALL tag | ||||
| 		if mrq.Tag != 1 { | ||||
| 		if args.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) | ||||
| 					ORDER BY likes DESC, create_date, movie_name`, args.Tag) | ||||
| 		} else { | ||||
| 			query = "SELECT movie_id,movie_name FROM videos ORDER BY create_date DESC, movie_name" | ||||
| 		} | ||||
| @@ -38,33 +55,69 @@ func getVideoHandlers() { | ||||
| 		return str | ||||
| 	}) | ||||
|  | ||||
| 	var rtn struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [readThumbnail] | ||||
| 	 * @apiDescription Load Thubnail of specific Video | ||||
| 	 * @apiName readThumbnail | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {int} Movieid id of video to load thumbnail | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} . Base64 encoded Thubnail | ||||
| 	 */ | ||||
| 	AddHandler("readThumbnail", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			Movieid int | ||||
| 		} | ||||
| 	AddHandler("readThumbnail", VideoNode, &rtn, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		var pic []byte | ||||
|  | ||||
| 		query := fmt.Sprintf("SELECT thumbnail FROM videos WHERE movie_id=%d", rtn.Movieid) | ||||
| 		query := fmt.Sprintf("SELECT thumbnail FROM videos WHERE movie_id=%d", args.Movieid) | ||||
|  | ||||
| 		err := database.QueryRow(query).Scan(&pic) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("the thumbnail of movie id %d couldn't be found", rtn.Movieid) | ||||
| 			fmt.Printf("the thumbnail of movie id %d couldn't be found", args.Movieid) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		return pic | ||||
| 	}) | ||||
|  | ||||
| 	var grm struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [getRandomMovies] | ||||
| 	 * @apiDescription Load random videos | ||||
| 	 * @apiName getRandomMovies | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {int} Number number of random videos to load | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} Tags Array of tags occuring in selection | ||||
| 	 * @apiSuccess {string} Tags.TagName Tagname | ||||
| 	 * @apiSuccess {uint32} Tags.TagId Tag ID | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} Videos Array of the videos | ||||
| 	 * @apiSuccess {string} Videos.MovieName Video Name | ||||
| 	 * @apiSuccess {int} Videos.MovieId Video ID | ||||
| 	 */ | ||||
| 	AddHandler("getRandomMovies", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			Number int | ||||
| 		} | ||||
| 	AddHandler("getRandomMovies", VideoNode, &grm, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 		query := fmt.Sprintf("SELECT movie_id,movie_name FROM videos ORDER BY RAND() LIMIT %d", args.Number) | ||||
| 		result.Videos = readVideosFromResultset(database.Query(query)) | ||||
|  | ||||
| 		var ids string | ||||
| @@ -99,13 +152,30 @@ func getVideoHandlers() { | ||||
| 		return str | ||||
| 	}) | ||||
|  | ||||
| 	var gsk struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [getSearchKeyWord] | ||||
| 	 * @apiDescription Get videos for search keyword | ||||
| 	 * @apiName getSearchKeyWord | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {string} KeyWord Keyword to search for | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} . List of Videos | ||||
| 	 * @apiSuccess {number} .MovieId Id of Video | ||||
| 	 * @apiSuccess {String} .MovieName  Name of video | ||||
| 	 */ | ||||
| 	AddHandler("getSearchKeyWord", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			KeyWord string | ||||
| 		} | ||||
| 	AddHandler("getSearchKeyWord", VideoNode, &gsk, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 					ORDER BY likes DESC, create_date DESC, movie_name`, args.KeyWord) | ||||
|  | ||||
| 		result := readVideosFromResultset(database.Query(query)) | ||||
| 		// jsonify results | ||||
| @@ -116,12 +186,47 @@ func getVideoHandlers() { | ||||
|  | ||||
| // function to handle stuff for loading specific videos and startdata | ||||
| func loadVideosHandlers() { | ||||
| 	var lv struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [loadVideo] | ||||
| 	 * @apiDescription Load all data for a specific video | ||||
| 	 * @apiName loadVideo | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {int} MovieId ID of video | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} MovieName Videoname | ||||
| 	 * @apiSuccess {uint32} MovieId Video ID | ||||
| 	 * @apiSuccess {string} MovieUrl Url to video file | ||||
| 	 * @apiSuccess {string} Poster Base64 encoded Poster | ||||
| 	 * @apiSuccess {uint64} Likes Number of likes | ||||
| 	 * @apiSuccess {uint16} Quality Video FrameWidth | ||||
| 	 * @apiSuccess {uint16} Length Video Length in seconds | ||||
| 	 * | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} Tags Array of tags of video | ||||
| 	 * @apiSuccess {string} Tags.TagName Tagname | ||||
| 	 * @apiSuccess {uint32} Tags.TagId Tag ID | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} SuggestedTag Array of tags for quick add suggestions | ||||
| 	 * @apiSuccess {string} SuggestedTag.TagName Tagname | ||||
| 	 * @apiSuccess {uint32} SuggestedTag.TagId Tag ID | ||||
| 	 * | ||||
| 	 * @apiSuccess {Object[]} Actors Array of Actors playing in this video | ||||
| 	 * @apiSuccess {uint32} Actors.ActorId Actor Id | ||||
| 	 * @apiSuccess {string} Actors.Name Actor Name | ||||
| 	 * @apiSuccess {string} Actors.Thumbnail Portrait Thumbnail | ||||
| 	 */ | ||||
| 	AddHandler("loadVideo", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			MovieId int | ||||
| 		} | ||||
| 	AddHandler("loadVideo", VideoNode, &lv, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := fmt.Sprintf(`SELECT movie_name,movie_url,movie_id,thumbnail,poster,likes,quality,length  | ||||
| 										FROM videos WHERE movie_id=%d`, lv.MovieId) | ||||
| 										FROM videos WHERE movie_id=%d`, args.MovieId) | ||||
|  | ||||
| 		var res types.FullVideoType | ||||
| 		var poster []byte | ||||
| @@ -129,7 +234,7 @@ func loadVideosHandlers() { | ||||
|  | ||||
| 		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.Printf("error getting full data list of videoid - %d", args.MovieId) | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
| @@ -149,7 +254,7 @@ func loadVideosHandlers() { | ||||
| 		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) | ||||
| 					GROUP BY t.tag_id`, args.MovieId) | ||||
|  | ||||
| 		res.Tags = readTagsFromResultset(database.Query(query)) | ||||
|  | ||||
| @@ -158,14 +263,14 @@ func loadVideosHandlers() { | ||||
| 						SELECT video_tags.tag_id FROM video_tags | ||||
| 					WHERE video_id=%d) | ||||
| 					ORDER BY rand() | ||||
| 					LIMIT 5`, lv.MovieId) | ||||
| 					LIMIT 5`, args.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) | ||||
| 					WHERE actors_videos.video_id=%d`, args.MovieId) | ||||
|  | ||||
| 		res.Actors = readActorsFromResultset(database.Query(query)) | ||||
|  | ||||
| @@ -174,7 +279,20 @@ func loadVideosHandlers() { | ||||
| 		return str | ||||
| 	}) | ||||
|  | ||||
| 	AddHandler("getStartData", VideoNode, nil, func() []byte { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [getStartData] | ||||
| 	 * @apiDescription Get general video informations at start | ||||
| 	 * @apiName getStartData | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiSuccess {uint32} VideoNr Total nr of videos | ||||
| 	 * @apiSuccess {uint32} FullHdNr number of FullHD videos | ||||
| 	 * @apiSuccess {uint32} HDNr number of HD videos | ||||
| 	 * @apiSuccess {uint32} SDNr number of SD videos | ||||
| 	 * @apiSuccess {uint32} DifferentTags number of different Tags available | ||||
| 	 * @apiSuccess {uint32} Tagged number of different Tags assigned | ||||
| 	 */ | ||||
| 	AddHandler("getStartData", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var result types.StartData | ||||
| 		// query settings and infotile values | ||||
| 		query := ` | ||||
| @@ -215,24 +333,54 @@ func loadVideosHandlers() { | ||||
| } | ||||
|  | ||||
| func addToVideoHandlers() { | ||||
| 	var al struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [addLike] | ||||
| 	 * @apiDescription Add a like to a video | ||||
| 	 * @apiName addLike | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {int} MovieId ID of video | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("addLike", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			MovieId int | ||||
| 		} | ||||
| 	AddHandler("addLike", VideoNode, &al, func() []byte { | ||||
| 		query := fmt.Sprintf("update videos set likes = likes + 1 where movie_id = %d", al.MovieId) | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		query := fmt.Sprintf("update videos set likes = likes + 1 where movie_id = %d", args.MovieId) | ||||
| 		return database.SuccessQuery(query) | ||||
| 	}) | ||||
|  | ||||
| 	var dv struct { | ||||
| 	/** | ||||
| 	 * @api {post} /api/video [deleteVideo] | ||||
| 	 * @apiDescription Delete a specific video from database | ||||
| 	 * @apiName deleteVideo | ||||
| 	 * @apiGroup video | ||||
| 	 * | ||||
| 	 * @apiParam {int} MovieId ID of video | ||||
| 	 * | ||||
| 	 * @apiSuccess {string} result 'success' if successfully or error message if not | ||||
| 	 */ | ||||
| 	AddHandler("deleteVideo", VideoNode, func(info *HandlerInfo) []byte { | ||||
| 		var args struct { | ||||
| 			MovieId int | ||||
| 		} | ||||
| 	AddHandler("deleteVideo", VideoNode, &dv, func() []byte { | ||||
| 		if err := FillStruct(&args, info.Data); err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		// delete tag constraints | ||||
| 		query := fmt.Sprintf("DELETE FROM video_tags WHERE video_id=%d", dv.MovieId) | ||||
| 		query := fmt.Sprintf("DELETE FROM video_tags WHERE video_id=%d", args.MovieId) | ||||
| 		err := database.Edit(query) | ||||
|  | ||||
| 		// delete actor constraints | ||||
| 		query = fmt.Sprintf("DELETE FROM actors_videos WHERE video_id=%d", dv.MovieId) | ||||
| 		query = fmt.Sprintf("DELETE FROM actors_videos WHERE video_id=%d", args.MovieId) | ||||
| 		err = database.Edit(query) | ||||
|  | ||||
| 		// respond only if result not successful | ||||
| @@ -240,7 +388,7 @@ func addToVideoHandlers() { | ||||
| 			return database.ManualSuccessResponse(err) | ||||
| 		} | ||||
|  | ||||
| 		query = fmt.Sprintf("DELETE FROM videos WHERE movie_id=%d", dv.MovieId) | ||||
| 		query = fmt.Sprintf("DELETE FROM videos WHERE movie_id=%d", args.MovieId) | ||||
| 		return database.SuccessQuery(query) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package oauth | ||||
|  | ||||
| import ( | ||||
| 	"gopkg.in/oauth2.v3" | ||||
| 	"gopkg.in/oauth2.v3/errors" | ||||
| 	"gopkg.in/oauth2.v3/manage" | ||||
| 	"gopkg.in/oauth2.v3/server" | ||||
| @@ -48,14 +49,14 @@ func InitOAuth() { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func ValidateToken(f func(rw http.ResponseWriter, req *http.Request, node int), node int) http.HandlerFunc { | ||||
| func ValidateToken(f func(rw http.ResponseWriter, req *http.Request, node int, tokenInfo *oauth2.TokenInfo), node int) http.HandlerFunc { | ||||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		_, err := srv.ValidationBearerToken(r) | ||||
| 		tokeninfo, err := srv.ValidationBearerToken(r) | ||||
| 		if err != nil { | ||||
| 			http.Error(w, err.Error(), http.StatusBadRequest) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		f(w, r, node) | ||||
| 		f(w, r, node, &tokeninfo) | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @@ -25,7 +25,8 @@ | ||||
|     "start": "react-scripts start", | ||||
|     "build": "CI=false react-scripts build", | ||||
|     "test": "CI=true react-scripts test --reporters=jest-junit --verbose --silent --coverage --reporters=default", | ||||
|     "lint": "eslint --format gitlab src/" | ||||
|     "lint": "eslint --format gitlab src/", | ||||
|     "apidoc": "apidoc -i apiGo/ -o doc/" | ||||
|   }, | ||||
|   "jest": { | ||||
|     "collectCoverageFrom": [ | ||||
| @@ -76,6 +77,13 @@ | ||||
|     "jest-junit": "^12.0.0", | ||||
|     "prettier": "^2.2.1", | ||||
|     "prettier-config": "^1.0.0", | ||||
|     "react-scripts": "4.0.3" | ||||
|     "react-scripts": "4.0.3", | ||||
|     "apidoc": "^0.28.1" | ||||
|   }, | ||||
|   "apidoc":{ | ||||
|     "name": "OpenMediaCenter", | ||||
|     "description": "API Documentation of OpenMediaCenter", | ||||
|     "title": "OpenMediaCenter Doc", | ||||
|     "sampleUrl": null | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ const VideoContainer = (props: Props): JSX.Element => { | ||||
|                             APINode.Video, | ||||
|                             { | ||||
|                                 action: 'readThumbnail', | ||||
|                                 movieid: el.MovieId | ||||
|                                 Movieid: el.MovieId | ||||
|                             }, | ||||
|                             (result) => callback(result) | ||||
|                         ); | ||||
|   | ||||
| @@ -105,7 +105,7 @@ export class CategoryView extends React.Component<CategoryViewProps, CategoryVie | ||||
|      * @param id tagid | ||||
|      */ | ||||
|     private fetchVideoData(id: number): void { | ||||
|         callAPI<VideoTypes.VideoUnloadedType[]>(APINode.Video, {action: 'getMovies', tag: id}, (result) => { | ||||
|         callAPI<VideoTypes.VideoUnloadedType[]>(APINode.Video, {action: 'getMovies', Tag: id}, (result) => { | ||||
|             this.videodata = result; | ||||
|             this.setState({loaded: true}); | ||||
|         }); | ||||
|   | ||||
| @@ -59,7 +59,7 @@ export class HomePage extends React.Component<Props, state> { | ||||
|      * @param tag tag to fetch videos | ||||
|      */ | ||||
|     fetchVideoData(tag: number): void { | ||||
|         callAPI(APINode.Video, {action: 'getMovies', tag: tag}, (result: VideoTypes.VideoUnloadedType[]) => { | ||||
|         callAPI(APINode.Video, {action: 'getMovies', Tag: tag}, (result: VideoTypes.VideoUnloadedType[]) => { | ||||
|             this.setState({ | ||||
|                 data: [] | ||||
|             }); | ||||
|   | ||||
| @@ -57,7 +57,7 @@ export class SearchHandling extends React.Component<Props, state> { | ||||
|      * @param keyword The keyword to search for | ||||
|      */ | ||||
|     searchVideos(keyword: string): void { | ||||
|         callAPI(APINode.Video, {action: 'getSearchKeyWord', keyword: keyword}, (result: VideoTypes.VideoUnloadedType[]) => { | ||||
|         callAPI(APINode.Video, {action: 'getSearchKeyWord', KeyWord: keyword}, (result: VideoTypes.VideoUnloadedType[]) => { | ||||
|             this.setState({ | ||||
|                 data: result | ||||
|             }); | ||||
|   | ||||
| @@ -85,8 +85,7 @@ class RandomPage extends React.Component<{}, state> { | ||||
|      * @param nr number of videos to load | ||||
|      */ | ||||
|     loadShuffledvideos(nr: number): void { | ||||
|         callAPI<GetRandomMoviesType>(APINode.Video, {action: 'getRandomMovies', number: nr}, (result) => { | ||||
|             console.log(result); | ||||
|         callAPI<GetRandomMoviesType>(APINode.Video, {action: 'getRandomMovies', Number: nr}, (result) => { | ||||
|             this.setState({videos: []}); // needed to trigger rerender of main videoview | ||||
|             this.setState({ | ||||
|                 videos: result.Videos, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user