* no unauthorized init
* more dynamic Preview element
This commit is contained in:
parent
57a7a9a827
commit
fdcecb0a75
@ -15,7 +15,6 @@ const (
|
||||
TagNode = iota
|
||||
SettingsNode = iota
|
||||
ActorNode = iota
|
||||
InitNode = iota
|
||||
)
|
||||
|
||||
type actionStruct struct {
|
||||
@ -42,9 +41,6 @@ func ServerInit() {
|
||||
http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler))
|
||||
http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(actorHandler))
|
||||
|
||||
// initialization api calls to check if password is neccessaray
|
||||
http.Handle(APIPREFIX+"/init", http.HandlerFunc(initHandler))
|
||||
|
||||
// initialize oauth service and add corresponding auth routes
|
||||
oauth.InitOAuth()
|
||||
}
|
||||
@ -85,10 +81,6 @@ func settingsHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
handlefunc(rw, req, SettingsNode)
|
||||
}
|
||||
|
||||
func initHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
handlefunc(rw, req, InitNode)
|
||||
}
|
||||
|
||||
func handlefunc(rw http.ResponseWriter, req *http.Request, node int) {
|
||||
// only allow post requests
|
||||
if req.Method != "POST" {
|
||||
|
@ -1,39 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"openmediacenter/apiGo/database/settings"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func AddInitHandlers() {
|
||||
passwordNeeded()
|
||||
}
|
||||
|
||||
func passwordNeeded() {
|
||||
AddHandler("loadInitialData", InitNode, nil, func() []byte {
|
||||
sett := settings.LoadSettings()
|
||||
|
||||
type InitialDataTypeResponse struct {
|
||||
DarkMode bool
|
||||
Pasword bool
|
||||
MediacenterName string
|
||||
VideoPath 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}")
|
||||
videoUrl := regexMatchUrl.FindString(sett.VideoPath)
|
||||
serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl)
|
||||
|
||||
res := InitialDataTypeResponse{
|
||||
DarkMode: sett.DarkMode,
|
||||
Pasword: sett.Pasword != "-1",
|
||||
MediacenterName: sett.Mediacenter_name,
|
||||
VideoPath: serverVideoPath,
|
||||
}
|
||||
|
||||
str, _ := json.Marshal(res)
|
||||
return str
|
||||
})
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"openmediacenter/apiGo/api/types"
|
||||
"openmediacenter/apiGo/database"
|
||||
"openmediacenter/apiGo/database/settings"
|
||||
"openmediacenter/apiGo/videoparser"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func AddSettingsHandlers() {
|
||||
@ -17,6 +21,30 @@ func getSettingsFromDB() {
|
||||
result := database.GetSettings()
|
||||
return jsonify(result)
|
||||
})
|
||||
AddHandler("loadInitialData", SettingsNode, nil, func() []byte {
|
||||
sett := settings.LoadSettings()
|
||||
|
||||
type InitialDataTypeResponse struct {
|
||||
DarkMode bool
|
||||
Pasword bool
|
||||
MediacenterName string
|
||||
VideoPath 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}")
|
||||
videoUrl := regexMatchUrl.FindString(sett.VideoPath)
|
||||
serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl)
|
||||
|
||||
res := InitialDataTypeResponse{
|
||||
DarkMode: sett.DarkMode,
|
||||
Pasword: sett.Pasword != "-1",
|
||||
MediacenterName: sett.Mediacenter_name,
|
||||
VideoPath: serverVideoPath,
|
||||
}
|
||||
|
||||
str, _ := json.Marshal(res)
|
||||
return str
|
||||
})
|
||||
}
|
||||
|
||||
func saveSettingsToDB() {
|
||||
|
@ -30,7 +30,6 @@ func main() {
|
||||
api.AddSettingsHandlers()
|
||||
api.AddTagHandlers()
|
||||
api.AddActorsHandlers()
|
||||
api.AddInitHandlers()
|
||||
|
||||
// add the static files
|
||||
static.ServeStaticFiles()
|
||||
|
14
src/App.tsx
14
src/App.tsx
@ -9,7 +9,7 @@ import style from './App.module.css';
|
||||
|
||||
import SettingsPage from './pages/SettingsPage/SettingsPage';
|
||||
import CategoryPage from './pages/CategoryPage/CategoryPage';
|
||||
import {APINode, apiTokenValid, callApiUnsafe, refreshAPIToken} from './utils/Api';
|
||||
import {APINode, apiTokenValid, callAPI, refreshAPIToken} from './utils/Api';
|
||||
|
||||
import {BrowserRouter as Router, NavLink, Route, Switch} from 'react-router-dom';
|
||||
import Player from './pages/Player/Player';
|
||||
@ -75,7 +75,7 @@ class App extends React.Component<{}, state> {
|
||||
|
||||
initialAPICall(): void {
|
||||
// this is the first api call so if it fails we know there is no connection to backend
|
||||
callApiUnsafe(APINode.Init, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => {
|
||||
callAPI(APINode.Settings, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => {
|
||||
// set theme
|
||||
GlobalInfos.enableDarkTheme(result.DarkMode);
|
||||
|
||||
@ -99,7 +99,15 @@ class App extends React.Component<{}, state> {
|
||||
|
||||
if (this.state.password === true) {
|
||||
// render authentication page if auth is neccessary
|
||||
return <AuthenticationPage onSuccessLogin={(): void => this.setState({password: false})} />;
|
||||
return (
|
||||
<AuthenticationPage
|
||||
onSuccessLogin={(): void => {
|
||||
this.setState({password: false});
|
||||
// reinit general infos
|
||||
this.initialAPICall();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.password === false) {
|
||||
return (
|
||||
<Router>
|
||||
|
@ -9,7 +9,6 @@ interface Props<T> {
|
||||
|
||||
interface state<T> {
|
||||
loadeditems: T[];
|
||||
selectionnr: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -24,8 +23,7 @@ class DynamicContentContainer<T> extends React.Component<Props<T>, state<T>> {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loadeditems: [],
|
||||
selectionnr: 0
|
||||
loadeditems: []
|
||||
};
|
||||
}
|
||||
|
||||
@ -35,6 +33,22 @@ class DynamicContentContainer<T> extends React.Component<Props<T>, state<T>> {
|
||||
this.loadPreviewBlock(this.props.initialLoadNr ? this.props.initialLoadNr : 16);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props<T>): void {
|
||||
// when source props change force update!
|
||||
if (prevProps.data.length !== this.props.data.length) {
|
||||
this.clean();
|
||||
this.loadPreviewBlock(this.props.initialLoadNr ? this.props.initialLoadNr : 16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear all elements rendered...
|
||||
*/
|
||||
clean(): void {
|
||||
this.loadindex = 0;
|
||||
this.setState({loadeditems: []});
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div className={style.maincontent}>
|
||||
|
@ -3,17 +3,18 @@ import style from './Preview.module.css';
|
||||
import {Spinner} from 'react-bootstrap';
|
||||
import {Link} from 'react-router-dom';
|
||||
import GlobalInfos from '../../utils/GlobalInfos';
|
||||
import {APINode, callAPIPlain} from '../../utils/Api';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faPhotoVideo} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
interface PreviewProps {
|
||||
name: string;
|
||||
movieId: number;
|
||||
picLoader: (callback: (pic: string) => void) => void;
|
||||
linkPath?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
interface PreviewState {
|
||||
previewpicture: string | null;
|
||||
picLoaded: boolean | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -21,30 +22,43 @@ interface PreviewState {
|
||||
* floating side by side
|
||||
*/
|
||||
class Preview extends React.Component<PreviewProps, PreviewState> {
|
||||
// store the picture to display
|
||||
pic?: string;
|
||||
|
||||
constructor(props: PreviewProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
previewpicture: null
|
||||
picLoaded: null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
callAPIPlain(APINode.Video, {action: 'readThumbnail', movieid: this.props.movieId}, (result) => {
|
||||
this.props.picLoader((result) => {
|
||||
this.pic = result;
|
||||
this.setState({
|
||||
previewpicture: result
|
||||
picLoaded: result !== ''
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (this.props.linkPath !== undefined) {
|
||||
return <Link to={this.props.linkPath}>{this.content()}</Link>;
|
||||
} else {
|
||||
return this.content();
|
||||
}
|
||||
}
|
||||
|
||||
content(): JSX.Element {
|
||||
const themeStyle = GlobalInfos.getThemeStyle();
|
||||
return (
|
||||
<Link to={'/player/' + this.props.movieId}>
|
||||
<div className={style.videopreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview}>
|
||||
<div
|
||||
className={style.videopreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview}
|
||||
onClick={this.props.onClick}>
|
||||
<div className={style.previewtitle + ' ' + themeStyle.lighttextcolor}>{this.props.name}</div>
|
||||
<div className={style.previewpic}>
|
||||
{this.state.previewpicture === '' ? (
|
||||
{this.state.picLoaded === false ? (
|
||||
<FontAwesomeIcon
|
||||
style={{
|
||||
color: 'white',
|
||||
@ -53,17 +67,16 @@ class Preview extends React.Component<PreviewProps, PreviewState> {
|
||||
icon={faPhotoVideo}
|
||||
size='5x'
|
||||
/>
|
||||
) : this.state.previewpicture === null ? (
|
||||
) : this.state.picLoaded === null ? (
|
||||
<span className={style.loadAnimation}>
|
||||
<Spinner animation='border' />
|
||||
</span>
|
||||
) : (
|
||||
<img className={style.previewimage} src={this.state.previewpicture} alt='Pic loading.' />
|
||||
<img className={style.previewimage} src={this.pic} alt='Pic loading.' />
|
||||
)}
|
||||
</div>
|
||||
<div className={style.previewbottom} />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import Preview from '../Preview/Preview';
|
||||
import {VideoTypes} from '../../types/ApiTypes';
|
||||
import DynamicContentContainer from '../DynamicContentContainer/DynamicContentContainer';
|
||||
import {APINode, callAPIPlain} from '../../utils/Api';
|
||||
|
||||
interface Props {
|
||||
data: VideoTypes.VideoUnloadedType[];
|
||||
@ -11,7 +12,23 @@ interface Props {
|
||||
const VideoContainer = (props: Props): JSX.Element => {
|
||||
return (
|
||||
<DynamicContentContainer
|
||||
renderElement={(el): JSX.Element => <Preview key={el.MovieId} name={el.MovieName} movieId={el.MovieId} />}
|
||||
renderElement={(el): JSX.Element => (
|
||||
<Preview
|
||||
key={el.MovieId}
|
||||
picLoader={(callback: (pic: string) => void): void => {
|
||||
callAPIPlain(
|
||||
APINode.Video,
|
||||
{
|
||||
action: 'readThumbnail',
|
||||
movieid: el.MovieId
|
||||
},
|
||||
(result) => callback(result)
|
||||
);
|
||||
}}
|
||||
name={el.MovieName}
|
||||
linkPath={'/player/' + el.MovieId}
|
||||
/>
|
||||
)}
|
||||
data={props.data}>
|
||||
{props.children}
|
||||
</DynamicContentContainer>
|
||||
|
@ -4,9 +4,10 @@ import {ActorType} from '../../types/VideoTypes';
|
||||
import ActorTile from '../../elements/ActorTile/ActorTile';
|
||||
import PageTitle from '../../elements/PageTitle/PageTitle';
|
||||
import SideBar from '../../elements/SideBar/SideBar';
|
||||
import style from './ActorOverviewPage.module.css';
|
||||
// import style from './ActorOverviewPage.module.css';
|
||||
import {Button} from '../../elements/GPElements/Button';
|
||||
import NewActorPopup from '../../elements/Popups/NewActorPopup/NewActorPopup';
|
||||
import DynamicContentContainer from '../../elements/DynamicContentContainer/DynamicContentContainer';
|
||||
|
||||
interface Props {}
|
||||
|
||||
@ -36,11 +37,12 @@ class ActorOverviewPage extends React.Component<Props, state> {
|
||||
<SideBar>
|
||||
<Button title='Add Actor' onClick={(): void => this.setState({NActorPopupVisible: true})} />
|
||||
</SideBar>
|
||||
<div className={style.container}>
|
||||
{this.state.actors.map((el) => (
|
||||
<ActorTile key={el.ActorId} actor={el} />
|
||||
))}
|
||||
</div>
|
||||
<DynamicContentContainer
|
||||
renderElement={(el): JSX.Element => <ActorTile key={el.ActorId} actor={el} />}
|
||||
data={this.state.actors}
|
||||
initialLoadNr={36}
|
||||
/>
|
||||
|
||||
{this.state.NActorPopupVisible ? (
|
||||
<NewActorPopup
|
||||
onHide={(): void => {
|
||||
|
@ -48,7 +48,7 @@ export class ActorPage extends React.Component<Props, state> {
|
||||
</div>
|
||||
<SideBarTitle>Attention: This is an early preview!</SideBarTitle>
|
||||
</SideBar>
|
||||
{this.state.data.length !== 0 ? <VideoContainer data={this.state.data} /> : <div>No Data found!</div>}
|
||||
<VideoContainer data={this.state.data} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -53,7 +53,6 @@ class TagView extends React.Component<Props, TagViewState> {
|
||||
Add a new Tag!
|
||||
</button>
|
||||
</SideBar>
|
||||
{this.state.loadedtags.length !== 0 ? (
|
||||
<DynamicContentContainer
|
||||
data={this.state.loadedtags}
|
||||
renderElement={(m): JSX.Element => (
|
||||
@ -63,9 +62,6 @@ class TagView extends React.Component<Props, TagViewState> {
|
||||
)}
|
||||
initialLoadNr={20}
|
||||
/>
|
||||
) : (
|
||||
'loading'
|
||||
)}
|
||||
{this.handlePopups()}
|
||||
</>
|
||||
);
|
||||
|
@ -157,7 +157,7 @@ export class HomePage extends React.Component<Props, state> {
|
||||
}}
|
||||
/>
|
||||
</SideBar>
|
||||
{this.state.data.length !== 0 ? <VideoContainer data={this.state.data} /> : <div>No Data found!</div>}
|
||||
<VideoContainer data={this.state.data} />
|
||||
<div className={style.rightinfo} />
|
||||
</Route>
|
||||
</Switch>
|
||||
|
@ -1,8 +1,13 @@
|
||||
import React from 'react';
|
||||
import Preview from '../../elements/Preview/Preview';
|
||||
|
||||
class TVShowPage extends React.Component {
|
||||
render(): JSX.Element {
|
||||
return <>TvShowPage</>;
|
||||
return (
|
||||
<>
|
||||
<Preview name='myTestItem' picLoader={(callback): void => callback('')} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,6 +279,5 @@ export enum APINode {
|
||||
Settings = 'settings',
|
||||
Tags = 'tags',
|
||||
Actor = 'actor',
|
||||
Video = 'video',
|
||||
Init = 'init'
|
||||
Video = 'video'
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user