new folder structure for php scripts
renamed api nodes php braces on same line
This commit is contained in:
		
							
								
								
									
										19
									
								
								src/App.js
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/App.js
									
									
									
									
									
								
							@@ -10,6 +10,9 @@ import style from './App.module.css'
 | 
			
		||||
import SettingsPage from "./pages/SettingsPage/SettingsPage";
 | 
			
		||||
import CategoryPage from "./pages/CategoryPage/CategoryPage";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The main App handles the main tabs and which content to show
 | 
			
		||||
 */
 | 
			
		||||
class App extends React.Component {
 | 
			
		||||
    newElement = null;
 | 
			
		||||
 | 
			
		||||
@@ -31,7 +34,7 @@ class App extends React.Component {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'loadInitialData');
 | 
			
		||||
 | 
			
		||||
        fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/settings.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    // set theme
 | 
			
		||||
@@ -47,6 +50,10 @@ class App extends React.Component {
 | 
			
		||||
                }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * create a viewbinding to call APP functions from child elements
 | 
			
		||||
     * @returns a set of callback functions
 | 
			
		||||
     */
 | 
			
		||||
    constructViewBinding() {
 | 
			
		||||
        return {
 | 
			
		||||
            changeRootElement: this.changeRootElement,
 | 
			
		||||
@@ -54,6 +61,10 @@ class App extends React.Component {
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * load the selected component into the main view
 | 
			
		||||
     * @returns {JSX.Element} body element of selected page
 | 
			
		||||
     */
 | 
			
		||||
    MainBody() {
 | 
			
		||||
        let page;
 | 
			
		||||
        if (this.state.page === "default") {
 | 
			
		||||
@@ -109,6 +120,9 @@ class App extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * render a new root element into the main body
 | 
			
		||||
     */
 | 
			
		||||
    changeRootElement(element) {
 | 
			
		||||
        this.newElement = element;
 | 
			
		||||
 | 
			
		||||
@@ -117,6 +131,9 @@ class App extends React.Component {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * return from page to the previous page before a change
 | 
			
		||||
     */
 | 
			
		||||
    returnToLastElement() {
 | 
			
		||||
        this.setState({
 | 
			
		||||
            page: "lastpage"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
.navitem {
 | 
			
		||||
    float: left;
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    opacity: 0.6;
 | 
			
		||||
    float: left;
 | 
			
		||||
 | 
			
		||||
    font-size: large;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
    opacity: 0.6;
 | 
			
		||||
    text-transform: capitalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -18,9 +18,9 @@
 | 
			
		||||
.navitem::after {
 | 
			
		||||
    content: '';
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 0;
 | 
			
		||||
    height: 2px;
 | 
			
		||||
    transition: width .3s;
 | 
			
		||||
    width: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navitem:hover::after {
 | 
			
		||||
@@ -33,22 +33,22 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navcontainer {
 | 
			
		||||
    border-bottom-width: 2px;
 | 
			
		||||
    border-style: dotted;
 | 
			
		||||
    border-width: 0;
 | 
			
		||||
 | 
			
		||||
    padding-bottom: 40px;
 | 
			
		||||
    padding-top: 20px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding-bottom: 40px;
 | 
			
		||||
 | 
			
		||||
    border-width: 0;
 | 
			
		||||
    border-style: dotted;
 | 
			
		||||
    border-bottom-width: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbrand {
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
    margin-right: 20px;
 | 
			
		||||
    float: left;
 | 
			
		||||
    font-size: large;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
    margin-right: 20px;
 | 
			
		||||
    text-transform: capitalize;
 | 
			
		||||
    float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,37 @@
 | 
			
		||||
import darktheme from "./AppDarkTheme.module.css";
 | 
			
		||||
import lighttheme from "./AppLightTheme.module.css";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is available for all components in project
 | 
			
		||||
 * it contains general infos about app - like theme
 | 
			
		||||
 */
 | 
			
		||||
class StaticInfos {
 | 
			
		||||
    #darktheme = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * check if the current theme is the dark theme
 | 
			
		||||
     * @returns {boolean} is dark theme?
 | 
			
		||||
     */
 | 
			
		||||
    isDarkTheme() {
 | 
			
		||||
        return this.#darktheme;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enableDarkTheme(enable = true){
 | 
			
		||||
    /**
 | 
			
		||||
     * setter to enable or disable the dark or light theme
 | 
			
		||||
     * @param enable enable the dark theme?
 | 
			
		||||
     */
 | 
			
		||||
    enableDarkTheme(enable = true) {
 | 
			
		||||
        this.#darktheme = enable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getThemeStyle(){
 | 
			
		||||
    /**
 | 
			
		||||
     * get the currently selected theme stylesheet
 | 
			
		||||
     * @returns {*} the style object of the current active theme
 | 
			
		||||
     */
 | 
			
		||||
    getThemeStyle() {
 | 
			
		||||
        return this.isDarkTheme() ? darktheme : lighttheme;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const GlobalInfos = new StaticInfos();
 | 
			
		||||
//Object.freeze(StaticInfos);
 | 
			
		||||
 | 
			
		||||
export default GlobalInfos;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,9 @@ import Modal from 'react-bootstrap/Modal'
 | 
			
		||||
import Dropdown from "react-bootstrap/Dropdown";
 | 
			
		||||
import DropdownButton from "react-bootstrap/DropdownButton";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * component creates overlay to add a new tag to a video
 | 
			
		||||
 */
 | 
			
		||||
class AddTagPopup extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -22,7 +25,7 @@ class AddTagPopup extends React.Component {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'getAllTags');
 | 
			
		||||
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/tags.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((result) => {
 | 
			
		||||
                this.setState({
 | 
			
		||||
@@ -68,13 +71,16 @@ class AddTagPopup extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * store the filled in form to the backend
 | 
			
		||||
     */
 | 
			
		||||
    storeselection() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'addTag');
 | 
			
		||||
        updateRequest.append('id', this.state.selection.id);
 | 
			
		||||
        updateRequest.append('movieid', this.props.movie_id);
 | 
			
		||||
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/tags.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    if (result.result !== "success") {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,9 @@ import React from "react";
 | 
			
		||||
import Modal from 'react-bootstrap/Modal'
 | 
			
		||||
import {Form} from "react-bootstrap";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * creates modal overlay to define a new Tag
 | 
			
		||||
 */
 | 
			
		||||
class NewTagPopup extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -45,12 +48,15 @@ class NewTagPopup extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * store the filled in form to the backend
 | 
			
		||||
     */
 | 
			
		||||
    storeselection() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'createTag');
 | 
			
		||||
        updateRequest.append('tagname', this.value);
 | 
			
		||||
 | 
			
		||||
        fetch('/api/Tags.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/tags.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((result) => {
 | 
			
		||||
                if (result.result !== "success") {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,14 +2,10 @@ import React from "react";
 | 
			
		||||
import style from "./PageTitle.module.css"
 | 
			
		||||
import GlobalInfos from "../../GlobalInfos";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component for generating PageTitle with bottom Line
 | 
			
		||||
 */
 | 
			
		||||
class PageTitle extends React.Component {
 | 
			
		||||
    constructor(props) {
 | 
			
		||||
        super(props);
 | 
			
		||||
 | 
			
		||||
        this.props = props;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const themeStyle = GlobalInfos.getThemeStyle();
 | 
			
		||||
        return (
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.pageheadersubtitle {
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
    font-size: 23pt;
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
    opacity: 0.6;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,10 @@ import Player from "../../pages/Player/Player";
 | 
			
		||||
import {Spinner} from "react-bootstrap";
 | 
			
		||||
import GlobalInfos from "../../GlobalInfos";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component for single preview tile
 | 
			
		||||
 * floating side by side
 | 
			
		||||
 */
 | 
			
		||||
class Preview extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -24,7 +28,7 @@ class Preview extends React.Component {
 | 
			
		||||
        updateRequest.append('action', 'readThumbnail');
 | 
			
		||||
        updateRequest.append('movieid', this.props.movie_id);
 | 
			
		||||
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.text()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    this.setState({
 | 
			
		||||
@@ -36,8 +40,8 @@ class Preview extends React.Component {
 | 
			
		||||
    render() {
 | 
			
		||||
        const themeStyle = GlobalInfos.getThemeStyle();
 | 
			
		||||
        return (
 | 
			
		||||
            <div className={style.videopreview + ' ' + themeStyle.secbackground + ' '+ themeStyle.preview} onClick={() => this.itemClick()}>
 | 
			
		||||
                <div className={style.previewtitle + ' '+ themeStyle.lighttextcolor}>{this.state.name}</div>
 | 
			
		||||
            <div className={style.videopreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview} onClick={() => this.itemClick()}>
 | 
			
		||||
                <div className={style.previewtitle + ' ' + themeStyle.lighttextcolor}>{this.state.name}</div>
 | 
			
		||||
                <div className={style.previewpic}>
 | 
			
		||||
                    {this.state.previewpicture !== null ?
 | 
			
		||||
                        <img className={style.previewimage}
 | 
			
		||||
@@ -53,6 +57,9 @@ class Preview extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * handle the click event of a tile
 | 
			
		||||
     */
 | 
			
		||||
    itemClick() {
 | 
			
		||||
        console.log("item clicked!" + this.state.name);
 | 
			
		||||
 | 
			
		||||
@@ -63,11 +70,14 @@ class Preview extends React.Component {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component for a Tag-name tile (used in category page)
 | 
			
		||||
 */
 | 
			
		||||
export class TagPreview extends React.Component {
 | 
			
		||||
    render() {
 | 
			
		||||
        const themeStyle = GlobalInfos.getThemeStyle();
 | 
			
		||||
        return (
 | 
			
		||||
            <div className={style.videopreview + ' ' + style.tagpreview + ' ' + themeStyle.secbackground + ' '+ themeStyle.preview} onClick={() => this.itemClick()}>
 | 
			
		||||
            <div className={style.videopreview + ' ' + style.tagpreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview} onClick={() => this.itemClick()}>
 | 
			
		||||
                <div className={style.tagpreviewtitle + ' ' + themeStyle.lighttextcolor}>
 | 
			
		||||
                    {this.props.name}
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -75,6 +85,9 @@ export class TagPreview extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * handle the click event of a Tag tile
 | 
			
		||||
     */
 | 
			
		||||
    itemClick() {
 | 
			
		||||
        this.props.categorybinding(this.props.name);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
.previewtitle {
 | 
			
		||||
    height: 20px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-size: smaller;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    height: 20px;
 | 
			
		||||
    height: 20px;
 | 
			
		||||
    max-width: 266px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.previewpic {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,24 +2,33 @@ import React from "react";
 | 
			
		||||
import style from "./SideBar.module.css"
 | 
			
		||||
import GlobalInfos from "../../GlobalInfos";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * component for sidebar-info
 | 
			
		||||
 */
 | 
			
		||||
class SideBar extends React.Component {
 | 
			
		||||
    render() {
 | 
			
		||||
        const themeStyle = GlobalInfos.getThemeStyle();
 | 
			
		||||
        return (<div className={style.sideinfo + ' '+ themeStyle.secbackground}>
 | 
			
		||||
        return (<div className={style.sideinfo + ' ' + themeStyle.secbackground}>
 | 
			
		||||
            {this.props.children}
 | 
			
		||||
        </div>);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The title of the sidebar
 | 
			
		||||
 */
 | 
			
		||||
export class SideBarTitle extends React.Component {
 | 
			
		||||
    render() {
 | 
			
		||||
        const themeStyle = GlobalInfos.getThemeStyle();
 | 
			
		||||
        return (
 | 
			
		||||
            <div className={style.sidebartitle + ' '+ themeStyle.subtextcolor}>{this.props.children}</div>
 | 
			
		||||
            <div className={style.sidebartitle + ' ' + themeStyle.subtextcolor}>{this.props.children}</div>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An item of the sidebar
 | 
			
		||||
 */
 | 
			
		||||
export class SideBarItem extends React.Component {
 | 
			
		||||
    render() {
 | 
			
		||||
        const themeStyle = GlobalInfos.getThemeStyle();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,9 @@ import React from "react";
 | 
			
		||||
import styles from "./Tag.module.css"
 | 
			
		||||
import CategoryPage from "../../pages/CategoryPage/CategoryPage";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A Component representing a single Category tag
 | 
			
		||||
 */
 | 
			
		||||
class Tag extends React.Component {
 | 
			
		||||
    render() {
 | 
			
		||||
        return (
 | 
			
		||||
@@ -11,9 +14,13 @@ class Tag extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * click handling for a Tag
 | 
			
		||||
     */
 | 
			
		||||
    TagClick() {
 | 
			
		||||
        const tag = this.props.children.toString().toLowerCase();
 | 
			
		||||
 | 
			
		||||
        // call callback functin to switch to category page with specified tag
 | 
			
		||||
        this.props.viewbinding.changeRootElement(
 | 
			
		||||
            <CategoryPage
 | 
			
		||||
                category={tag}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,10 @@ import React from "react";
 | 
			
		||||
import Preview from "../Preview/Preview";
 | 
			
		||||
import style from "./VideoContainer.module.css"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A videocontainer storing lots of Preview elements
 | 
			
		||||
 * includes scroll handling and loading of preview infos
 | 
			
		||||
 */
 | 
			
		||||
class VideoContainer extends React.Component {
 | 
			
		||||
    // stores current index of loaded elements
 | 
			
		||||
    loadindex = 0;
 | 
			
		||||
@@ -43,9 +47,14 @@ class VideoContainer extends React.Component {
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        this.setState({});
 | 
			
		||||
        // unbind scroll listener when unmounting component
 | 
			
		||||
        document.removeEventListener('scroll', this.trackScrolling);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * load previews to the container
 | 
			
		||||
     * @param nr number of previews to load
 | 
			
		||||
     */
 | 
			
		||||
    loadPreviewBlock(nr) {
 | 
			
		||||
        console.log("loadpreviewblock called ...")
 | 
			
		||||
        let ret = [];
 | 
			
		||||
@@ -67,9 +76,11 @@ class VideoContainer extends React.Component {
 | 
			
		||||
        this.loadindex += nr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * scroll event handler -> load new previews if on bottom
 | 
			
		||||
     */
 | 
			
		||||
    trackScrolling = () => {
 | 
			
		||||
        // comparison if current scroll position is on bottom
 | 
			
		||||
        // 200 stands for bottom offset to trigger load
 | 
			
		||||
        // comparison if current scroll position is on bottom --> 200 is bottom offset to trigger load
 | 
			
		||||
        if (window.innerHeight + document.documentElement.scrollTop + 200 >= document.documentElement.offsetHeight) {
 | 
			
		||||
            this.loadPreviewBlock(8);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,10 @@ import NewTagPopup from "../../elements/NewTagPopup/NewTagPopup";
 | 
			
		||||
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
 | 
			
		||||
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component for Category Page
 | 
			
		||||
 * Contains a Tag Overview and loads specific Tag videos in VideoContainer
 | 
			
		||||
 */
 | 
			
		||||
class CategoryPage extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -27,7 +31,11 @@ class CategoryPage extends React.Component {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
    /**
 | 
			
		||||
     * render the Title and SideBar component for the Category page
 | 
			
		||||
     * @returns {JSX.Element} corresponding jsx element for Title and Sidebar
 | 
			
		||||
     */
 | 
			
		||||
    renderSideBarATitle() {
 | 
			
		||||
        return (
 | 
			
		||||
            <>
 | 
			
		||||
                <PageTitle
 | 
			
		||||
@@ -61,7 +69,14 @@ class CategoryPage extends React.Component {
 | 
			
		||||
                        this.setState({popupvisible: true})
 | 
			
		||||
                    }}>Add a new Tag!
 | 
			
		||||
                    </button>
 | 
			
		||||
                </SideBar>
 | 
			
		||||
                </SideBar></>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        return (
 | 
			
		||||
            <>
 | 
			
		||||
                {this.renderSideBarATitle()}
 | 
			
		||||
 | 
			
		||||
                {this.state.selected ?
 | 
			
		||||
                    <>
 | 
			
		||||
@@ -100,10 +115,18 @@ class CategoryPage extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * load a specific tag into a new previewcontainer
 | 
			
		||||
     * @param tagname
 | 
			
		||||
     */
 | 
			
		||||
    loadTag = (tagname) => {
 | 
			
		||||
        this.fetchVideoData(tagname);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * fetch data for a specific tag from backend
 | 
			
		||||
     * @param tag tagname
 | 
			
		||||
     */
 | 
			
		||||
    fetchVideoData(tag) {
 | 
			
		||||
        console.log(tag);
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
@@ -113,7 +136,7 @@ class CategoryPage extends React.Component {
 | 
			
		||||
        console.log("fetching data");
 | 
			
		||||
 | 
			
		||||
        // fetch all videos available
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    this.videodata = result;
 | 
			
		||||
@@ -125,6 +148,9 @@ class CategoryPage extends React.Component {
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * go back to the default category overview
 | 
			
		||||
     */
 | 
			
		||||
    loadCategoryPageDefault = () => {
 | 
			
		||||
        this.setState({selected: null});
 | 
			
		||||
        this.loadTags();
 | 
			
		||||
@@ -138,7 +164,7 @@ class CategoryPage extends React.Component {
 | 
			
		||||
        updateRequest.append('action', 'getAllTags');
 | 
			
		||||
 | 
			
		||||
        // fetch all videos available
 | 
			
		||||
        fetch('/api/Tags.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/tags.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    this.setState({loadedtags: result});
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,9 @@ import VideoContainer from "../../elements/VideoContainer/VideoContainer";
 | 
			
		||||
import style from "./HomePage.module.css"
 | 
			
		||||
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The home page component showing on the initial pageload
 | 
			
		||||
 */
 | 
			
		||||
class HomePage extends React.Component {
 | 
			
		||||
    /** keyword variable needed temporary store search keyword */
 | 
			
		||||
    keyword = "";
 | 
			
		||||
@@ -47,7 +50,7 @@ class HomePage extends React.Component {
 | 
			
		||||
        console.log("fetching data");
 | 
			
		||||
 | 
			
		||||
        // fetch all videos available
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    this.setState({
 | 
			
		||||
@@ -71,7 +74,7 @@ class HomePage extends React.Component {
 | 
			
		||||
        updateRequest.append('action', 'getStartData');
 | 
			
		||||
 | 
			
		||||
        // fetch all videos available
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    this.setState({
 | 
			
		||||
@@ -102,7 +105,7 @@ class HomePage extends React.Component {
 | 
			
		||||
        updateRequest.append('keyword', keyword);
 | 
			
		||||
 | 
			
		||||
        // fetch all videos available
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    this.setState({
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,10 @@ import AddTagPopup from "../../elements/AddTagPopup/AddTagPopup";
 | 
			
		||||
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Player page loads when a video is selected to play and handles the video view
 | 
			
		||||
 * and actions such as tag adding and liking
 | 
			
		||||
 */
 | 
			
		||||
class Player extends React.Component {
 | 
			
		||||
    options = {
 | 
			
		||||
        controls: [
 | 
			
		||||
@@ -59,7 +63,8 @@ class Player extends React.Component {
 | 
			
		||||
                    {this.state.quality !== 0 ?
 | 
			
		||||
                        <SideBarItem><b>{this.state.quality}p</b> Quality!</SideBarItem> : null}
 | 
			
		||||
                    {this.state.length !== 0 ?
 | 
			
		||||
                        <SideBarItem><b>{Math.round(this.state.length / 60)}</b> Minutes of length!</SideBarItem>: null}
 | 
			
		||||
                        <SideBarItem><b>{Math.round(this.state.length / 60)}</b> Minutes of
 | 
			
		||||
                            length!</SideBarItem> : null}
 | 
			
		||||
                    <Line/>
 | 
			
		||||
                    <SideBarTitle>Tags:</SideBarTitle>
 | 
			
		||||
                    {this.state.tags.map((m) => (
 | 
			
		||||
@@ -98,12 +103,15 @@ class Player extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * fetch all the required infos of a video from backend
 | 
			
		||||
     */
 | 
			
		||||
    fetchMovieData() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'loadVideo');
 | 
			
		||||
        updateRequest.append('movieid', this.props.movie_id);
 | 
			
		||||
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((result) => {
 | 
			
		||||
                this.setState({
 | 
			
		||||
@@ -129,13 +137,15 @@ class Player extends React.Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* Click Listener */
 | 
			
		||||
    /**
 | 
			
		||||
     * click handler for the like btn
 | 
			
		||||
     */
 | 
			
		||||
    likebtn() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'addLike');
 | 
			
		||||
        updateRequest.append('movieid', this.props.movie_id);
 | 
			
		||||
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    if (result.result === "success") {
 | 
			
		||||
@@ -147,6 +157,10 @@ class Player extends React.Component {
 | 
			
		||||
                }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * closebtn click handler
 | 
			
		||||
     * calls callback to viewbinding to show previous page agains
 | 
			
		||||
     */
 | 
			
		||||
    closebtn() {
 | 
			
		||||
        this.props.viewbinding.returnToLastElement();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,8 @@
 | 
			
		||||
    float: left;
 | 
			
		||||
    margin-left: 20px;
 | 
			
		||||
    margin-top: 25px;
 | 
			
		||||
    width: 60%;
 | 
			
		||||
    margin-top: 20px;
 | 
			
		||||
    width: 60%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.videoactions {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,9 @@ import Tag from "../../elements/Tag/Tag";
 | 
			
		||||
import PageTitle from "../../elements/PageTitle/PageTitle";
 | 
			
		||||
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Randompage shuffles random viedeopreviews and provides a shuffle btn
 | 
			
		||||
 */
 | 
			
		||||
class RandomPage extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -50,17 +53,24 @@ class RandomPage extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * click handler for shuffle btn
 | 
			
		||||
     */
 | 
			
		||||
    shuffleclick() {
 | 
			
		||||
        this.loadShuffledvideos(4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * load random videos from backend
 | 
			
		||||
     * @param nr number of videos to load
 | 
			
		||||
     */
 | 
			
		||||
    loadShuffledvideos(nr) {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'getRandomMovies');
 | 
			
		||||
        updateRequest.append('number', nr);
 | 
			
		||||
 | 
			
		||||
        // fetch all videos available
 | 
			
		||||
        fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/video.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    console.log(result);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,10 @@ import {Button, Col, Form} from "react-bootstrap";
 | 
			
		||||
import style from "./GeneralSettings.module.css"
 | 
			
		||||
import GlobalInfos from "../../GlobalInfos";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component for Generalsettings tag on Settingspage
 | 
			
		||||
 * handles general settings of mediacenter which concerns to all pages
 | 
			
		||||
 */
 | 
			
		||||
class GeneralSettings extends React.Component {
 | 
			
		||||
    constructor(props) {
 | 
			
		||||
        super(props);
 | 
			
		||||
@@ -19,22 +23,7 @@ class GeneralSettings extends React.Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'loadGeneralSettings');
 | 
			
		||||
 | 
			
		||||
        fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    console.log(result);
 | 
			
		||||
                    this.setState({
 | 
			
		||||
                        videopath: result.video_path,
 | 
			
		||||
                        tvshowpath: result.episode_path,
 | 
			
		||||
                        mediacentername: result.mediacenter_name,
 | 
			
		||||
                        password: result.password,
 | 
			
		||||
                        passwordsupport: result.passwordEnabled,
 | 
			
		||||
                        tmdbsupport: result.TMDB_grabbing
 | 
			
		||||
                    });
 | 
			
		||||
                }));
 | 
			
		||||
        this.loadSettings();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
@@ -119,6 +108,31 @@ class GeneralSettings extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * inital load of already specified settings from backend
 | 
			
		||||
     */
 | 
			
		||||
    loadSettings() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'loadGeneralSettings');
 | 
			
		||||
 | 
			
		||||
        fetch('/api/settings.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    console.log(result);
 | 
			
		||||
                    this.setState({
 | 
			
		||||
                        videopath: result.video_path,
 | 
			
		||||
                        tvshowpath: result.episode_path,
 | 
			
		||||
                        mediacentername: result.mediacenter_name,
 | 
			
		||||
                        password: result.password,
 | 
			
		||||
                        passwordsupport: result.passwordEnabled,
 | 
			
		||||
                        tmdbsupport: result.TMDB_grabbing
 | 
			
		||||
                    });
 | 
			
		||||
                }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * save the selected and typed settings to the backend
 | 
			
		||||
     */
 | 
			
		||||
    saveSettings() {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        updateRequest.append('action', 'saveGeneralSettings');
 | 
			
		||||
@@ -130,7 +144,7 @@ class GeneralSettings extends React.Component {
 | 
			
		||||
        updateRequest.append("tmdbsupport", this.state.tmdbsupport);
 | 
			
		||||
        updateRequest.append("darkmodeenabled", GlobalInfos.isDarkTheme());
 | 
			
		||||
 | 
			
		||||
        fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
        fetch('/api/settings.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
            .then((response) => response.json()
 | 
			
		||||
                .then((result) => {
 | 
			
		||||
                    if (result.success) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
import React from "react";
 | 
			
		||||
import style from "./MovieSettings.module.css"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component for MovieSettings on Settingspage
 | 
			
		||||
 * handles settings concerning to movies in general
 | 
			
		||||
 */
 | 
			
		||||
class MovieSettings extends React.Component {
 | 
			
		||||
    constructor(props) {
 | 
			
		||||
        super(props);
 | 
			
		||||
@@ -36,6 +40,9 @@ class MovieSettings extends React.Component {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * starts the reindex process of the videos in the specified folder
 | 
			
		||||
     */
 | 
			
		||||
    startReindex() {
 | 
			
		||||
        // clear output text before start
 | 
			
		||||
        this.setState({text: []});
 | 
			
		||||
@@ -60,6 +67,9 @@ class MovieSettings extends React.Component {
 | 
			
		||||
        this.myinterval = setInterval(this.updateStatus, 1000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This interval function reloads the current status of reindexing from backend
 | 
			
		||||
     */
 | 
			
		||||
    updateStatus = () => {
 | 
			
		||||
        const updateRequest = new FormData();
 | 
			
		||||
        fetch('/api/extractionData.php', {method: 'POST', body: updateRequest})
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,10 @@ import GeneralSettings from "./GeneralSettings";
 | 
			
		||||
import style from "./SettingsPage.module.css"
 | 
			
		||||
import GlobalInfos from "../../GlobalInfos";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The Settingspage handles all kinds of settings for the mediacenter
 | 
			
		||||
 * and is basically a wrapper for child-tabs
 | 
			
		||||
 */
 | 
			
		||||
class SettingsPage extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -14,6 +17,10 @@ class SettingsPage extends React.Component {
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * load the selected tab
 | 
			
		||||
     * @returns {JSX.Element|string} the jsx element of the selected tab
 | 
			
		||||
     */
 | 
			
		||||
    getContent() {
 | 
			
		||||
        switch (this.state.currentpage) {
 | 
			
		||||
            case "general":
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,11 @@ import Adapter from 'enzyme-adapter-react-16';
 | 
			
		||||
 | 
			
		||||
configure({adapter: new Adapter()});
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * prepares fetch api for a virtual test call
 | 
			
		||||
 * @param response the response fetch should give you back
 | 
			
		||||
 * @returns {jest.Mock<any, any>} a jest mock function simulating a fetch
 | 
			
		||||
 */
 | 
			
		||||
global.prepareFetchApi = (response) => {
 | 
			
		||||
    const mockJsonPromise = Promise.resolve(response);
 | 
			
		||||
    const mockFetchPromise = Promise.resolve({
 | 
			
		||||
@@ -17,6 +22,10 @@ global.prepareFetchApi = (response) => {
 | 
			
		||||
    return (jest.fn().mockImplementation(() => mockFetchPromise));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * prepares a failing virtual fetch api call
 | 
			
		||||
 * @returns {jest.Mock<any, any>} a jest moch function simulating a failing fetch call
 | 
			
		||||
 */
 | 
			
		||||
global.prepareFailingFetchApi = () => {
 | 
			
		||||
    const mockFetchPromise = Promise.reject("myreason");
 | 
			
		||||
    return (jest.fn().mockImplementation(() => mockFetchPromise));
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user