add tvshow syntax to db

basic tvshow api request to show available tvshows
limit randompage videos to 3
improve settings object to remove one useless copy
This commit is contained in:
lukas 2021-04-16 22:44:56 +02:00
parent fdcecb0a75
commit 4539147208
17 changed files with 165 additions and 69 deletions

View File

@ -15,6 +15,7 @@ const (
TagNode = iota TagNode = iota
SettingsNode = iota SettingsNode = iota
ActorNode = iota ActorNode = iota
TVShowNode = iota
) )
type actionStruct struct { type actionStruct struct {
@ -36,10 +37,11 @@ func AddHandler(action string, apiNode int, n interface{}, h func() []byte) {
} }
func ServerInit() { func ServerInit() {
http.Handle(APIPREFIX+"/video", oauth.ValidateToken(videoHandler)) http.Handle(APIPREFIX+"/video", oauth.ValidateToken(handlefunc, VideoNode))
http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(tagHandler)) http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(handlefunc, TagNode))
http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler)) http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(handlefunc, SettingsNode))
http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(actorHandler)) http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(handlefunc, ActorNode))
http.Handle(APIPREFIX+"/tvshow", oauth.ValidateToken(handlefunc, TVShowNode))
// initialize oauth service and add corresponding auth routes // initialize oauth service and add corresponding auth routes
oauth.InitOAuth() oauth.InitOAuth()
@ -65,22 +67,6 @@ func handleAPICall(action string, requestBody string, apiNode int) []byte {
return nil 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) { func handlefunc(rw http.ResponseWriter, req *http.Request, node int) {
// only allow post requests // only allow post requests
if req.Method != "POST" { if req.Method != "POST" {

View File

@ -61,6 +61,22 @@ func readActorsFromResultset(rows *sql.Rows) []types.Actor {
return result 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 { func jsonify(v interface{}) []byte {
// jsonify results // jsonify results
str, err := json.Marshal(v) str, err := json.Marshal(v)

View File

@ -29,17 +29,21 @@ func getSettingsFromDB() {
Pasword bool Pasword bool
MediacenterName string MediacenterName string
VideoPath 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) videoUrl := regexMatchUrl.FindString(sett.VideoPath)
tvshowurl := regexMatchUrl.FindString(sett.TVShowPath)
serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl) serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl)
serverTVShowPath := strings.TrimPrefix(sett.TVShowPath, tvshowurl)
res := InitialDataTypeResponse{ res := InitialDataTypeResponse{
DarkMode: sett.DarkMode, DarkMode: sett.DarkMode,
Pasword: sett.Pasword != "-1", Pasword: sett.Pasword != "-1",
MediacenterName: sett.Mediacenter_name, MediacenterName: sett.MediacenterName,
VideoPath: serverVideoPath, VideoPath: serverVideoPath,
TVShowPath: serverTVShowPath,
} }
str, _ := json.Marshal(res) str, _ := json.Marshal(res)
@ -74,6 +78,11 @@ func reIndexHandling() {
return database.ManualSuccessResponse(nil) return database.ManualSuccessResponse(nil)
}) })
AddHandler("startTVShowReindex", SettingsNode, nil, func() []byte {
videoparser.StartTVShowReindex()
return database.ManualSuccessResponse(nil)
})
AddHandler("cleanupGravity", SettingsNode, nil, func() []byte { AddHandler("cleanupGravity", SettingsNode, nil, func() []byte {
videoparser.StartCleanup() videoparser.StartCleanup()
return nil return nil

15
apiGo/api/TVShows.go Normal file
View File

@ -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))
})
}

View File

@ -37,7 +37,7 @@ func deleteFromDB() {
return database.ManualSuccessResponse(err) return database.ManualSuccessResponse(err)
} else { } else {
// check with regex if its the key constraint error // 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()) { if r.MatchString(err.Error()) {
return []byte(`{"result":"not empty tag"}`) return []byte(`{"result":"not empty tag"}`)
} else { } else {

View File

@ -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) { return func(w http.ResponseWriter, r *http.Request) {
_, err := srv.ValidationBearerToken(r) _, err := srv.ValidationBearerToken(r)
if err != nil { if err != nil {
@ -56,6 +56,6 @@ func ValidateToken(f http.HandlerFunc) http.HandlerFunc {
return return
} }
f.ServeHTTP(w, r) f(w, r, node)
} }
} }

