diff --git a/apiGo/api/ApiBase.go b/apiGo/api/ApiBase.go index 4dd760b..bc83d1f 100644 --- a/apiGo/api/ApiBase.go +++ b/apiGo/api/ApiBase.go @@ -15,6 +15,7 @@ const ( TagNode = iota SettingsNode = iota ActorNode = iota + TVShowNode = iota ) type actionStruct struct { @@ -36,10 +37,11 @@ func AddHandler(action string, apiNode int, n interface{}, h func() []byte) { } func ServerInit() { - http.Handle(APIPREFIX+"/video", oauth.ValidateToken(videoHandler)) - http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(tagHandler)) - http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler)) - http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(actorHandler)) + http.Handle(APIPREFIX+"/video", oauth.ValidateToken(handlefunc, VideoNode)) + http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(handlefunc, TagNode)) + http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(handlefunc, SettingsNode)) + http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(handlefunc, ActorNode)) + http.Handle(APIPREFIX+"/tvshow", oauth.ValidateToken(handlefunc, TVShowNode)) // initialize oauth service and add corresponding auth routes oauth.InitOAuth() @@ -65,22 +67,6 @@ func handleAPICall(action string, requestBody string, apiNode int) []byte { 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" { diff --git a/apiGo/api/Helpers.go b/apiGo/api/Helpers.go index 1437a68..2407997 100644 --- a/apiGo/api/Helpers.go +++ b/apiGo/api/Helpers.go @@ -61,6 +61,22 @@ func readActorsFromResultset(rows *sql.Rows) []types.Actor { return result } +// ID - Name : pay attention to the order! +func readTVshowsFromResultset(rows *sql.Rows) []types.TVShow { + result := []types.TVShow{} + for rows.Next() { + var vid types.TVShow + err := rows.Scan(&vid.Id, &vid.Name) + if err != nil { + panic(err.Error()) // proper error handling instead of panic in your app + } + result = append(result, vid) + } + rows.Close() + + return result +} + func jsonify(v interface{}) []byte { // jsonify results str, err := json.Marshal(v) diff --git a/apiGo/api/Settings.go b/apiGo/api/Settings.go index 2f6a296..6229903 100644 --- a/apiGo/api/Settings.go +++ b/apiGo/api/Settings.go @@ -29,17 +29,21 @@ func getSettingsFromDB() { Pasword bool MediacenterName string VideoPath string + TVShowPath string } - regexMatchUrl := regexp.MustCompile("^http(|s):\\/\\/([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}:[0-9]{1,5}") + regexMatchUrl := regexp.MustCompile("^http(|s)://([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}:[0-9]{1,5}") videoUrl := regexMatchUrl.FindString(sett.VideoPath) + tvshowurl := regexMatchUrl.FindString(sett.TVShowPath) serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl) + serverTVShowPath := strings.TrimPrefix(sett.TVShowPath, tvshowurl) res := InitialDataTypeResponse{ DarkMode: sett.DarkMode, Pasword: sett.Pasword != "-1", - MediacenterName: sett.Mediacenter_name, + MediacenterName: sett.MediacenterName, VideoPath: serverVideoPath, + TVShowPath: serverTVShowPath, } str, _ := json.Marshal(res) @@ -74,6 +78,11 @@ func reIndexHandling() { return database.ManualSuccessResponse(nil) }) + AddHandler("startTVShowReindex", SettingsNode, nil, func() []byte { + videoparser.StartTVShowReindex() + return database.ManualSuccessResponse(nil) + }) + AddHandler("cleanupGravity", SettingsNode, nil, func() []byte { videoparser.StartCleanup() return nil diff --git a/apiGo/api/TVShows.go b/apiGo/api/TVShows.go new file mode 100644 index 0000000..f06dafa --- /dev/null +++ b/apiGo/api/TVShows.go @@ -0,0 +1,15 @@ +package api + +import "openmediacenter/apiGo/database" + +func AddTvshowHandlers() { + var dT struct { + TagId int + Force bool + } + AddHandler("getTVShows", TVShowNode, &dT, func() []byte { + query := "SELECT id, name FROM tvshow" + rows := database.Query(query) + return jsonify(readTVshowsFromResultset(rows)) + }) +} diff --git a/apiGo/api/Tags.go b/apiGo/api/Tags.go index 6845926..8701731 100644 --- a/apiGo/api/Tags.go +++ b/apiGo/api/Tags.go @@ -37,7 +37,7 @@ func deleteFromDB() { return database.ManualSuccessResponse(err) } else { // check with regex if its the key constraint error - r, _ := regexp.Compile("^.*a foreign key constraint fails.*$") + r := regexp.MustCompile("^.*a foreign key constraint fails.*$") if r.MatchString(err.Error()) { return []byte(`{"result":"not empty tag"}`) } else { diff --git a/apiGo/api/oauth/Oauth.go b/apiGo/api/oauth/Oauth.go index ef5ec93..0d98e25 100644 --- a/apiGo/api/oauth/Oauth.go +++ b/apiGo/api/oauth/Oauth.go @@ -48,7 +48,7 @@ func InitOAuth() { }) } -func ValidateToken(f http.HandlerFunc) http.HandlerFunc { +func ValidateToken(f func(rw http.ResponseWriter, req *http.Request, node int), node int) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, err := srv.ValidationBearerToken(r) if err != nil { @@ -56,6 +56,6 @@ func ValidateToken(f http.HandlerFunc) http.HandlerFunc { return } - f.ServeHTTP(w, r) + f(w, r, node) } } diff --git a/apiGo/api/types/Types.go b/apiGo/api/types/Types.go index 7e6d6c3..e0d9652 100644 --- a/apiGo/api/types/Types.go +++ b/apiGo/api/types/Types.go @@ -7,12 +7,12 @@ type VideoUnloadedType struct { type FullVideoType struct { MovieName string - MovieId int + MovieId uint32 MovieUrl string Poster string - Likes int - Quality int - Length int + Likes uint64 + Quality uint16 + Length uint16 Tags []Tag SuggestedTag []Tag Actors []Actor @@ -20,22 +20,22 @@ type FullVideoType struct { type Tag struct { TagName string - TagId int + TagId uint32 } type Actor struct { - ActorId int + ActorId uint32 Name string Thumbnail string } type StartData struct { - VideoNr int - FullHdNr int - HDNr int - SDNr int - DifferentTags int - Tagged int + VideoNr uint32 + FullHdNr uint32 + HDNr uint32 + SDNr uint32 + DifferentTags uint32 + Tagged uint32 } type SettingsType struct { @@ -47,10 +47,15 @@ type SettingsType struct { TMDBGrabbing bool DarkMode bool - VideoNr int + VideoNr uint32 DBSize float32 - DifferentTags int - TagsAdded int + DifferentTags uint32 + TagsAdded uint32 PathPrefix string } + +type TVShow struct { + Id uint32 + Name string +} diff --git a/apiGo/database/settings/DBSettings.go b/apiGo/database/settings/DBSettings.go index 5323ace..75cbf51 100644 --- a/apiGo/database/settings/DBSettings.go +++ b/apiGo/database/settings/DBSettings.go @@ -15,35 +15,24 @@ func GetPassword() *string { } type SettingsType struct { - DarkMode bool - Pasword string - Mediacenter_name string - VideoPath string + DarkMode bool + Pasword string + MediacenterName string + VideoPath string + TVShowPath string } func LoadSettings() *SettingsType { - query := "SELECT DarkMode, password, mediacenter_name, video_path from settings" + query := "SELECT DarkMode, password, mediacenter_name, video_path, episode_path from settings" - type RawSettingsType struct { - DarkMode int - Pasword string - Mediacenter_name string - VideoPath string - } + result := SettingsType{} + var darkmode uint8 - result := RawSettingsType{} - - err := database.QueryRow(query).Scan(&result.DarkMode, &result.Pasword, &result.Mediacenter_name, &result.VideoPath) + err := database.QueryRow(query).Scan(&darkmode, &result.Pasword, &result.MediacenterName, &result.VideoPath, &result.TVShowPath) if err != nil { fmt.Println("error while parsing db data: " + err.Error()) } - res := SettingsType{ - DarkMode: result.DarkMode != 0, - Pasword: result.Pasword, - Mediacenter_name: result.Mediacenter_name, - VideoPath: result.VideoPath, - } - - return &res + result.DarkMode = darkmode != 0 + return &result } diff --git a/apiGo/main.go b/apiGo/main.go index 17974e8..2328dd9 100644 --- a/apiGo/main.go +++ b/apiGo/main.go @@ -30,6 +30,7 @@ func main() { api.AddSettingsHandlers() api.AddTagHandlers() api.AddActorsHandlers() + api.AddTvshowHandlers() // add the static files static.ServeStaticFiles() diff --git a/apiGo/videoparser/VideoParser.go b/apiGo/videoparser/VideoParser.go index bfc5348..8e2dd5c 100644 --- a/apiGo/videoparser/VideoParser.go +++ b/apiGo/videoparser/VideoParser.go @@ -54,6 +54,11 @@ func StartReindex() bool { return true } +// StartTVShowReindex reindex dir walks for TVShow reindex +func StartTVShowReindex() { + // todo implement walking through dirs and reindex! +} + func GetStatusMessage() *StatusMessage { msg := StatusMessage{ Messages: messageBuffer, diff --git a/database.sql b/database.sql index 4579e35..9b2fd9e 100644 --- a/database.sql +++ b/database.sql @@ -24,6 +24,26 @@ create table if not exists tags tag_name varchar(50) null ); +create table if not exists tvshow +( + name varchar(100) null, + thumbnail mediumblob null, + id int auto_increment + primary key +); + +create table if not exists tvshow_episodes +( + id int auto_increment + primary key, + name varchar(100) null, + season int null, + poster mediumblob null, + tvshow_id int null, + constraint tvshow_episodes_tvshow_id_fk + foreign key (tvshow_id) references tvshow (id) +); + create table if not exists videos ( movie_id int auto_increment diff --git a/src/App.tsx b/src/App.tsx index d3d4c81..77f440d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -79,7 +79,7 @@ class App extends React.Component<{}, state> { // set theme GlobalInfos.enableDarkTheme(result.DarkMode); - GlobalInfos.setVideoPath(result.VideoPath); + GlobalInfos.setVideoPaths(result.VideoPath, result.TVShowPath); this.setState({ mediacentername: result.MediacenterName diff --git a/src/pages/RandomPage/RandomPage.tsx b/src/pages/RandomPage/RandomPage.tsx index ffd3a79..c3468be 100644 --- a/src/pages/RandomPage/RandomPage.tsx +++ b/src/pages/RandomPage/RandomPage.tsx @@ -23,6 +23,8 @@ interface GetRandomMoviesType { * Randompage shuffles random viedeopreviews and provides a shuffle btn */ class RandomPage extends React.Component<{}, state> { + readonly LoadNR = 3; + constructor(props: {}) { super(props); @@ -37,7 +39,7 @@ class RandomPage extends React.Component<{}, state> { componentDidMount(): void { addKeyHandler(this.keypress); - this.loadShuffledvideos(4); + this.loadShuffledvideos(this.LoadNR); } componentWillUnmount(): void { @@ -75,7 +77,7 @@ class RandomPage extends React.Component<{}, state> { * click handler for shuffle btn */ shuffleclick(): void { - this.loadShuffledvideos(4); + this.loadShuffledvideos(this.LoadNR); } /** diff --git a/src/pages/TVShowPage/TVShowPage.tsx b/src/pages/TVShowPage/TVShowPage.tsx index dfec9d5..24fdd91 100644 --- a/src/pages/TVShowPage/TVShowPage.tsx +++ b/src/pages/TVShowPage/TVShowPage.tsx @@ -1,11 +1,38 @@ import React from 'react'; import Preview from '../../elements/Preview/Preview'; +import {APINode, callAPI} from '../../utils/Api'; +import {TVShow} from '../../types/ApiTypes'; +import DynamicContentContainer from '../../elements/DynamicContentContainer/DynamicContentContainer'; + +interface State { + loading: boolean; +} + +interface Props {} + +class TVShowPage extends React.Component { + state = { + loading: true + }; + + data: TVShow.TVshowType[] = []; + + componentDidMount(): void { + callAPI(APINode.TVShow, {action: 'getTVShows'}, (resp: TVShow.TVshowType[]) => { + this.data = resp; + this.setState({loading: false}); + }); + } -class TVShowPage extends React.Component { render(): JSX.Element { return ( <> - callback('')} /> + ( + callback('')} linkPath={'/tvshows/' + elem.Id} /> + )} + data={this.state.loading ? [] : this.data} + /> ); } diff --git a/src/types/ApiTypes.ts b/src/types/ApiTypes.ts index 25f1e88..882171f 100644 --- a/src/types/ApiTypes.ts +++ b/src/types/ApiTypes.ts @@ -35,6 +35,7 @@ export namespace SettingsTypes { Password: boolean; MediacenterName: string; VideoPath: string; + TVShowPath: string; } export interface loadGeneralSettingsType { @@ -58,6 +59,16 @@ export namespace SettingsTypes { } } +export namespace TVShow { + /** + * result of actor fetch + */ + export interface TVshowType { + Id: number; + Name: string; + } +} + export namespace ActorTypes { /** * result of actor fetch diff --git a/src/utils/Api.ts b/src/utils/Api.ts index 404b408..2d68ccd 100644 --- a/src/utils/Api.ts +++ b/src/utils/Api.ts @@ -279,5 +279,6 @@ export enum APINode { Settings = 'settings', Tags = 'tags', Actor = 'actor', - Video = 'video' + Video = 'video', + TVShow = 'tvshow' } diff --git a/src/utils/GlobalInfos.ts b/src/utils/GlobalInfos.ts index 37f4065..e55b570 100644 --- a/src/utils/GlobalInfos.ts +++ b/src/utils/GlobalInfos.ts @@ -8,6 +8,7 @@ import lighttheme from '../AppLightTheme.module.css'; class StaticInfos { private darktheme: boolean = true; private videopath: string = ''; + private tvshowpath: string = ''; /** * check if the current theme is the dark theme @@ -47,8 +48,9 @@ class StaticInfos { * set the current videopath * @param vidpath videopath with beginning and ending slash */ - setVideoPath(vidpath: string): void { + setVideoPaths(vidpath: string, tvshowpath: string): void { this.videopath = vidpath; + this.tvshowpath = tvshowpath; } /** @@ -58,6 +60,13 @@ class StaticInfos { return this.videopath; } + /** + * return the current tvshow path + */ + getTVShowPath(): string { + return this.tvshowpath; + } + /** * load the Password page manually */