View File

@ -7,12 +7,12 @@ type VideoUnloadedType struct {
type FullVideoType struct { type FullVideoType struct {
MovieName string MovieName string
MovieId int MovieId uint32
MovieUrl string MovieUrl string
Poster string Poster string
Likes int Likes uint64
Quality int Quality uint16
Length int Length uint16
Tags []Tag Tags []Tag
SuggestedTag []Tag SuggestedTag []Tag
Actors []Actor Actors []Actor
@ -20,22 +20,22 @@ type FullVideoType struct {
type Tag struct { type Tag struct {
TagName string TagName string
TagId int TagId uint32
} }
type Actor struct { type Actor struct {
ActorId int ActorId uint32
Name string Name string
Thumbnail string Thumbnail string
} }
type StartData struct { type StartData struct {
VideoNr int VideoNr uint32
FullHdNr int FullHdNr uint32
HDNr int HDNr uint32
SDNr int SDNr uint32
DifferentTags int DifferentTags uint32
Tagged int Tagged uint32
} }
type SettingsType struct { type SettingsType struct {
@ -47,10 +47,15 @@ type SettingsType struct {
TMDBGrabbing bool TMDBGrabbing bool
DarkMode bool DarkMode bool
VideoNr int VideoNr uint32
DBSize float32 DBSize float32
DifferentTags int DifferentTags uint32
TagsAdded int TagsAdded uint32
PathPrefix string PathPrefix string
} }
type TVShow struct {
Id uint32
Name string
}

View File

@ -15,35 +15,24 @@ func GetPassword() *string {
} }
type SettingsType struct { type SettingsType struct {
DarkMode bool DarkMode bool
Pasword string Pasword string
Mediacenter_name string MediacenterName string
VideoPath string VideoPath string
TVShowPath string
} }
func LoadSettings() *SettingsType { 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 { result := SettingsType{}
DarkMode int var darkmode uint8
Pasword string
Mediacenter_name string
VideoPath string
}
result := RawSettingsType{} err := database.QueryRow(query).Scan(&darkmode, &result.Pasword, &result.MediacenterName, &result.VideoPath, &result.TVShowPath)
err := database.QueryRow(query).Scan(&result.DarkMode, &result.Pasword, &result.Mediacenter_name, &result.VideoPath)
if err != nil { if err != nil {
fmt.Println("error while parsing db data: " + err.Error()) fmt.Println("error while parsing db data: " + err.Error())
} }
res := SettingsType{ result.DarkMode = darkmode != 0
DarkMode: result.DarkMode != 0, return &result
Pasword: result.Pasword,
Mediacenter_name: result.Mediacenter_name,
VideoPath: result.VideoPath,
}
return &res
} }

View File

@ -30,6 +30,7 @@ func main() {
api.AddSettingsHandlers() api.AddSettingsHandlers()
api.AddTagHandlers() api.AddTagHandlers()
api.AddActorsHandlers() api.AddActorsHandlers()
api.AddTvshowHandlers()
// add the static files // add the static files
static.ServeStaticFiles() static.ServeStaticFiles()

View File

@ -54,6 +54,11 @@ func StartReindex() bool {
return true return true
} }
// StartTVShowReindex reindex dir walks for TVShow reindex
func StartTVShowReindex() {
// todo implement walking through dirs and reindex!
}
func GetStatusMessage() *StatusMessage { func GetStatusMessage() *StatusMessage {
msg := StatusMessage{ msg := StatusMessage{
Messages: messageBuffer, Messages: messageBuffer,

View File

@ -24,6 +24,26 @@ create table if not exists tags
tag_name varchar(50) null 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 create table if not exists videos
( (
movie_id int auto_increment movie_id int auto_increment

View File

@ -79,7 +79,7 @@ class App extends React.Component<{}, state> {
// set theme // set theme
GlobalInfos.enableDarkTheme(result.DarkMode); GlobalInfos.enableDarkTheme(result.DarkMode);
GlobalInfos.setVideoPath(result.VideoPath); GlobalInfos.setVideoPaths(result.VideoPath, result.TVShowPath);
this.setState({ this.setState({
mediacentername: result.MediacenterName mediacentername: result.MediacenterName

View File

@ -23,6 +23,8 @@ interface GetRandomMoviesType {
* Randompage shuffles random viedeopreviews and provides a shuffle btn * Randompage shuffles random viedeopreviews and provides a shuffle btn
*/ */
class RandomPage extends React.Component<{}, state> { class RandomPage extends React.Component<{}, state> {
readonly LoadNR = 3;
constructor(props: {}) { constructor(props: {}) {
super(props); super(props);
@ -37,7 +39,7 @@ class RandomPage extends React.Component<{}, state> {
componentDidMount(): void { componentDidMount(): void {
addKeyHandler(this.keypress); addKeyHandler(this.keypress);
this.loadShuffledvideos(4); this.loadShuffledvideos(this.LoadNR);
} }
componentWillUnmount(): void { componentWillUnmount(): void {
@ -75,7 +77,7 @@ class RandomPage extends React.Component<{}, state> {
* click handler for shuffle btn * click handler for shuffle btn
*/ */
shuffleclick(): void { shuffleclick(): void {
this.loadShuffledvideos(4); this.loadShuffledvideos(this.LoadNR);
} }
/** /**

View File

@ -1,11 +1,38 @@
import React from 'react'; import React from 'react';
import Preview from '../../elements/Preview/Preview'; 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<Props, State> {
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 { render(): JSX.Element {
return ( return (
<> <>
<Preview name='myTestItem' picLoader={(callback): void => callback('')} /> <DynamicContentContainer
renderElement={(elem): JSX.Element => (
<Preview name={elem.Name} picLoader={(callback): void => callback('')} linkPath={'/tvshows/' + elem.Id} />
)}
data={this.state.loading ? [] : this.data}
/>
</> </>
); );
} }

View File

@ -35,6 +35,7 @@ export namespace SettingsTypes {
Password: boolean; Password: boolean;
MediacenterName: string; MediacenterName: string;
VideoPath: string; VideoPath: string;
TVShowPath: string;
} }
export interface loadGeneralSettingsType { 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 { export namespace ActorTypes {
/** /**
* result of actor fetch * result of actor fetch

View File

@ -279,5 +279,6 @@ export enum APINode {
Settings = 'settings', Settings = 'settings',
Tags = 'tags', Tags = 'tags',
Actor = 'actor', Actor = 'actor',
Video = 'video' Video = 'video',
TVShow = 'tvshow'
} }

View File

@ -8,6 +8,7 @@ import lighttheme from '../AppLightTheme.module.css';
class StaticInfos { class StaticInfos {
private darktheme: boolean = true; private darktheme: boolean = true;
private videopath: string = ''; private videopath: string = '';
private tvshowpath: string = '';
/** /**
* check if the current theme is the dark theme * check if the current theme is the dark theme
@ -47,8 +48,9 @@ class StaticInfos {
* set the current videopath * set the current videopath
* @param vidpath videopath with beginning and ending slash * @param vidpath videopath with beginning and ending slash
*/ */
setVideoPath(vidpath: string): void { setVideoPaths(vidpath: string, tvshowpath: string): void {
this.videopath = vidpath; this.videopath = vidpath;
this.tvshowpath = tvshowpath;
} }
/** /**
@ -58,6 +60,13 @@ class StaticInfos {
return this.videopath; return this.videopath;
} }
/**
* return the current tvshow path
*/
getTVShowPath(): string {
return this.tvshowpath;
}
/** /**
* load the Password page manually * load the Password page manually
*/ */